Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build-firmware.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ jobs:
{ id: waveshare-s3-touch-lcd-43, arch: esp32s3 },
{ id: waveshare-s3-touch-lcd-147, arch: esp32s3 },
{ id: waveshare-s3-touch-lcd-128, arch: esp32s3 },
{ id: waveshare-s3-lcd-13, arch: esp32s3 }
{ id: waveshare-s3-lcd-13, arch: esp32s3 },
{ id: waveshare-esp32-c6-lcd-147, arch: esp32c6 }
]
runs-on: ubuntu-latest
steps:
Expand Down
7 changes: 7 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)

idf_component_register(
SRCS ${SOURCE_FILES}
INCLUDE_DIRS "Source"
REQUIRES Tactility esp_lvgl_port ST7789 PwmBacklight driver
)
53 changes: 53 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/Source/Configuration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "devices/Display.h"
#include "devices/SdCard.h"

#include <PwmBacklight.h>
#include <Tactility/hal/Configuration.h>
#include <Tactility/hal/uart/Uart.h>
#include <Tactility/lvgl/LvglSync.h>

using namespace tt::hal;

static DeviceVector createDevices() {
return {
createDisplay(),
createSdCard()
// TODO: Add RGB LED device (GPIO8, RMT-based WS2812)
};
}

extern bool initBoot();

extern const Configuration hardwareConfiguration = {
.initBoot = initBoot,
.uiScale = UiScale::Smallest,
.createDevices = createDevices,
.i2c = {},
.spi {
// Display and SD card (shared SPI bus)
spi::Configuration {
.device = LCD_SPI_HOST,
.dma = SPI_DMA_CH_AUTO,
.config = {
.mosi_io_num = LCD_PIN_MOSI,
.miso_io_num = LCD_PIN_MISO,
.sclk_io_num = LCD_PIN_SCLK,
.quadwp_io_num = GPIO_NUM_NC,
.quadhd_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 = LCD_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 {}
};
8 changes: 8 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/Source/Init.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#include "devices/Display.h"

#include <PwmBacklight.h>

bool initBoot() {
// Initialize backlight with 5 kHz frequency (as per demo code)
return driver::pwmbacklight::init(LCD_PIN_BACKLIGHT, 5000);
}
38 changes: 38 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/Source/devices/Display.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include "Display.h"

#include <PwmBacklight.h>
#include <St7789Display.h>

std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
// Configuration based on demo code:
// - Resolution: 172x320
// - X offset: 34 pixels (gapX parameter)
// - Y offset: 0 pixels
// - Mirror X-axis disabled (to fix inverted text)
// - 12MHz SPI clock

St7789Display::Configuration panel_configuration = {
.horizontalResolution = LCD_HORIZONTAL_RESOLUTION,
.verticalResolution = LCD_VERTICAL_RESOLUTION,
.gapX = LCD_GAP_X,
.gapY = LCD_GAP_Y,
.swapXY = false,
.mirrorX = false, // disabled to fix inverted text
.mirrorY = false,
.invertColor = true,
.bufferSize = 0, // default = 1/10 of screen
.touch = nullptr,
.backlightDutyFunction = driver::pwmbacklight::setBacklightDuty,
.resetPin = LCD_PIN_RESET
};

auto spi_configuration = std::make_shared<St7789Display::SpiConfiguration>(St7789Display::SpiConfiguration {
.spiHostDevice = LCD_SPI_HOST,
.csPin = LCD_PIN_CS,
.dcPin = LCD_PIN_DC,
.pixelClockFrequency = LCD_PIXEL_CLOCK_HZ,
.transactionQueueDepth = 10
});

return std::make_shared<St7789Display>(panel_configuration, spi_configuration);
}
32 changes: 32 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/Source/devices/Display.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include "Tactility/hal/display/DisplayDevice.h"
#include <driver/gpio.h>
#include <driver/spi_common.h>
#include <memory>

// Display SPI configuration
constexpr auto LCD_SPI_HOST = SPI2_HOST;
constexpr auto LCD_PIN_CS = GPIO_NUM_14;
constexpr auto LCD_PIN_DC = GPIO_NUM_15;
constexpr auto LCD_PIN_RESET = GPIO_NUM_21;
constexpr auto LCD_PIXEL_CLOCK_HZ = 12'000'000; // 12 MHz as in demo

// Display panel configuration
constexpr auto LCD_HORIZONTAL_RESOLUTION = 172;
constexpr auto LCD_VERTICAL_RESOLUTION = 320;
constexpr auto LCD_GAP_X = 34; // X offset for 1.47" display
constexpr auto LCD_GAP_Y = 0;

// Display backlight
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_22;

// SPI bus configuration (shared with SD card)
constexpr auto LCD_PIN_MOSI = GPIO_NUM_6;
constexpr auto LCD_PIN_MISO = GPIO_NUM_5;
constexpr auto LCD_PIN_SCLK = GPIO_NUM_7;
constexpr auto LCD_BUFFER_HEIGHT = LCD_VERTICAL_RESOLUTION / 10;
constexpr auto LCD_BUFFER_SIZE = LCD_HORIZONTAL_RESOLUTION * LCD_BUFFER_HEIGHT;
constexpr auto LCD_SPI_TRANSFER_SIZE_LIMIT = LCD_BUFFER_SIZE * LV_COLOR_DEPTH / 8;

std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay();
26 changes: 26 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/Source/devices/SdCard.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "SdCard.h"
#include "Display.h"

#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
#include <Tactility/hal/spi/Spi.h>

using tt::hal::sdcard::SpiSdCardDevice;

std::shared_ptr<SdCardDevice> createSdCard() {
// SD card shares SPI bus with display (SPI2_HOST)
// CS pin is GPIO4, need to protect display CS during SD operations
auto configuration = std::make_unique<SpiSdCardDevice::Config>(
SD_PIN_CS, // CS pin for SD card
GPIO_NUM_NC, // CD (card detect) pin - not used
GPIO_NUM_NC, // WP (write protect) pin - not used
GPIO_NUM_NC, // Power pin - not used
SdCardDevice::MountBehaviour::AtBoot,
tt::hal::spi::getLock(LCD_SPI_HOST), // Use same lock as display
std::vector<gpio_num_t> { LCD_PIN_CS }, // Assert display CS high during SD operations
LCD_SPI_HOST
);

return std::make_shared<SpiSdCardDevice>(
std::move(configuration)
);
}
13 changes: 13 additions & 0 deletions Boards/waveshare-esp32-c6-lcd-147/Source/devices/SdCard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Tactility/hal/sdcard/SdCardDevice.h"
#include <driver/gpio.h>
#include <driver/spi_common.h>
#include <memory>

using tt::hal::sdcard::SdCardDevice;

// SD card configuration (shares SPI bus with display)
constexpr auto SD_PIN_CS = GPIO_NUM_4;

std::shared_ptr<SdCardDevice> createSdCard();
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ if (DEFINED ENV{ESP_IDF_VERSION})

set(EXCLUDE_COMPONENTS "Simulator")

idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_panic_handler" APPEND)
# Panic handler wrapping is only available on Xtensa architecture
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=esp_panic_handler" APPEND)
endif()

idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_button_create" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_dropdown_create" APPEND)
idf_build_set_property(LINK_OPTIONS "-Wl,--wrap=lv_list_create" APPEND)
Expand Down
2 changes: 2 additions & 0 deletions Firmware/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ menu "Tactility App"
bool "Waveshare ESP32 S3 Touch LCD 1.28"
config TT_BOARD_WAVESHARE_S3_LCD_13
bool "Waveshare ESP32 S3 LCD 1.3"
config TT_BOARD_WAVESHARE_ESP32_C6_LCD_147
bool "Waveshare ESP32 C6 LCD 1.47"
help
Select a board/hardware configuration.
Use TT_BOARD_CUSTOM if you will manually configure the board in your project.
Expand Down
22 changes: 18 additions & 4 deletions Firmware/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
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_ili9341:
version: "2.0.1"
rules:
- if: "target in [esp32, esp32s3]"
atanisoft/esp_lcd_ili9488:
version: "1.0.10"
rules:
- if: "target in [esp32, esp32s3]"
teriyakigod/esp_lcd_st7735:
version: "0.0.1"
rules:
- if: "target in [esp32, esp32s3]"
espressif/esp_lcd_touch: "1.1.2"
atanisoft/esp_lcd_touch_xpt2046: "1.0.5"
atanisoft/esp_lcd_touch_xpt2046:
version: "1.0.5"
rules:
- if: "target in [esp32, esp32s3]"
espressif/esp_lcd_touch_cst816s: "1.0.3"
espressif/esp_lcd_touch_gt911: "1.1.3"
espressif/esp_lcd_touch_ft5x06: "1.0.6~1"
Expand All @@ -15,6 +27,8 @@ dependencies:
- if: "target in [esp32s3, esp32p4]"
espressif/esp_lcd_st7796:
version: "1.3.4"
rules:
- if: "target in [esp32, esp32s3]"
Comment on lines 16 to +31
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify ST7796 driver compatibility with ESP32-C6.

The ST7796 driver is now restricted to [esp32, esp32s3]. Verify whether it supports ESP32-C6, and if so, add esp32c6 to enable future board support.


🏁 Script executed:

#!/bin/bash
# Check if ST7796 supports ESP32-C6
curl -s "https://components.espressif.com/api/v1/components/espressif/esp_lcd_st7796/versions/1.3.4" | jq -r '.targets[]' 2>/dev/null || echo "Failed to fetch target info"

Length of output: 27


I'll search for documentation on the ST7796 driver's ESP32 compatibility to verify ESP32-C6 support.

Add esp32c6 to ST7796 driver target list.

ESP32-C6 support is available for ST7796, requiring ESP-IDF V5.1. Update the rules condition in Firmware/idf_component.yml at lines 28-31 to include esp32c6:

  espressif/esp_lcd_st7796:
    version: "1.3.4"
    rules:
      - if: "target in [esp32, esp32s3, esp32c6]"
🤖 Prompt for AI Agents
Firmware/idf_component.yml around lines 28-31: the ST7796 component rule only
allows esp32 and esp32s3 targets but needs esp32c6 support; modify the rules
condition to include esp32c6 so the line becomes a target list containing esp32,
esp32s3, esp32c6, and ensure the project uses ESP-IDF v5.1 or later as required
by the driver.

espressif/esp_lcd_gc9a01: "2.0.3"
espressif/esp_lcd_panel_io_additions: "1.0.1"
espressif/esp_tinyusb:
Expand Down
14 changes: 11 additions & 3 deletions Tactility/Source/app/crashdiagnostics/QrUrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@
#include <Tactility/kernel/PanicHandler.h>

#include <sstream>
#include <vector>
#include <esp_cpu.h>

#if CONFIG_IDF_TARGET_ARCH_XTENSA
#include <esp_cpu_utils.h>
#endif

#include <sdkconfig.h>

std::string getUrlFromCrashData() {
auto crash_data = getRtcCrashData();
auto* stack_buffer = (uint32_t*) malloc(crash_data.callstackLength * 2 * sizeof(uint32_t));
std::vector<uint32_t> stack_buffer(crash_data.callstackLength * 2);

for (int i = 0; i < crash_data.callstackLength; ++i) {
const CallstackFrame&frame = crash_data.callstack[i];
#if CONFIG_IDF_TARGET_ARCH_XTENSA
uint32_t pc = esp_cpu_process_stack_pc(frame.pc);
#else
uint32_t pc = frame.pc; // No processing needed on RISC-V
#endif
#if CRASH_DATA_INCLUDES_SP
uint32_t sp = frame.sp;
#endif
Expand All @@ -41,8 +51,6 @@ std::string getUrlFromCrashData() {
#endif
}

free(stack_buffer);

return stream.str();
}

Expand Down
8 changes: 4 additions & 4 deletions Tactility/Source/hal/sdcard/SdmmcDevice.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#ifdef ESP_PLATFORM
#if defined(ESP_PLATFORM) && defined(SOC_SDMMC_HOST_SUPPORTED)

#include <Tactility/hal/sdcard/SdmmcDevice.h>
#include <Tactility/Log.h>
Expand Down Expand Up @@ -97,9 +97,9 @@ SdmmcDevice::State SdmmcDevice::getState(TickType_t timeout) const {
}

/**
* 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.
* Use locking to prevent concurrent access to the SD card during display rendering.
* This ensures that SD card status checks only happen when LVGL isn't actively rendering,
* preventing potential timing issues or resource conflicts.
*/
auto lock = getLock()->asScopedLock();
bool locked = lock.lock(timeout);
Expand Down
6 changes: 6 additions & 0 deletions TactilityCore/Source/CpuAffinity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ namespace tt {

#ifdef ESP_PLATFORM

#if CONFIG_FREERTOS_NUMBER_OF_CORES == 2
static CpuAffinity getEspWifiAffinity() {
#ifdef CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0
return 0;
#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1)
return 1;
#else
return 0; // Default to core 0 if not specified
#endif
}

Expand All @@ -20,8 +23,11 @@ static CpuAffinity getEspMainSchedulerAffinity() {
return 0;
#elif defined(CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1)
return 1;
#else
return 0; // Default to core 0 if not specified
#endif
}
#endif // CONFIG_FREERTOS_NUMBER_OF_CORES == 2

static CpuAffinity getFreeRtosTimerAffinity() {
#if defined(CONFIG_FREERTOS_TIMER_TASK_NO_AFFINITY)
Expand Down
Loading
Loading