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.
espressif_esp32_p4_function_ev_board
esp32_p4_function_ev_board
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
SimpleMap
class (shared_components/simple_map/
): Main map interface and logicmap_tiles
component: 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 main
main/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 monitor
This 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.