mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-02-20 15:35:05 +00:00
Implement LilyGO T-Dongle S3
+ fix issue with apps installed in /data + implement SDMMC driver + implement ST7735 driver
This commit is contained in:
parent
114062c96d
commit
e23b956cf4
7
Boards/LilygoTdongleS3/CMakeLists.txt
Normal file
7
Boards/LilygoTdongleS3/CMakeLists.txt
Normal 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
|
||||
)
|
||||
15
Boards/LilygoTdongleS3/Source/Init.cpp
Normal file
15
Boards/LilygoTdongleS3/Source/Init.cpp
Normal 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;
|
||||
}
|
||||
92
Boards/LilygoTdongleS3/Source/LilygoTdongleS3.cpp
Normal file
92
Boards/LilygoTdongleS3/Source/LilygoTdongleS3.cpp
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
5
Boards/LilygoTdongleS3/Source/LilygoTdongleS3.h
Normal file
5
Boards/LilygoTdongleS3/Source/LilygoTdongleS3.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/Configuration.h>
|
||||
|
||||
extern const tt::hal::Configuration lilygo_tdongle_s3;
|
||||
36
Boards/LilygoTdongleS3/Source/devices/Display.cpp
Normal file
36
Boards/LilygoTdongleS3/Source/devices/Display.cpp
Normal 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);
|
||||
}
|
||||
5
Boards/LilygoTdongleS3/Source/devices/Display.h
Normal file
5
Boards/LilygoTdongleS3/Source/devices/Display.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/display/DisplayDevice.h>
|
||||
|
||||
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
|
||||
22
Boards/LilygoTdongleS3/Source/devices/Sdcard.cpp
Normal file
22
Boards/LilygoTdongleS3/Source/devices/Sdcard.cpp
Normal 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)
|
||||
);
|
||||
}
|
||||
7
Boards/LilygoTdongleS3/Source/devices/Sdcard.h
Normal file
7
Boards/LilygoTdongleS3/Source/devices/Sdcard.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
||||
|
||||
using tt::hal::sdcard::SdCardDevice;
|
||||
|
||||
std::shared_ptr<SdCardDevice> createSdCard();
|
||||
@ -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")
|
||||
|
||||
5
Drivers/ST7735/CMakeLists.txt
Normal file
5
Drivers/ST7735/CMakeLists.txt
Normal 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
3
Drivers/ST7735/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# ST7735
|
||||
|
||||
A basic ESP32 LVGL driver for ST7735 displays.
|
||||
170
Drivers/ST7735/Source/St7735Display.cpp
Normal file
170
Drivers/ST7735/Source/St7735Display.cpp
Normal 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");
|
||||
}
|
||||
}
|
||||
116
Drivers/ST7735/Source/St7735Display.h
Normal file
116
Drivers/ST7735/Source/St7735Display.h
Normal 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();
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
91
Tactility/Include/Tactility/hal/sdcard/SdmmcDevice.h
Normal file
91
Tactility/Include/Tactility/hal/sdcard/SdmmcDevice.h
Normal 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
|
||||
@ -4,6 +4,6 @@
|
||||
|
||||
namespace tt {
|
||||
|
||||
void initFromBootApp();
|
||||
void registerApps();
|
||||
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -108,7 +108,7 @@ class BootApp : public App {
|
||||
|
||||
if (!setupUsbBootMode()) {
|
||||
TT_LOG_I(TAG, "initFromBootApp");
|
||||
initFromBootApp();
|
||||
registerApps();
|
||||
waitForMinimalSplashDuration(start_time);
|
||||
stop(manifest.appId);
|
||||
startNextApp();
|
||||
|
||||
113
Tactility/Source/hal/sdcard/SdmmcDevice.cpp
Normal file
113
Tactility/Source/hal/sdcard/SdmmcDevice.cpp
Normal 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
|
||||
@ -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,
|
||||
|
||||
53
sdkconfig.board.lilygo-tdongle-s3
Normal file
53
sdkconfig.board.lilygo-tdongle-s3
Normal 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"
|
||||
Loading…
x
Reference in New Issue
Block a user