Skip to content

Commit 2a028a4

Browse files
committed
Add initial M5Stack Tab5 ESP-IDF environment and board skeleton
1 parent 2273727 commit 2a028a4

File tree

11 files changed

+549
-0
lines changed

11 files changed

+549
-0
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
cmake_minimum_required(VERSION 3.16.0)
2+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
3+
project(trail-mate)

boards/m5stack-tab5.json

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"build": {
3+
"arduino": {
4+
"ldscript": "esp32p4_out.ld",
5+
"partitions": "default_16MB.csv",
6+
"memory_type": "opi_opi"
7+
},
8+
"core": "esp32",
9+
"extra_flags": [
10+
"-DBOARD_HAS_PSRAM",
11+
"-DARDUINO_USB_MODE=1",
12+
"-DARDUINO_RUNNING_CORE=1",
13+
"-DARDUINO_EVENT_RUNNING_CORE=1"
14+
],
15+
"f_cpu": "400000000L",
16+
"f_flash": "80000000L",
17+
"flash_mode": "qio",
18+
"mcu": "esp32p4",
19+
"variant": "esp32p4"
20+
},
21+
"connectivity": [
22+
"wifi",
23+
"bluetooth"
24+
],
25+
"debug": {
26+
"default_tool": "esp-builtin",
27+
"onboard_tools": [
28+
"esp-builtin"
29+
]
30+
},
31+
"frameworks": [
32+
"arduino",
33+
"espidf"
34+
],
35+
"name": "M5Stack Tab5 (ESP32-P4, 16MB Flash, 32MB PSRAM)",
36+
"upload": {
37+
"flash_size": "16MB",
38+
"maximum_ram_size": 33554432,
39+
"maximum_size": 16777216,
40+
"require_upload_port": true,
41+
"speed": 115200
42+
},
43+
"url": "https://docs.m5stack.com/en/core/Tab5",
44+
"vendor": "M5Stack"
45+
}
46+

platformio.ini

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,41 @@ lib_deps =
7474
nanopb/nanopb @ ^0.4.8
7575
rweather/Crypto @ 0.4.0
7676

77+
; Base configuration for ESP-IDF-based environments (e.g. M5Stack Tab5 / ESP32-P4)
78+
[idf_base]
79+
extends = env
80+
framework = espidf
81+
platform = espressif32@6.12.0
82+
board_build.filesystem = fatfs
83+
board_build.partitions = partitions.csv
84+
85+
platform_packages =
86+
toolchain-riscv32-esp@8.4.0+2021r2-patch5
87+
88+
build_flags =
89+
-std=gnu++17
90+
-D LV_CONF_INCLUDE_SIMPLE
91+
-D LV_USE_SNAPSHOT=1
92+
-D HAS_GPS=1
93+
-D HAS_SD=1
94+
-D HAS_PSRAM=1
95+
-I${PROJECT_DIR}/src/ui
96+
-I${PROJECT_DIR}/src
97+
-I${PROJECT_DIR}
98+
-I${PROJECT_DIR}/src/chat/infra/meshtastic/generated
99+
lib_extra_dirs =
100+
${PROJECT_DIR}/src/ui
101+
lib_deps =
102+
lvgl/lvgl @ 9.4.0
103+
jgromes/RadioLib @ 7.4.0
104+
lewisxhe/XPowersLib@0.3.1
105+
lewisxhe/SensorLib @ 0.3.3
106+
mikalhart/TinyGPSPlus @ 1.0.3
107+
earlephilhower/ESP8266Audio @ 2.0.0
108+
h2zero/NimBLE-Arduino @ 2.2.3
109+
nanopb/nanopb @ ^0.4.8
110+
rweather/Crypto @ 0.4.0
111+
77112
; NOTE: Board-specific environments (including tlora_pager_sx1262 / tlora_pager_sx1280)
78113
; are defined in variants/*/envs/*.ini and loaded via extra_configs above.
79114
; Keep root config focused on shared settings only.

src/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# This file was automatically generated for projects
2+
# without default 'CMakeLists.txt' file.
3+
4+
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
5+
6+
idf_component_register(SRCS ${app_sources})

src/board/BoardBase.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#pragma once
22

3+
// In Arduino environments we use <Arduino.h> for basic types and helpers.
4+
// In ESP-IDF (or other non-Arduino builds), fall back to standard headers.
5+
#if __has_include(<Arduino.h>)
36
#include <Arduino.h>
7+
#else
8+
#include <stdint.h>
9+
#include <stdbool.h>
10+
#endif
411

512
// Abstract base class: provides a unified interface for different hardware boards.
613
// Only keeps the minimal set actually used by the application layer to avoid tight coupling.

src/board/M5Tab5Board.cpp

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include "M5Tab5Board.h"
2+
3+
#include "gps/GPS.h"
4+
#include "freertos/FreeRTOS.h"
5+
#include "freertos/task.h"
6+
7+
// NOTE: This is a minimal skeleton implementation that allows the firmware
8+
// to build and run on the M5Stack Tab5 environment. Hardware-specific
9+
// display, touch, GNSS, LoRa, and sensor wiring will be filled in gradually.
10+
11+
M5Tab5Board::M5Tab5Board() : LilyGo_Display(SPI_DRIVER, false) {}
12+
13+
M5Tab5Board* M5Tab5Board::getInstance()
14+
{
15+
static M5Tab5Board instance;
16+
return &instance;
17+
}
18+
19+
uint32_t M5Tab5Board::begin(uint32_t /*disable_hw_init*/)
20+
{
21+
// For now, just mark display/touch as logically ready so UI can run.
22+
display_ready_ = true;
23+
touch_ready_ = true;
24+
rtc_ready_ = false;
25+
sd_ready_ = false;
26+
gps_ready_ = false;
27+
28+
// Default rotation: landscape.
29+
rotation_ = 1;
30+
return 0;
31+
}
32+
33+
void M5Tab5Board::setBrightness(uint8_t level)
34+
{
35+
brightness_ = level;
36+
// TODO: hook into Tab5 backlight control when integrating display driver.
37+
}
38+
39+
void M5Tab5Board::setRotation(uint8_t rotation)
40+
{
41+
rotation_ = rotation;
42+
}
43+
44+
void M5Tab5Board::pushColors(uint16_t /*x1*/, uint16_t /*y1*/, uint16_t /*x2*/, uint16_t /*y2*/, uint16_t* /*color*/)
45+
{
46+
// TODO: forward to Tab5 display driver (MIPI DSI) when integrated.
47+
}
48+
49+
uint16_t M5Tab5Board::width()
50+
{
51+
return SCREEN_WIDTH;
52+
}
53+
54+
uint16_t M5Tab5Board::height()
55+
{
56+
return SCREEN_HEIGHT;
57+
}
58+
59+
uint8_t M5Tab5Board::getPoint(int16_t* x, int16_t* y, uint8_t get_point)
60+
{
61+
if (!touch_ready_ || !x || !y)
62+
{
63+
return 0;
64+
}
65+
// TODO: wire to Tab5 touch driver (GT911/ST7123). For now, report no touch.
66+
(void)get_point;
67+
return 0;
68+
}
69+
70+
RotaryMsg_t M5Tab5Board::getRotary()
71+
{
72+
// Tab5 has no rotary encoder; always return "no movement".
73+
RotaryMsg_t msg{};
74+
msg.dir = ROTARY_DIR_NONE;
75+
msg.centerBtnPressed = false;
76+
return msg;
77+
}
78+
79+
int M5Tab5Board::getKeyChar(char* c)
80+
{
81+
// No physical keyboard on Tab5. Virtual keyboard events are injected
82+
// directly via LVGL, so this always reports "no key".
83+
if (c)
84+
{
85+
*c = '\0';
86+
}
87+
return -1;
88+
}
89+
90+
// ---- LoraBoard stubs ----
91+
92+
int M5Tab5Board::transmitRadio(const uint8_t* /*data*/, size_t /*len*/) { return -1; }
93+
int M5Tab5Board::startRadioReceive() { return -1; }
94+
uint32_t M5Tab5Board::getRadioIrqFlags() { return 0; }
95+
int M5Tab5Board::getRadioPacketLength(bool /*update*/) { return 0; }
96+
int M5Tab5Board::readRadioData(uint8_t* /*buf*/, size_t /*len*/) { return 0; }
97+
void M5Tab5Board::clearRadioIrqFlags(uint32_t /*flags*/) {}
98+
float M5Tab5Board::getRadioRSSI() { return 0.0f; }
99+
float M5Tab5Board::getRadioSNR() { return 0.0f; }
100+
void M5Tab5Board::configureLoraRadio(float /*freq_mhz*/, float /*bw_khz*/, uint8_t /*sf*/, uint8_t /*cr_denom*/,
101+
int8_t /*tx_power*/, uint16_t /*preamble_len*/, uint8_t /*sync_word*/,
102+
uint8_t /*crc_len*/)
103+
{
104+
}
105+
106+
// ---- GpsBoard stubs ----
107+
108+
static GPS s_dummy_gps;
109+
110+
bool M5Tab5Board::initGPS()
111+
{
112+
gps_ready_ = false;
113+
return false;
114+
}
115+
116+
GPS& M5Tab5Board::getGPS()
117+
{
118+
return s_dummy_gps;
119+
}
120+
121+
void M5Tab5Board::powerControl(PowerCtrlChannel_t /*ch*/, bool /*enable*/)
122+
{
123+
}
124+
125+
bool M5Tab5Board::syncTimeFromGPS(uint32_t /*gps_task_interval_ms*/)
126+
{
127+
return false;
128+
}
129+
130+
// ---- MotionBoard stubs ----
131+
132+
SensorBHI260AP& M5Tab5Board::getMotionSensor()
133+
{
134+
// Tab5 has IMU, but we don't wire it yet. This is a stub to satisfy interface.
135+
// Code paths that rely on motion sensor should be disabled for Tab5 via HAS_* flags.
136+
for (;;)
137+
{
138+
vTaskDelay(portMAX_DELAY);
139+
}
140+
}
141+
142+
// ---- SdBoard stubs ----
143+
144+
bool M5Tab5Board::installSD()
145+
{
146+
sd_ready_ = false;
147+
return false;
148+
}
149+
150+
void M5Tab5Board::uninstallSD()
151+
{
152+
}
153+
154+
bool M5Tab5Board::isCardReady()
155+
{
156+
return false;
157+
}
158+
159+
// ---- Global board instance for Tab5 env ----
160+
161+
namespace
162+
{
163+
M5Tab5Board& getInstanceRef()
164+
{
165+
return *M5Tab5Board::getInstance();
166+
}
167+
} // namespace
168+
169+
M5Tab5Board& instance = getInstanceRef();
170+
BoardBase& board = getInstanceRef();
171+

src/board/M5Tab5Board.h

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#pragma once
2+
3+
#include "BoardBase.h"
4+
#include "GpsBoard.h"
5+
#include "LoraBoard.h"
6+
#include "SdBoard.h"
7+
#include "MotionBoard.h"
8+
#include "display/DisplayInterface.h"
9+
10+
// Minimal M5Stack Tab5 board integration.
11+
// This is a skeleton that allows the firmware to build and run basic UI
12+
// on ESP32-P4, with hardware-specific details to be filled in incrementally.
13+
14+
class SensorBHI260AP;
15+
class GPS;
16+
17+
class M5Tab5Board : public BoardBase,
18+
public LoraBoard,
19+
public GpsBoard,
20+
public MotionBoard,
21+
public SdBoard,
22+
public LilyGo_Display
23+
{
24+
public:
25+
static M5Tab5Board* getInstance();
26+
27+
// BoardBase
28+
uint32_t begin(uint32_t disable_hw_init = 0) override;
29+
void wakeUp() override {}
30+
void handlePowerButton() override {}
31+
void softwareShutdown() override {}
32+
33+
void setBrightness(uint8_t level) override;
34+
uint8_t getBrightness() override { return brightness_; }
35+
36+
bool hasKeyboard() override { return false; }
37+
void keyboardSetBrightness(uint8_t /*level*/) override {}
38+
uint8_t keyboardGetBrightness() override { return 0; }
39+
40+
bool isRTCReady() const override { return rtc_ready_; }
41+
bool isCharging() override { return false; }
42+
int getBatteryLevel() override { return -1; }
43+
44+
bool isSDReady() const override { return sd_ready_; }
45+
bool isCardReady() override { return false; }
46+
bool isGPSReady() const override { return gps_ready_; }
47+
48+
void vibrator() override {}
49+
void stopVibrator() override {}
50+
51+
// Display / input (LilyGo_Display interface used by LV_Helper_v9)
52+
void setRotation(uint8_t rotation) override;
53+
uint8_t getRotation() override { return rotation_; }
54+
void pushColors(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t* color) override;
55+
uint16_t width() override;
56+
uint16_t height() override;
57+
bool useDMA() override { return false; }
58+
bool hasTouch() override { return true; }
59+
uint8_t getPoint(int16_t* x, int16_t* y, uint8_t get_point) override;
60+
bool hasEncoder() override { return false; }
61+
RotaryMsg_t getRotary() override;
62+
int getKeyChar(char* c) override;
63+
void feedback(void* args = NULL) override { (void)args; }
64+
65+
// LoraBoard (stubs for now; real radio wiring to be added later)
66+
bool isRadioOnline() const override { return false; }
67+
int transmitRadio(const uint8_t* data, size_t len) override;
68+
int startRadioReceive() override;
69+
uint32_t getRadioIrqFlags() override;
70+
int getRadioPacketLength(bool update) override;
71+
int readRadioData(uint8_t* buf, size_t len) override;
72+
void clearRadioIrqFlags(uint32_t flags) override;
73+
float getRadioRSSI() override;
74+
float getRadioSNR() override;
75+
void configureLoraRadio(float freq_mhz, float bw_khz, uint8_t sf, uint8_t cr_denom,
76+
int8_t tx_power, uint16_t preamble_len, uint8_t sync_word,
77+
uint8_t crc_len) override;
78+
79+
// GpsBoard (stubs; to be connected to Tab5 GNSS module)
80+
bool initGPS() override;
81+
void setGPSOnline(bool online) override { gps_ready_ = online; }
82+
GPS& getGPS() override;
83+
bool isGPSReady() const override { return gps_ready_; }
84+
void powerControl(PowerCtrlChannel_t ch, bool enable) override;
85+
bool syncTimeFromGPS(uint32_t gps_task_interval_ms = 0) override;
86+
87+
// MotionBoard (Tab5 has IMU; stub until wired)
88+
SensorBHI260AP& getMotionSensor() override;
89+
bool isSensorReady() const override { return false; }
90+
91+
// SdBoard
92+
bool installSD() override;
93+
void uninstallSD() override;
94+
bool isCardReady() override;
95+
96+
private:
97+
M5Tab5Board();
98+
99+
private:
100+
uint8_t brightness_ = DEVICE_MAX_BRIGHTNESS_LEVEL;
101+
uint8_t rotation_ = 0;
102+
bool display_ready_ = false;
103+
bool touch_ready_ = false;
104+
bool rtc_ready_ = false;
105+
bool sd_ready_ = false;
106+
bool gps_ready_ = false;
107+
};
108+

0 commit comments

Comments
 (0)