This project demonstrates how to use the 0015__map_tiles component(ESP Registry) across multiple independent ESP-IDF projects. It showcases different use cases of interactive map display on ESP32 devices with LVGL 9.x, providing complete examples of GPS-based map navigation with various interaction patterns.
This contains ESP-IDF projects that share a common map component:
map_tiles_projects/
├── shared_components/
│ └── simple_map/ # Shared SimpleMap component
│ ├── simple_map.hpp
│ ├── simple_map.cpp
│ └── CMakeLists.txt
├── espressif_esp32_p4_function_ev_board/ # Demo for espressif_esp32_p4_function_ev_board
│ ├── main/
│ │ ├── main.cpp
│ │ └── CMakeLists.txt
│ └── CMakeLists.txt
├── waveshare_esp32_s3_touch_amoled_1_75/ # Demo for waveshare_esp32_s3_touch_amoled_1_75
│ ├── main/
│ │ ├── main.cpp
│ │ └── CMakeLists.txt
│ └── CMakeLists.txt
├── waveshare_esp32_p4_wifi6_touch_lcd_xc/ # Demo for waveshare_esp32_p4_wifi6_touch_lcd_xc
│ ├── main/
│ │ ├── main.cpp
│ │ └── CMakeLists.txt
│ └── CMakeLists.txt
├── components/ # Device-specific components
└── CMakeLists.txt # Shared components only
- Interactive Map Display: Touch-scrollable map with smooth tile loading
- Real-time GPS Coordinates: Automatically updates latitude/longitude as you scroll
- Zoom Control: Adjustable zoom levels (X-19) with dynamic tile reloading
- GPS Input Panel: Manual coordinate entry with on-screen keyboard
- Smart Tile Loading: Preserves old tiles during updates for smooth transitions
- Multiple Tile Types: Support for different map styles (street, satellite, etc.)
- Touch-optimized UI: Designed for touchscreen interaction
- ESP32-S3 with at least 8MB PSRAM (recommended)
- Display with LVGL 9.x support
- Touch panel support
- SD card for map tile storage
- Minimum 4MB flash memory
- ESP-IDF 5.0+: ESP32 development framework
- LVGL 9.3+: Graphics library
- 0015__map_tiles: Map tiles component (included in managed_components)
- SD card support: For tile storage (FAT filesystem)
The map tiles should be stored on SD card in the following format:
- Format: RGB565 binary files
- Size: 256x256 pixels per tile
- Structure:
/sdcard/tiles1/zoom/x/y.bin - Zoom levels: 10-19 (configurable)
Example directory structure:
/sdcard/
├── tiles1/
│ ├── 15/
│ │ ├── 10485/
│ │ │ ├── 12733.bin
│ │ │ ├── 12734.bin
│ │ │ └── ...
│ │ └── ...
│ ├── 16/
│ └── ...
- Power on: The map initializes and displays a default location
- Scroll: Touch and drag to pan around the map
- View coordinates: Current GPS coordinates are shown in the input panel
- Zoom: Use the slider to select zoom level, then press "Update Map"
- Go to location: Enter coordinates manually and press "Update Map"
- Touch scrolling: Drag to move around the map
- GPS coordinates: Real-time updates as you scroll
- Zoom slider: Select zoom level (10-19)
- Update button: Apply coordinate/zoom changes
- Keyboard: Appears when editing coordinates
// GPS coordinates update automatically as you scroll
void SimpleMap::update_current_gps_from_map_center();- Old tiles remain visible during updates
- Loading indicators show progress
- Automatic tile caching and management
- Debounced scroll events for smooth performance
- Responsive coordinate updates
- User-friendly input validation
SimpleMapclass (shared_components/simple_map/): Main map interface and logicmap_tilescomponent: Low-level tile management (managed component)- Input panel: GPS coordinate entry and zoom control
- Event handlers: Touch, scroll, and button events
This project requires a larger main task stack size than the ESP-IDF default to function correctly. The application loads and displays map tiles directly from an SD card while updating the LVGL graphical interface.
The call stack for these operations—including file I/O (VFS/FATFS), image decoding, and LVGL object updates—can be quite deep. The default main task stack is insufficient for these nested function calls and will likely result in a stack overflow and a system crash.
To ensure stability, you must increase the main task stack size to a minimum of 10,240 bytes (10 KB). If you plan to enable long filenames or complex decoders, or if you add more features, we recommend a safer size of 12–16 KB.
-
menuconfig
idf.py menuconfig→ Component config → ESP System Settings → Main task stack size- Set to 10240 (or higher).
-
sdkconfig
CONFIG_ESP_MAIN_TASK_STACK_SIZE=10240
// Initialize the map system
bool SimpleMap::init(lv_obj_t* parent_screen);
// Display map at specific location
void SimpleMap::show_location(double lat, double lon, int zoom);
// Handle user interactions
void SimpleMap::map_scroll_event_cb(lv_event_t *e);
void SimpleMap::update_button_event_cb(lv_event_t *e);
// GPS coordinate management
void SimpleMap::update_current_gps_from_map_center();
void SimpleMap::get_current_location(double* lat, double* lon);The map system is configured in SimpleMap::init():
map_tiles_config_t config = {
.base_path = "/sdcard", // SD card mount point
.tile_folders = {"tiles1"}, // Tile directory names
.tile_type_count = 1, // Number of tile types
.grid_cols = 5, // Tile grid width
.grid_rows = 5, // Tile grid height
.default_zoom = 18, // Initial zoom level
.use_spiram = true, // Use PSRAM for tiles
.default_tile_type = 0 // Default tile type
};- Uses PSRAM for tile storage when available
- Efficient tile caching and cleanup
- Minimal memory fragmentation
- Preserves old tiles during updates
- Debounced scroll events (50ms for GPS updates)
- Optimized LVGL object management
- Smooth scrolling with momentum disabled
- Real-time coordinate feedback
- Responsive zoom controls
class SimpleMap {
public:
// Core functionality
static bool init(lv_obj_t* parent_screen);
static void show_location(double lat, double lon, int zoom = 18);
static void update_location(double lat, double lon);
static void cleanup();
// Tile management
static bool set_tile_type(int tile_type);
static int get_tile_type();
static int get_tile_type_count();
// Coordinate access
static void get_current_location(double* lat, double* lon);
static int get_current_zoom();
// Map positioning
static void center_map_on_gps();
};- Grid size: 5x5 to 9x9 tiles (5x5 recommended)
- Zoom range: 10-19 (standard map zoom levels)
- Tile types: Up to 8 different tile sets
- Memory: PSRAM or regular RAM for tile storage
-
Map not displaying:
- Check SD card mount and tile directory structure
- Verify tile format (RGB565, 256x256 pixels)
- Ensure sufficient PSRAM/memory
-
Slow performance:
- Enable PSRAM in menuconfig
- Reduce grid size if memory limited
- Check SD card speed class
-
Touch not working:
- Verify touch panel configuration
- Check LVGL input device setup
- Ensure proper touch calibration
-
Coordinates incorrect:
- Verify tile coordinate system matches your map data
- Check zoom level calculations
- Ensure proper GPS coordinate conversion
Enable debug output to troubleshoot issues:
// Key debug messages
"SimpleMap: Initialized with grid size %dx%d"
"SimpleMap: Loading %dx%d grid at position (%d,%d)"
"SimpleMap: Updated GPS from map center: %.6f, %.6f"
"SimpleMap: Zoom changed from %d to %d"#include "simple_map.hpp"
extern "C" void app_main(void) {
// Standard ESP32 initialization...
// Initialize interactive map
if (!SimpleMap::init(lv_screen_active())) {
ESP_LOGE(TAG, "Failed to initialize map");
return;
}
// Show initial location with full controls
SimpleMap::show_location(37.77490, -122.41942, 16);
SimpleMap::center_map_on_gps();
}#include "simple_map.hpp"
// Predefined locations for demo
static const struct {
double lat, lon;
const char* name;
} demo_locations[] = {
{40.7128, -74.0060, "New York City"},
{51.5074, -0.1278, "London"},
{35.6762, 139.6503, "Tokyo"}
};
void location_cycle_task(void *pvParameters) {
while (1) {
vTaskDelay(pdMS_TO_TICKS(10000)); // 10 second intervals
// Cycle through locations
current_location_index = (current_location_index + 1) % 3;
SimpleMap::show_location(
demo_locations[current_location_index].lat,
demo_locations[current_location_index].lon,
15
);
}
}
extern "C" void app_main(void) {
// Standard ESP32 initialization...
// Initialize map for tracking mode
SimpleMap::init(lv_screen_active());
SimpleMap::show_location(demo_locations[0].lat, demo_locations[0].lon, 15);
// Start location cycling task
xTaskCreate(location_cycle_task, "location_cycle", 4096, NULL, 5, NULL);
}Both devices use the same SimpleMap API:
// Change tile type (e.g., satellite view)
SimpleMap::set_tile_type(1);
// Get current position
double lat, lon;
SimpleMap::get_current_location(&lat, &lon);
// Update to new location
SimpleMap::update_location(40.7128, -74.0060);mkdir device_custom_project
cd device_custom_project# Device Custom - Your Demo
cmake_minimum_required(VERSION 3.5)
# Add shared components from parent directory
set(EXTRA_COMPONENT_DIRS "../shared_components")
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(simple_map_device_custom)mkdir mainmain/CMakeLists.txt:
idf_component_register(SRCS "main.cpp"
INCLUDE_DIRS "."
REQUIRES simple_map)main/main.cpp:
#include "simple_map.hpp"
extern "C" void app_main(void) {
// Your device-specific initialization
// Initialize shared map component
if (!SimpleMap::init(lv_screen_active())) {
return;
}
// Your custom map configuration
SimpleMap::show_location(your_lat, your_lon, your_zoom);
}idf.py build flash monitorThis is a multi-device example project demonstrating the 0015__map_tiles component. For improvements or bug fixes:
- Shared SimpleMap component: Contribute to
shared_components/simple_map/ - Device-specific features: Create new device configurations
- Core map functionality: Contribute to the main 0015__map_tiles component repository
- LVGL Team: For the excellent graphics library
- Espressif: For the ESP-IDF framework
- Map tile providers: For map data (ensure proper attribution)
For questions and support:
- Check the troubleshooting section above
- Review the 0015__map_tiles component documentation
- Post issues with full debug output and hardware configuration
This project is provided as an example for the 0015__map_tiles component. Check individual component licenses for specific terms.
