Implement LilyGO T-Dongle S3

+ fix issue with apps installed in /data
+ implement SDMMC driver
+ implement ST7735 driver
This commit is contained in:
Ken Van Hoeylandt 2025-10-11 16:29:57 +02:00
parent 114062c96d
commit e23b956cf4
23 changed files with 763 additions and 4 deletions

View File

@ -0,0 +1,7 @@
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility EspLcdCompat ST7735 GT911 PwmBacklight driver
)

View File

@ -0,0 +1,15 @@
#include "PwmBacklight.h"
#include "Tactility/service/gps/GpsService.h"
#include <Tactility/TactilityCore.h>
#define TAG "T-Dongle"
bool initBoot() {
if (!driver::pwmbacklight::init(GPIO_NUM_38, 12000)) {
TT_LOG_E(TAG, "Backlight init failed");
return false;
}
return true;
}

View File

@ -0,0 +1,92 @@
#include <Tactility/hal/Configuration.h>
#include <Tactility/lvgl/LvglSync.h>
#include "devices/Display.h"
#include "devices/Sdcard.h"
#define TDECK_SPI_TRANSFER_SIZE_LIMIT (80 * 160 * (LV_COLOR_DEPTH / 8))
bool initBoot();
using namespace tt::hal;
static std::vector<std::shared_ptr<Device>> createDevices() {
return {
createDisplay(),
createSdCard()
};
}
extern const Configuration lilygo_tdongle_s3 = {
.initBoot = initBoot,
.uiScale = UiScale::Smallest,
.createDevices = createDevices,
.i2c = {
i2c::Configuration {
.name = "STEMMA QT",
.port = I2C_NUM_0,
.initMode = i2c::InitMode::ByTactility,
.isMutable = false,
.config = (i2c_config_t) {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_44,
.scl_io_num = GPIO_NUM_43,
.sda_pullup_en = true,
.scl_pullup_en = true,
.master = {
.clk_speed = 400000
},
.clk_flags = 0
}
}
},
.spi {
spi::Configuration {
.device = SPI3_HOST,
.dma = SPI_DMA_CH_AUTO,
.config = {
.mosi_io_num = GPIO_NUM_3,
.miso_io_num = GPIO_NUM_NC,
.sclk_io_num = GPIO_NUM_5,
.quadwp_io_num = GPIO_NUM_NC,
.data4_io_num = GPIO_NUM_NC,
.data5_io_num = GPIO_NUM_NC,
.data6_io_num = GPIO_NUM_NC,
.data7_io_num = GPIO_NUM_NC,
.data_io_default_level = false,
.max_transfer_sz = TDECK_SPI_TRANSFER_SIZE_LIMIT,
.flags = 0,
.isr_cpu_id = ESP_INTR_CPU_AFFINITY_AUTO,
.intr_flags = 0
},
.initMode = spi::InitMode::ByTactility,
.isMutable = false,
.lock = tt::lvgl::getSyncLock() // esp_lvgl_port owns the lock for the display
},
},
.uart {
uart::Configuration {
.name = "STEMMA QT",
.port = UART_NUM_1,
.rxPin = GPIO_NUM_44,
.txPin = GPIO_NUM_43,
.rtsPin = GPIO_NUM_NC,
.ctsPin = GPIO_NUM_NC,
.rxBufferSize = 1024,
.txBufferSize = 1024,
.config = {
.baud_rate = 38400,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 0,
.source_clk = UART_SCLK_DEFAULT,
.flags = {
.allow_pd = 0,
.backup_before_sleep = 0,
}
}
}
}
};

View File

@ -0,0 +1,5 @@
#pragma once
#include <Tactility/hal/Configuration.h>
extern const tt::hal::Configuration lilygo_tdongle_s3;

View File

@ -0,0 +1,36 @@
#include "Display.h"
#include <PwmBacklight.h>
#include <St7735Display.h>
#define LCD_SPI_HOST SPI3_HOST
#define LCD_PIN_CS GPIO_NUM_4
#define LCD_PIN_DC GPIO_NUM_2
#define LCD_PIN_RESET GPIO_NUM_1
#define LCD_HORIZONTAL_RESOLUTION 80
#define LCD_VERTICAL_RESOLUTION 160
#define LCD_SPI_TRANSFER_HEIGHT LCD_VERTICAL_RESOLUTION / 4
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
auto configuration = std::make_unique<St7735Display::Configuration>(
LCD_SPI_HOST,
LCD_PIN_CS,
LCD_PIN_DC,
LCD_PIN_RESET,
80,
160,
nullptr,
false,
false,
false,
true,
0,
26,
1
);
configuration->backlightDutyFunction = driver::pwmbacklight::setBacklightDuty;
auto display = std::make_shared<St7735Display>(std::move(configuration));
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
}

View File

@ -0,0 +1,5 @@
#pragma once
#include <Tactility/hal/display/DisplayDevice.h>
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -0,0 +1,22 @@
#include "Sdcard.h"
#include <Tactility/hal/sdcard/SdmmcDevice.h>
#include <Tactility/lvgl/LvglSync.h>
using tt::hal::sdcard::SdmmcDevice;
std::shared_ptr<SdCardDevice> createSdCard() {
auto configuration = std::make_unique<SdmmcDevice::Config>(
GPIO_NUM_12,
GPIO_NUM_16,
GPIO_NUM_14,
GPIO_NUM_17,
GPIO_NUM_21,
GPIO_NUM_18,
SdCardDevice::MountBehaviour::AtBoot
);
return std::make_shared<SdmmcDevice>(
std::move(configuration)
);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Tactility/hal/sdcard/SdCardDevice.h"
using tt::hal::sdcard::SdCardDevice;
std::shared_ptr<SdCardDevice> createSdCard();

View File

@ -51,6 +51,8 @@ function(INIT_TACTILITY_GLOBALS SDKCONFIG_FILE)
set(TACTILITY_BOARD_PROJECT ElecrowCrowpanelBasic50)
elseif (board_id STREQUAL "lilygo-tdeck")
set(TACTILITY_BOARD_PROJECT LilygoTdeck)
elseif (board_id STREQUAL "lilygo-tdongle-s3")
set(TACTILITY_BOARD_PROJECT LilygoTdongleS3)
elseif (board_id STREQUAL "lilygo-tlora-pager")
set(TACTILITY_BOARD_PROJECT LilygoTLoraPager)
elseif (board_id STREQUAL "m5stack-cardputer")

View File

@ -0,0 +1,5 @@
idf_component_register(
SRC_DIRS "Source"
INCLUDE_DIRS "Source"
REQUIRES Tactility driver EspLcdCompat esp_lcd_st7735
)

3
Drivers/ST7735/README.md Normal file
View File

@ -0,0 +1,3 @@
# ST7735
A basic ESP32 LVGL driver for ST7735 displays.

View File

@ -0,0 +1,170 @@
#include "St7735Display.h"
#include <Tactility/Log.h>
#include <esp_lcd_panel_commands.h>
#include <esp_lcd_panel_dev.h>
#include <esp_lcd_st7735.h>
#include <esp_lvgl_port.h>
constexpr auto TAG = "ST7735";
bool St7735Display::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
TT_LOG_I(TAG, "Starting");
const esp_lcd_panel_io_spi_config_t panel_io_config = {
.cs_gpio_num = configuration->csPin,
.dc_gpio_num = configuration->dcPin,
.spi_mode = 0,
.pclk_hz = configuration->pixelClockFrequency,
.trans_queue_depth = configuration->transactionQueueDepth,
.on_color_trans_done = nullptr,
.user_ctx = nullptr,
.lcd_cmd_bits = 8,
.lcd_param_bits = 8,
.cs_ena_pretrans = 0,
.cs_ena_posttrans = 0,
.flags = {
.dc_high_on_cmd = 0,
.dc_low_on_data = 0,
.dc_low_on_param = 0,
.octal_mode = 0,
.quad_mode = 0,
.sio_mode = 1,
.lsb_first = 0,
.cs_high_active = 0
}
};
if (esp_lcd_new_panel_io_spi(configuration->spiHostDevice, &panel_io_config, &outHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
}
return true;
}
bool St7735Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) {
const esp_lcd_panel_dev_config_t panel_config = {
.reset_gpio_num = configuration->resetPin,
.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR,
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
.bits_per_pixel = 16,
.flags = {
.reset_active_high = false
},
.vendor_config = nullptr
};
if (esp_lcd_new_panel_st7735(ioHandle, &panel_config, &panelHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to create panel");
return false;
}
if (esp_lcd_panel_reset(panelHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to reset panel");
return false;
}
if (esp_lcd_panel_init(panelHandle) != ESP_OK) {
TT_LOG_E(TAG, "Failed to init panel");
return false;
}
if (esp_lcd_panel_invert_color(panelHandle, configuration->invertColor) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set panel to invert");
return false;
}
// Warning: it looks like LVGL rotation is broken when "gap" is set and the screen is moved to a non-default orientation
int gap_x = configuration->swapXY ? configuration->gapY : configuration->gapX;
int gap_y = configuration->swapXY ? configuration->gapX : configuration->gapY;
if (esp_lcd_panel_set_gap(panelHandle, gap_x, gap_y) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set panel gap");
return false;
}
if (esp_lcd_panel_swap_xy(panelHandle, configuration->swapXY) != ESP_OK) {
TT_LOG_E(TAG, "Failed to swap XY ");
return false;
}
if (esp_lcd_panel_mirror(panelHandle, configuration->mirrorX, configuration->mirrorY) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set panel to mirror");
return false;
}
if (esp_lcd_panel_disp_on_off(panelHandle, true) != ESP_OK) {
TT_LOG_E(TAG, "Failed to turn display on");
return false;
}
return true;
}
lvgl_port_display_cfg_t St7735Display::getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) {
return lvgl_port_display_cfg_t {
.io_handle = ioHandle,
.panel_handle = panelHandle,
.control_handle = nullptr,
.buffer_size = configuration->bufferSize,
.double_buffer = false,
.trans_size = 0,
.hres = configuration->horizontalResolution,
.vres = configuration->verticalResolution,
.monochrome = false,
.rotation = {
.swap_xy = configuration->swapXY,
.mirror_x = configuration->mirrorX,
.mirror_y = configuration->mirrorY,
},
.color_format = LV_COLOR_FORMAT_RGB565,
.flags = {
.buff_dma = true,
.buff_spiram = false,
.sw_rotate = false,
.swap_bytes = true,
.full_refresh = false,
.direct_mode = false
}
};
}
/**
* Note:
* The datasheet implies this should work, but it doesn't:
* https://www.digikey.com/htmldatasheets/production/1640716/0/0/1/ILI9341-Datasheet.pdf
*
* This repo claims it only has 1 curve:
* https://github.com/brucemack/hello-ili9341
*
* I'm leaving it in as I'm not sure if it's just my hardware that's problematic.
*/
void St7735Display::setGammaCurve(uint8_t index) {
uint8_t gamma_curve;
switch (index) {
case 0:
gamma_curve = 0x01;
break;
case 1:
gamma_curve = 0x04;
break;
case 2:
gamma_curve = 0x02;
break;
case 3:
gamma_curve = 0x08;
break;
default:
return;
}
const uint8_t param[] = {
gamma_curve
};
auto io_handle = getIoHandle();
assert(io_handle != nullptr);
if (esp_lcd_panel_io_tx_param(io_handle, LCD_CMD_GAMSET, param, 1) != ESP_OK) {
TT_LOG_E(TAG, "Failed to set gamma");
}
}

View File

@ -0,0 +1,116 @@
#pragma once
#include "Tactility/hal/spi/Spi.h"
#include <EspLcdDisplay.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include <driver/gpio.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_types.h>
#include <functional>
#include <lvgl.h>
class St7735Display final : public EspLcdDisplay {
std::shared_ptr<tt::Lock> lock;
public:
class Configuration {
public:
Configuration(
spi_host_device_t spiHostDevice,
gpio_num_t csPin,
gpio_num_t dcPin,
gpio_num_t resetPin,
unsigned int horizontalResolution,
unsigned int verticalResolution,
std::shared_ptr<tt::hal::touch::TouchDevice> touch,
bool swapXY = false,
bool mirrorX = false,
bool mirrorY = false,
bool invertColor = false,
uint32_t bufferSize = 0, // Size in pixel count. 0 means default, which is 1/10 of the screen size
int gapX = 0,
int gapY = 0
) : spiHostDevice(spiHostDevice),
csPin(csPin),
dcPin(dcPin),
resetPin(resetPin),
horizontalResolution(horizontalResolution),
verticalResolution(verticalResolution),
gapX(gapX),
gapY(gapY),
swapXY(swapXY),
mirrorX(mirrorX),
mirrorY(mirrorY),
invertColor(invertColor),
bufferSize(bufferSize),
touch(std::move(touch))
{
if (this->bufferSize == 0) {
this->bufferSize = horizontalResolution * verticalResolution / 10;
}
}
spi_host_device_t spiHostDevice;
gpio_num_t csPin;
gpio_num_t dcPin;
gpio_num_t resetPin = GPIO_NUM_NC;
unsigned int pixelClockFrequency = 27'000'000; // Hertz
size_t transactionQueueDepth = 10;
unsigned int horizontalResolution;
unsigned int verticalResolution;
int gapX;
int gapY;
bool swapXY = false;
bool mirrorX = false;
bool mirrorY = false;
bool invertColor = false;
uint32_t bufferSize = 0; // Size in pixel count. 0 means default, which is 1/10 of the screen size
std::shared_ptr<tt::hal::touch::TouchDevice> touch;
std::function<void(uint8_t)> _Nullable backlightDutyFunction = nullptr;
};
private:
std::unique_ptr<Configuration> configuration;
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t& panelHandle) override;
lvgl_port_display_cfg_t getLvglPortDisplayConfig(esp_lcd_panel_io_handle_t ioHandle, esp_lcd_panel_handle_t panelHandle) override;
public:
explicit St7735Display(std::unique_ptr<Configuration> inConfiguration) :
EspLcdDisplay(tt::hal::spi::getLock(inConfiguration->spiHostDevice)),
configuration(std::move(inConfiguration)
) {
assert(configuration != nullptr);
assert(getLock() != nullptr);
}
std::string getName() const override { return "ST7735"; }
std::string getDescription() const override { return "ST7735 display"; }
std::shared_ptr<tt::hal::touch::TouchDevice> _Nullable getTouchDevice() override { return configuration->touch; }
void setBacklightDuty(uint8_t backlightDuty) override {
if (configuration->backlightDutyFunction != nullptr) {
configuration->backlightDutyFunction(backlightDuty);
}
}
bool supportsBacklightDuty() const override { return configuration->backlightDutyFunction != nullptr; }
void setGammaCurve(uint8_t index) override;
uint8_t getGammaCurveCount() const override { return 4; };
};
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();

View File

@ -41,6 +41,8 @@ menu "Tactility App"
bool "Elecrow CrowPanel Basic 5.0"
config TT_BOARD_LILYGO_TDECK
bool "LilyGo T-Deck"
config TT_BOARD_LILYGO_TDONGLE_S3
bool "LilyGo T-Dongle S3"
config TT_BOARD_LILYGO_TLORA_PAGER
bool "LilyGo T-Lora Pager"
config TT_BOARD_M5STACK_CARDPUTER

View File

@ -8,6 +8,9 @@
#if defined(CONFIG_TT_BOARD_LILYGO_TDECK)
#include "LilygoTdeck.h"
#define TT_BOARD_HARDWARE &lilygo_tdeck
#elif defined(CONFIG_TT_BOARD_LILYGO_TDONGLE_S3)
#include "LilygoTdongleS3.h"
#define TT_BOARD_HARDWARE &lilygo_tdongle_s3
#elif defined(CONFIG_TT_BOARD_LILYGO_TLORA_PAGER)
#include "LilygoTloraPager.h"
#define TT_BOARD_HARDWARE &lilygo_tlora_pager

View File

@ -1,6 +1,7 @@
dependencies:
espressif/esp_lcd_ili9341: "2.0.1"
atanisoft/esp_lcd_ili9488: "1.0.10"
teriyakigod/esp_lcd_st7735: "0.0.1"
espressif/esp_lcd_touch: "1.1.2"
atanisoft/esp_lcd_touch_xpt2046: "1.0.5"
espressif/esp_lcd_touch_cst816s: "1.0.3"

View File

@ -0,0 +1,91 @@
#ifdef ESP_PLATFORM
#pragma once
#include "SdCardDevice.h"
#include <Tactility/hal/spi/Spi.h>
#include <sd_protocol_types.h>
#include <utility>
#include <vector>
#include <Tactility/hal/Device.h>
#include <hal/spi_types.h>
#include <soc/gpio_num.h>
namespace tt::hal::sdcard {
/**
* SD card interface for the SDMMC interface.
*/
class SdmmcDevice final : public SdCardDevice {
std::shared_ptr<Mutex> mutex = std::make_shared<Mutex>(Mutex::Type::Recursive);
public:
struct Config {
Config(
gpio_num_t pinClock,
gpio_num_t pinCmd,
gpio_num_t pinD0,
gpio_num_t pinD1,
gpio_num_t pinD2,
gpio_num_t pinD3,
MountBehaviour mountBehaviourAtBoot
) :
pinClock(pinClock),
pinCmd(pinCmd),
pinD0(pinD0),
pinD1(pinD1),
pinD2(pinD2),
pinD3(pinD3),
mountBehaviourAtBoot(mountBehaviourAtBoot)
{}
int spiFrequencyKhz;
gpio_num_t pinClock;
gpio_num_t pinCmd;
gpio_num_t pinD0;
gpio_num_t pinD1;
gpio_num_t pinD2;
gpio_num_t pinD3;
MountBehaviour mountBehaviourAtBoot;
bool formatOnMountFailed = false;
uint16_t maxOpenFiles = 4;
uint16_t allocUnitSize = 16 * 1024;
bool statusCheckEnabled = false;
};
private:
std::string mountPath;
sdmmc_card_t* card = nullptr;
std::shared_ptr<Config> config;
bool applyGpioWorkAround();
bool mountInternal(const std::string& mountPath);
public:
explicit SdmmcDevice(std::unique_ptr<Config> config) : SdCardDevice(config->mountBehaviourAtBoot),
config(std::move(config))
{}
std::string getName() const override { return "SDMMC"; }
std::string getDescription() const override { return "SD card via SDMMC interface"; }
bool mount(const std::string& mountPath) override;
bool unmount() override;
std::string getMountPath() const override { return mountPath; }
std::shared_ptr<Lock> getLock() const override { return mutex; }
State getState(TickType_t timeout) const override;
sdmmc_card_t* _Nullable getCard() { return card; }
};
}
#endif

View File

@ -4,6 +4,6 @@
namespace tt {
void initFromBootApp();
void registerApps();
}

View File

@ -201,6 +201,13 @@ static void registerInstalledAppsFromSdCards() {
}
}
static void registerInstalledAppsFromData() {
auto app_path = "/data/app";
if (file::isDirectory(app_path)) {
registerInstalledApps(app_path);
}
}
static void registerAndStartSecondaryServices() {
TT_LOG_I(TAG, "Registering and starting system services");
addService(service::loader::manifest);
@ -222,13 +229,14 @@ static void registerAndStartPrimaryServices() {
#endif
}
void initFromBootApp() {
void registerApps() {
registerInternalApps();
auto data_apps_path = std::format("{}/apps", file::MOUNT_POINT_DATA);
if (file::isDirectory(data_apps_path)) {
registerInstalledApps(data_apps_path);
}
registerInstalledAppsFromSdCards();
registerInstalledAppsFromData();
}
void run(const Configuration& config) {

View File

@ -108,7 +108,7 @@ class BootApp : public App {
if (!setupUsbBootMode()) {
TT_LOG_I(TAG, "initFromBootApp");
initFromBootApp();
registerApps();
waitForMinimalSplashDuration(start_time);
stop(manifest.appId);
startNextApp();

View File

@ -0,0 +1,113 @@
#ifdef ESP_PLATFORM
#include <Tactility/hal/sdcard/SdmmcDevice.h>
#include <Tactility/Log.h>
#include <esp_vfs_fat.h>
#include <sdmmc_cmd.h>
#include <driver/sdmmc_host.h>
namespace tt::hal::sdcard {
constexpr auto* TAG = "SdmmcDevice";
bool SdmmcDevice::mountInternal(const std::string& newMountPath) {
TT_LOG_I(TAG, "Mounting %s", newMountPath.c_str());
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = config->formatOnMountFailed,
.max_files = config->maxOpenFiles,
.allocation_unit_size = config->allocUnitSize,
.disk_status_check_enable = config->statusCheckEnabled,
.use_one_fat = false
};
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = {
.clk = config->pinClock,
.cmd = config->pinCmd,
.d0 = config->pinD0,
.d1 = config->pinD1,
.d2 = config->pinD2,
.d3 = config->pinD3,
.d4 = static_cast<gpio_num_t>(0),
.d5 = static_cast<gpio_num_t>(0),
.d6 = static_cast<gpio_num_t>(0),
.d7 = static_cast<gpio_num_t>(0),
.cd = GPIO_NUM_NC,
.wp = GPIO_NUM_NC,
.width = 4,
.flags = 0
};
esp_err_t result = esp_vfs_fat_sdmmc_mount(newMountPath.c_str(), &host, &slot_config, &mount_config, &card);
if (result != ESP_OK || card == nullptr) {
if (result == ESP_FAIL) {
TT_LOG_E(TAG, "Mounting failed. Ensure the card is formatted with FAT.");
} else {
TT_LOG_E(TAG, "Mounting failed (%s)", esp_err_to_name(result));
}
return false;
}
mountPath = newMountPath;
return true;
}
bool SdmmcDevice::mount(const std::string& newMountPath) {
if (mountInternal(newMountPath)) {
TT_LOG_I(TAG, "Mounted at %s", newMountPath.c_str());
sdmmc_card_print_info(stdout, card);
return true;
} else {
TT_LOG_E(TAG, "Mount failed for %s", newMountPath.c_str());
return false;
}
}
bool SdmmcDevice::unmount() {
if (card == nullptr) {
TT_LOG_E(TAG, "Can't unmount: not mounted");
return false;
}
if (esp_vfs_fat_sdcard_unmount(mountPath.c_str(), card) != ESP_OK) {
TT_LOG_E(TAG, "Unmount failed for %s", mountPath.c_str());
return false;
}
TT_LOG_I(TAG, "Unmounted %s", mountPath.c_str());
mountPath = "";
card = nullptr;
return true;
}
SdmmcDevice::State SdmmcDevice::getState(TickType_t timeout) const {
if (card == nullptr) {
return State::Unmounted;
}
/**
* The SD card and the screen are on the same SPI bus.
* Writing and reading to the bus from 2 devices at the same time causes crashes.
* This work-around ensures that this check is only happening when LVGL isn't rendering.
*/
auto lock = getLock()->asScopedLock();
bool locked = lock.lock(timeout);
if (!locked) {
return State::Timeout;
}
if (sdmmc_get_status(card) != ESP_OK) {
return State::Error;
}
return State::Mounted;
}
}
#endif

View File

@ -20,7 +20,10 @@ namespace tt {
class Mutex final : public Lock {
public:
/**
* A "Normal" mutex can only be locked once. Even from within the same task/thread.
* A "Recursive" mutex can be locked again from the same task/thread.
*/
enum class Type {
Normal,
Recursive,

View File

@ -0,0 +1,53 @@
# Software defaults
# Increase stack size for WiFi (fixes crash after scan)
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3072
CONFIG_LV_FONT_MONTSERRAT_14=y
CONFIG_LV_FONT_MONTSERRAT_18=y
CONFIG_LV_USE_USER_DATA=y
CONFIG_LV_USE_FS_STDIO=y
CONFIG_LV_FS_STDIO_LETTER=65
CONFIG_LV_FS_STDIO_PATH=""
CONFIG_LV_FS_STDIO_CACHE_SIZE=4096
CONFIG_LV_USE_LODEPNG=y
CONFIG_LV_USE_BUILTIN_MALLOC=n
CONFIG_LV_USE_CLIB_MALLOC=y
CONFIG_LV_USE_MSGBOX=n
CONFIG_LV_USE_SPINNER=n
CONFIG_LV_USE_WIN=n
CONFIG_LV_USE_SNAPSHOT=y
CONFIG_FREERTOS_HZ=1000
CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=2
CONFIG_FREERTOS_SMP=n
CONFIG_FREERTOS_UNICORE=n
CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=5120
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
CONFIG_FATFS_LFN_HEAP=y
CONFIG_FATFS_VOLUME_COUNT=3
CONFIG_FATFS_SECTOR_512=y
CONFIG_WL_SECTOR_SIZE_512=y
CONFIG_WL_SECTOR_SIZE=512
CONFIG_WL_SECTOR_MODE_SAFE=y
CONFIG_WL_SECTOR_MODE=1
# Hardware: Main
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions-16mb.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions-16mb.csv"
CONFIG_TT_BOARD_LILYGO_TDONGLE_S3=y
CONFIG_TT_BOARD_NAME="LilyGo T-Dongle S3"
CONFIG_TT_BOARD_ID="lilygo-tdongle-s3"
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_IDF_TARGET="esp32s3"
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_FLASHMODE_QIO=y
# SPI Flash (can set back to 80MHz after ESP-IDF bug is resolved)
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
# LVGL
CONFIG_LV_DPI_DEF=186
CONFIG_LV_DISP_DEF_REFR_PERIOD=10
CONFIG_LV_THEME_DEFAULT_DARK=y
# USB
CONFIG_TINYUSB_MSC_ENABLED=y
CONFIG_TINYUSB_MSC_MOUNT_PATH="/sdcard"