Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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 = SPI2_HOST,
.dma = SPI_DMA_CH_AUTO,
.config = {
.mosi_io_num = GPIO_NUM_6,
.miso_io_num = GPIO_NUM_5,
.sclk_io_num = GPIO_NUM_7,
.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 = ((172 * (320 / 10)) * LV_COLOR_DEPTH / 8),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we make this a constexpr auto .. in Display.h?

A common setup (from another board) looks like this:

constexpr auto LCD_SPI_HOST = SPIX_HOST;
constexpr auto LCD_PIN_CS = GPIO_NUM_XX;
constexpr auto LCD_PIN_DC = GPIO_NUM_XX; // RS
constexpr auto LCD_HORIZONTAL_RESOLUTION = ...;
constexpr auto LCD_VERTICAL_RESOLUTION = ...;
constexpr auto LCD_BUFFER_HEIGHT = (LCD_VERTICAL_RESOLUTION / 3);
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;

Yesterday I refactored the remaining boards to use constexpr in this manner

Comment thread
marciogranzotto marked this conversation as resolved.
Outdated
.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
}
Comment thread
KenVanHoeylandt marked this conversation as resolved.
},
.uart {}
};
Comment thread
KenVanHoeylandt marked this conversation as resolved.
82 changes: 82 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,82 @@
#include <driver/ledc.h>
#include <esp_err.h>
#include <driver/gpio.h>

// Backlight configuration based on demo code
#define LCD_BL_PIN GPIO_NUM_22
#define LCD_BL_LEDC_MODE LEDC_LOW_SPEED_MODE
#define LCD_BL_LEDC_TIMER LEDC_TIMER_0
#define LCD_BL_LEDC_CHANNEL LEDC_CHANNEL_0
#define LCD_BL_LEDC_RESOLUTION LEDC_TIMER_13_BIT // 13-bit resolution (8192 levels)
#define LCD_BL_LEDC_DUTY ((1 << LCD_BL_LEDC_RESOLUTION) - 1) // Max duty = 8191
#define LCD_BL_FREQUENCY 5000 // 5 kHz

namespace driver::pwmbacklight {

bool init(gpio_num_t pin, uint32_t maxDuty) {
// Configure LEDC timer
ledc_timer_config_t timer_config = {
.speed_mode = LCD_BL_LEDC_MODE,
.duty_resolution = LCD_BL_LEDC_RESOLUTION,
.timer_num = LCD_BL_LEDC_TIMER,
.freq_hz = LCD_BL_FREQUENCY,
.clk_cfg = LEDC_AUTO_CLK
};
Comment thread
KenVanHoeylandt marked this conversation as resolved.
Outdated
esp_err_t err = ledc_timer_config(&timer_config);
if (err != ESP_OK) {
return false;
}

// Configure LEDC channel
ledc_channel_config_t channel_config = {
.gpio_num = LCD_BL_PIN,
.speed_mode = LCD_BL_LEDC_MODE,
.channel = LCD_BL_LEDC_CHANNEL,
.intr_type = LEDC_INTR_DISABLE,
.timer_sel = LCD_BL_LEDC_TIMER,
.duty = 0, // Start with backlight off
.hpoint = 0,
.flags = {
.output_invert = 0
}
};
err = ledc_channel_config(&channel_config);
if (err != ESP_OK) {
return false;
}

return true;
}

void setBacklightDuty(uint8_t level) {
// Convert 0-255 level to duty cycle with inverted mapping as in demo code
// The demo uses: duty = max - (81 * (100 - percentage))
// We'll adapt this for 0-255 range
if (level > 255) level = 255;

// Map 0-255 to 0-100 percentage
uint8_t percentage = (level * 100) / 255;

// Calculate duty with inverted logic (higher level = higher duty)
uint32_t duty;
if (percentage == 0) {
duty = 0;
} else {
// Map to full range: 0% -> 0, 100% -> LCD_BL_LEDC_DUTY
duty = LCD_BL_LEDC_DUTY - ((81 * (100 - percentage)));
}

// Ensure duty doesn't exceed max
if (duty > LCD_BL_LEDC_DUTY) {
duty = LCD_BL_LEDC_DUTY;
}

ledc_set_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL, duty);
ledc_update_duty(LCD_BL_LEDC_MODE, LCD_BL_LEDC_CHANNEL);
}

} // namespace driver::pwmbacklight
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did the driver from Drivers/PwmBacklight/ not work?
If it didn't work then I'm fine with the custom code. Otherwise:

You should be able to use the things from <PwmBacklight.h> (although in rare cases it might not work)

You use it by calling this from initBoot(), just like your function:

    if (!driver::pwmbacklight::init(LCD_BL_PIN, 256)) {
        TT_LOG_E(TAG, "Backlight init failed");
        return false;
    }

And then the display config can simply set:

 .backlightDutyFunction = driver::pwmbacklight::setBacklightDuty,


bool initBoot() {
return driver::pwmbacklight::init(LCD_BL_PIN, 256);
}
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 = 172,
.verticalResolution = 320,
.gapX = 34, // X offset for 1.47" display
.gapY = 0,
.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 = GPIO_NUM_21
};

auto spi_configuration = std::make_shared<St7789Display::SpiConfiguration>(St7789Display::SpiConfiguration {
.spiHostDevice = SPI2_HOST,
.csPin = GPIO_NUM_14,
.dcPin = GPIO_NUM_15,
.pixelClockFrequency = 12'000'000, // 12 MHz as in demo
.transactionQueueDepth = 10
});

return std::make_shared<St7789Display>(panel_configuration, spi_configuration);
}
5 changes: 5 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,5 @@
#pragma once

#include "Tactility/hal/display/DisplayDevice.h"

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 <Tactility/lvgl/LvglSync.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>(
GPIO_NUM_4, // 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(SPI2_HOST), // Use same lock as display
std::vector<gpio_num_t> { GPIO_NUM_14 }, // Assert display CS high during SD operations
SPI2_HOST
);

return std::make_shared<SpiSdCardDevice>(
std::move(configuration)
);
}
7 changes: 7 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,7 @@
#pragma once

#include "Tactility/hal/sdcard/SdCardDevice.h"

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

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
Copy Markdown

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
8 changes: 8 additions & 0 deletions Tactility/Source/app/crashdiagnostics/QrUrl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
#include <Tactility/kernel/PanicHandler.h>

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

#if CONFIG_IDF_TARGET_ARCH_XTENSA
#include <esp_cpu_utils.h>
#endif
Comment thread
KenVanHoeylandt marked this conversation as resolved.

#include <sdkconfig.h>

Expand All @@ -14,7 +18,11 @@ std::string getUrlFromCrashData() {
auto* stack_buffer = (uint32_t*) malloc(crash_data.callstackLength * 2 * sizeof(uint32_t));
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 Down
2 changes: 1 addition & 1 deletion 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
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