-
-
Notifications
You must be signed in to change notification settings - Fork 90
Add support for Waveshare ESP32-C6-LCD-1.47 board #394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
| ) |
| 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), | ||
|
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 | ||
| } | ||
|
KenVanHoeylandt marked this conversation as resolved.
|
||
| }, | ||
| .uart {} | ||
| }; | ||
|
KenVanHoeylandt marked this conversation as resolved.
|
||
| 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 | ||
| }; | ||
|
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 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did the driver from You should be able to use the things from 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); | ||
| } | ||
| 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); | ||
| } |
| 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(); |
| 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) | ||
| ); | ||
| } |
| 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(); |
| 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" | ||
|
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify ST7796 driver compatibility with ESP32-C6. The ST7796 driver is now restricted to 🏁 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 ESP32-C6 support is available for ST7796, requiring ESP-IDF V5.1. Update the 🤖 Prompt for AI Agents |
||
| espressif/esp_lcd_gc9a01: "2.0.3" | ||
| espressif/esp_lcd_panel_io_additions: "1.0.1" | ||
| espressif/esp_tinyusb: | ||
|
|
||
There was a problem hiding this comment.
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 ..inDisplay.h?A common setup (from another board) looks like this:
Yesterday I refactored the remaining boards to use constexpr in this manner