Skip to content

Commit c98cb2b

Browse files
Add Guition JC1060P470CIWY and update other Guition device IDs (#447)
This commit contains @josemalm32 's implementation for the Guition JC1060P470CIWY (see #427) I've added these changes: - Updated the branch for the new logging method - Updated the branch for the PR that I mentioned in the above linked issue - Replaced the manually pasted in esp_lcd_jd9165 driver with the one from the component registry - Updated Spanish to English - Updated all drivers' mutexes/locks - Fixed the display color format - Fixed bug in power deinit - Renamed I2C bus in config - Added device to continuous integration - Renamed several Guition devices from CYD to Guition - Fix for `EspLcdDisplayV2` init for when features are not supported - Pin esp_wifi_remote to version 1.2.3 - Fix in `WifiManage` logging - Fix for `WifiEsp.cpp`'s check for wifi presence - Fix for `WifiEsp`'s scan list logging - Fix for `gcc_soft_float_symbols` in TactiltyC
1 parent f620255 commit c98cb2b

File tree

44 files changed

+1060
-46
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1060
-46
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,17 @@ jobs:
3939
{ id: cyd-e32r28t, arch: esp32 },
4040
{ id: cyd-e32r32p, arch: esp32 },
4141
{ id: cyd-2432s032c, arch: esp32 },
42-
{ id: cyd-jc2432w328c, arch: esp32 },
4342
{ id: cyd-8048s043c, arch: esp32s3 },
44-
{ id: cyd-jc8048w550c, arch: esp32s3 },
4543
{ id: cyd-4848s040c, arch: esp32s3 },
4644
{ id: elecrow-crowpanel-advance-28, arch: esp32s3 },
4745
{ id: elecrow-crowpanel-advance-35, arch: esp32s3 },
4846
{ id: elecrow-crowpanel-advance-50, arch: esp32s3 },
4947
{ id: elecrow-crowpanel-basic-28, arch: esp32 },
5048
{ id: elecrow-crowpanel-basic-35, arch: esp32 },
5149
{ id: elecrow-crowpanel-basic-50, arch: esp32s3 },
50+
{ id: guition-jc1060p470ciwy, arch: esp32p4 },
51+
{ id: guition-jc2432w328c, arch: esp32 },
52+
{ id: guition-jc8048w550c, arch: esp32s3 },
5253
{ id: heltec-wifi-lora-32-v3, arch: esp32s3 },
5354
{ id: lilygo-tdeck, arch: esp32s3 },
5455
{ id: lilygo-tdongle-s3, arch: esp32s3 },
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language=en-US
22
timeFormat24h=true
3-
dateFormat=MM/DD/YYYY
4-
region=US
3+
dateFormat=DD/MM/YYYY
4+
region=EU
55
timezone=Europe/Amsterdam
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
2+
3+
idf_component_register(
4+
SRCS ${SOURCE_FILES}
5+
INCLUDE_DIRS "Source"
6+
REQUIRES Tactility esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_jd9165 GT911 PwmBacklight driver vfs fatfs
7+
PRIV_REQUIRES esp_adc EstimatedPower
8+
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "devices/Display.h"
2+
#include "devices/Power.h"
3+
#include "devices/SdCard.h"
4+
5+
#include <Tactility/hal/Configuration.h>
6+
7+
using namespace tt::hal;
8+
9+
static DeviceVector createDevices() {
10+
return {
11+
createDisplay(),
12+
createSdCard(),
13+
createPower()
14+
};
15+
}
16+
17+
extern const Configuration hardwareConfiguration = {
18+
.createDevices = createDevices,
19+
.i2c = {
20+
i2c::Configuration {
21+
.name = "Internal",
22+
.port = I2C_NUM_0,
23+
.initMode = i2c::InitMode::ByTactility,
24+
.isMutable = false,
25+
.config = (i2c_config_t) {
26+
.mode = I2C_MODE_MASTER,
27+
.sda_io_num = GPIO_NUM_7,
28+
.scl_io_num = GPIO_NUM_8,
29+
.sda_pullup_en = true,
30+
.scl_pullup_en = true,
31+
.master = {
32+
.clk_speed = 400000
33+
},
34+
.clk_flags = 0
35+
}
36+
}
37+
}
38+
};
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#include "Display.h"
2+
#include "Jd9165Display.h"
3+
4+
#include <Gt911Touch.h>
5+
#include <PwmBacklight.h>
6+
#include <Tactility/Logger.h>
7+
#include <Tactility/Mutex.h>
8+
9+
constexpr auto LCD_PIN_RESET = GPIO_NUM_0; // Match P4 EV board reset line
10+
constexpr auto LCD_PIN_BACKLIGHT = GPIO_NUM_23;
11+
constexpr auto LCD_HORIZONTAL_RESOLUTION = 1024;
12+
constexpr auto LCD_VERTICAL_RESOLUTION = 600;
13+
14+
constexpr auto TOUCH_I2C_PORT = I2C_NUM_0;
15+
constexpr auto TOUCH_I2C_SDA = GPIO_NUM_7;
16+
constexpr auto TOUCH_I2C_SCL = GPIO_NUM_8;
17+
constexpr auto TOUCH_PIN_RESET = GPIO_NUM_NC;
18+
constexpr auto TOUCH_PIN_INTERRUPT = GPIO_NUM_NC;
19+
20+
static std::shared_ptr<tt::hal::touch::TouchDevice> createTouch() {
21+
auto configuration = std::make_unique<Gt911Touch::Configuration>(
22+
TOUCH_I2C_PORT,
23+
LCD_HORIZONTAL_RESOLUTION,
24+
LCD_VERTICAL_RESOLUTION,
25+
false, // swapXY
26+
false, // mirrorX
27+
false, // mirrorY
28+
TOUCH_PIN_RESET,
29+
TOUCH_PIN_INTERRUPT
30+
);
31+
32+
return std::make_shared<Gt911Touch>(std::move(configuration));
33+
}
34+
35+
std::shared_ptr<tt::hal::display::DisplayDevice> createDisplay() {
36+
// Initialize PWM backlight
37+
if (!driver::pwmbacklight::init(LCD_PIN_BACKLIGHT, 20000, LEDC_TIMER_1, LEDC_CHANNEL_0)) {
38+
tt::Logger("jc1060p470ciwy").warn("Failed to initialize backlight");
39+
}
40+
41+
auto touch = createTouch();
42+
43+
auto configuration = std::make_shared<EspLcdConfiguration>(EspLcdConfiguration {
44+
.horizontalResolution = LCD_HORIZONTAL_RESOLUTION,
45+
.verticalResolution = LCD_VERTICAL_RESOLUTION,
46+
.gapX = 0,
47+
.gapY = 0,
48+
.monochrome = false,
49+
.swapXY = false,
50+
.mirrorX = false,
51+
.mirrorY = false,
52+
.invertColor = false,
53+
.bufferSize = 0, // 0 = default (1/10 of screen)
54+
.touch = touch,
55+
.backlightDutyFunction = driver::pwmbacklight::setBacklightDuty,
56+
.resetPin = LCD_PIN_RESET,
57+
.lvglColorFormat = LV_COLOR_FORMAT_RGB565,
58+
.lvglSwapBytes = false,
59+
.rgbElementOrder = LCD_RGB_ELEMENT_ORDER_RGB,
60+
.bitsPerPixel = 16
61+
});
62+
63+
const auto display = std::make_shared<Jd9165Display>(configuration);
64+
return std::reinterpret_pointer_cast<tt::hal::display::DisplayDevice>(display);
65+
}
File renamed without changes.
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
#include "Jd9165Display.h"
2+
3+
#include <Tactility/Logger.h>
4+
5+
#include <esp_lcd_jd9165.h>
6+
7+
static const auto LOGGER = tt::Logger("JD9165");
8+
9+
// MIPI DSI PHY power configuration
10+
#define MIPI_DSI_PHY_PWR_LDO_CHAN 3 // LDO_VO3 connects to VDD_MIPI_DPHY
11+
#define MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV 2500
12+
13+
// JD9165 initialization commands from ESP32-P4 Function EV Board
14+
// Delays set to match the reference sequence exactly.
15+
static const jd9165_lcd_init_cmd_t jd9165_init_cmds[] = {
16+
{0x30, (uint8_t[]){0x00}, 1, 0},
17+
{0xF7, (uint8_t[]){0x49,0x61,0x02,0x00}, 4, 0},
18+
{0x30, (uint8_t[]){0x01}, 1, 0},
19+
{0x04, (uint8_t[]){0x0C}, 1, 0},
20+
{0x05, (uint8_t[]){0x00}, 1, 0},
21+
{0x06, (uint8_t[]){0x00}, 1, 0},
22+
{0x0B, (uint8_t[]){0x11}, 1, 0},
23+
{0x17, (uint8_t[]){0x00}, 1, 0},
24+
{0x20, (uint8_t[]){0x04}, 1, 0},
25+
{0x1F, (uint8_t[]){0x05}, 1, 0},
26+
{0x23, (uint8_t[]){0x00}, 1, 0},
27+
{0x25, (uint8_t[]){0x19}, 1, 0},
28+
{0x28, (uint8_t[]){0x18}, 1, 0},
29+
{0x29, (uint8_t[]){0x04}, 1, 0},
30+
{0x2A, (uint8_t[]){0x01}, 1, 0},
31+
{0x2B, (uint8_t[]){0x04}, 1, 0},
32+
{0x2C, (uint8_t[]){0x01}, 1, 0},
33+
{0x30, (uint8_t[]){0x02}, 1, 0},
34+
{0x01, (uint8_t[]){0x22}, 1, 0},
35+
{0x03, (uint8_t[]){0x12}, 1, 0},
36+
{0x04, (uint8_t[]){0x00}, 1, 0},
37+
{0x05, (uint8_t[]){0x64}, 1, 0},
38+
{0x0A, (uint8_t[]){0x08}, 1, 0},
39+
{0x0B, (uint8_t[]){0x0A,0x1A,0x0B,0x0D,0x0D,0x11,0x10,0x06,0x08,0x1F,0x1D}, 11, 0},
40+
{0x0C, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0},
41+
{0x0D, (uint8_t[]){0x16,0x1B,0x0B,0x0D,0x0D,0x11,0x10,0x07,0x09,0x1E,0x1C}, 11, 0},
42+
{0x0E, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0},
43+
{0x0F, (uint8_t[]){0x16,0x1B,0x0D,0x0B,0x0D,0x11,0x10,0x1C,0x1E,0x09,0x07}, 11, 0},
44+
{0x10, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0},
45+
{0x11, (uint8_t[]){0x0A,0x1A,0x0D,0x0B,0x0D,0x11,0x10,0x1D,0x1F,0x08,0x06}, 11, 0},
46+
{0x12, (uint8_t[]){0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D,0x0D}, 11, 0},
47+
{0x14, (uint8_t[]){0x00,0x00,0x11,0x11}, 4, 0},
48+
{0x18, (uint8_t[]){0x99}, 1, 0},
49+
{0x30, (uint8_t[]){0x06}, 1, 0},
50+
{0x12, (uint8_t[]){0x36,0x2C,0x2E,0x3C,0x38,0x35,0x35,0x32,0x2E,0x1D,0x2B,0x21,0x16,0x29}, 14, 0},
51+
{0x13, (uint8_t[]){0x36,0x2C,0x2E,0x3C,0x38,0x35,0x35,0x32,0x2E,0x1D,0x2B,0x21,0x16,0x29}, 14, 0},
52+
{0x30, (uint8_t[]){0x0A}, 1, 0},
53+
{0x02, (uint8_t[]){0x4F}, 1, 0},
54+
{0x0B, (uint8_t[]){0x40}, 1, 0},
55+
{0x12, (uint8_t[]){0x3E}, 1, 0},
56+
{0x13, (uint8_t[]){0x78}, 1, 0},
57+
{0x30, (uint8_t[]){0x0D}, 1, 0},
58+
{0x0D, (uint8_t[]){0x04}, 1, 0},
59+
{0x10, (uint8_t[]){0x0C}, 1, 0},
60+
{0x11, (uint8_t[]){0x0C}, 1, 0},
61+
{0x12, (uint8_t[]){0x0C}, 1, 0},
62+
{0x13, (uint8_t[]){0x0C}, 1, 0},
63+
{0x30, (uint8_t[]){0x00}, 1, 0},
64+
{0X3A, (uint8_t[]){0x55}, 1, 0},
65+
{0x11, (uint8_t[]){0x00}, 1, 120},
66+
{0x29, (uint8_t[]){0x00}, 1, 20},
67+
};
68+
69+
Jd9165Display::~Jd9165Display() {
70+
// TODO: This should happen during ::stop(), but this isn't currently exposed
71+
if (mipiDsiBus != nullptr) {
72+
esp_lcd_del_dsi_bus(mipiDsiBus);
73+
mipiDsiBus = nullptr;
74+
}
75+
if (ldoChannel != nullptr) {
76+
esp_ldo_release_channel(ldoChannel);
77+
ldoChannel = nullptr;
78+
}
79+
}
80+
81+
bool Jd9165Display::createMipiDsiBus() {
82+
// Enable MIPI DSI PHY power (transition from "no power" to "shutdown" state)
83+
esp_ldo_channel_config_t ldo_mipi_phy_config = {
84+
.chan_id = MIPI_DSI_PHY_PWR_LDO_CHAN,
85+
.voltage_mv = MIPI_DSI_PHY_PWR_LDO_VOLTAGE_MV,
86+
.flags = {}
87+
};
88+
89+
if (esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldoChannel) != ESP_OK) {
90+
LOGGER.error("Failed to acquire LDO channel for MIPI DSI PHY");
91+
return false;
92+
}
93+
94+
LOGGER.info("MIPI DSI PHY powered on");
95+
96+
// Create MIPI DSI bus
97+
// TODO: use MIPI_DSI_PHY_CLK_SRC_DEFAULT() in future ESP-IDF 6.0.0 update with esp_lcd_jd9165 library version 2.x
98+
const esp_lcd_dsi_bus_config_t bus_config = {
99+
.bus_id = 0,
100+
.num_data_lanes = 2,
101+
.phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT,
102+
.lane_bit_rate_mbps = 750
103+
};
104+
105+
if (esp_lcd_new_dsi_bus(&bus_config, &mipiDsiBus) != ESP_OK) {
106+
LOGGER.error("Failed to create MIPI DSI bus");
107+
return false;
108+
}
109+
110+
LOGGER.info("MIPI DSI bus created");
111+
return true;
112+
}
113+
114+
bool Jd9165Display::createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) {
115+
// Initialize MIPI DSI bus if not already done
116+
if (mipiDsiBus == nullptr) {
117+
if (!createMipiDsiBus()) {
118+
return false;
119+
}
120+
}
121+
122+
// Use DBI interface to send LCD commands and parameters
123+
esp_lcd_dbi_io_config_t dbi_config = JD9165_PANEL_IO_DBI_CONFIG();
124+
125+
if (esp_lcd_new_panel_io_dbi(mipiDsiBus, &dbi_config, &ioHandle) != ESP_OK) {
126+
LOGGER.error("Failed to create panel IO");
127+
return false;
128+
}
129+
130+
return true;
131+
}
132+
133+
esp_lcd_panel_dev_config_t Jd9165Display::createPanelConfig(std::shared_ptr<EspLcdConfiguration> espLcdConfiguration, gpio_num_t resetPin) {
134+
return {
135+
.reset_gpio_num = resetPin,
136+
.rgb_ele_order = espLcdConfiguration->rgbElementOrder,
137+
.data_endian = LCD_RGB_DATA_ENDIAN_LITTLE,
138+
.bits_per_pixel = static_cast<uint8_t>(espLcdConfiguration->bitsPerPixel),
139+
.flags = {
140+
.reset_active_high = 0
141+
},
142+
.vendor_config = nullptr // Will be set in createPanelHandle
143+
};
144+
}
145+
146+
bool Jd9165Display::createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) {
147+
// Create DPI panel configuration
148+
// Override default timings
149+
const esp_lcd_dpi_panel_config_t dpi_config = {
150+
.virtual_channel = 0,
151+
.dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT,
152+
.dpi_clock_freq_mhz = 50,
153+
.pixel_format = LCD_COLOR_PIXEL_FORMAT_RGB565,
154+
.in_color_format = LCD_COLOR_FMT_RGB565,
155+
.out_color_format = LCD_COLOR_FMT_RGB565,
156+
.num_fbs = 1,
157+
.video_timing = {
158+
.h_size = 1024,
159+
.v_size = 600,
160+
.hsync_pulse_width = 20,
161+
.hsync_back_porch = 160,
162+
.hsync_front_porch = 160,
163+
.vsync_pulse_width = 2,
164+
.vsync_back_porch = 21,
165+
.vsync_front_porch = 12,
166+
},
167+
.flags = {
168+
.use_dma2d = 1,
169+
.disable_lp = 0
170+
}
171+
};
172+
173+
jd9165_vendor_config_t vendor_config = {
174+
.init_cmds = jd9165_init_cmds,
175+
.init_cmds_size = sizeof(jd9165_init_cmds) / sizeof(jd9165_lcd_init_cmd_t),
176+
.mipi_config = {
177+
.dsi_bus = mipiDsiBus,
178+
.dpi_config = &dpi_config,
179+
},
180+
};
181+
182+
// Create a mutable copy of panelConfig to set vendor_config
183+
esp_lcd_panel_dev_config_t mutable_panel_config = panelConfig;
184+
mutable_panel_config.vendor_config = &vendor_config;
185+
186+
if (esp_lcd_new_panel_jd9165(ioHandle, &mutable_panel_config, &panelHandle) != ESP_OK) {
187+
LOGGER.error("Failed to create panel");
188+
return false;
189+
}
190+
191+
LOGGER.info("JD9165 panel created successfully");
192+
// Defer reset/init to base class applyConfiguration to avoid double initialization
193+
return true;
194+
}
195+
196+
lvgl_port_display_dsi_cfg_t Jd9165Display::getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) {
197+
// Disable avoid_tearing to prevent stalls/blank flashes when other tasks (e.g. flash writes) block timing
198+
return lvgl_port_display_dsi_cfg_t{
199+
.flags = {
200+
.avoid_tearing = 0,
201+
},
202+
};
203+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#pragma once
2+
3+
#include <EspLcdDisplayV2.h>
4+
#include <Tactility/RecursiveMutex.h>
5+
6+
#include <esp_lcd_mipi_dsi.h>
7+
#include <esp_ldo_regulator.h>
8+
9+
class Jd9165Display final : public EspLcdDisplayV2 {
10+
11+
class NoLock final : public tt::Lock {
12+
bool lock(TickType_t timeout) const override { return true; }
13+
void unlock() const override { /* NO-OP */ }
14+
};
15+
16+
esp_lcd_dsi_bus_handle_t mipiDsiBus = nullptr;
17+
esp_ldo_channel_handle_t ldoChannel = nullptr;
18+
19+
bool createMipiDsiBus();
20+
21+
protected:
22+
23+
bool createIoHandle(esp_lcd_panel_io_handle_t& ioHandle) override;
24+
25+
esp_lcd_panel_dev_config_t createPanelConfig(std::shared_ptr<EspLcdConfiguration> espLcdConfiguration, gpio_num_t resetPin) override;
26+
27+
bool createPanelHandle(esp_lcd_panel_io_handle_t ioHandle, const esp_lcd_panel_dev_config_t& panelConfig, esp_lcd_panel_handle_t& panelHandle) override;
28+
29+
bool useDsiPanel() const override { return true; }
30+
31+
lvgl_port_display_dsi_cfg_t getLvglPortDisplayDsiConfig(esp_lcd_panel_io_handle_t /*ioHandle*/, esp_lcd_panel_handle_t /*panelHandle*/) override;
32+
33+
public:
34+
35+
Jd9165Display(
36+
const std::shared_ptr<EspLcdConfiguration>& configuration
37+
) : EspLcdDisplayV2(configuration, std::make_shared<NoLock>()) {}
38+
39+
~Jd9165Display() override;
40+
41+
std::string getName() const override { return "JD9165"; }
42+
43+
std::string getDescription() const override { return "JD9165 MIPI-DSI 1024x600 display"; }
44+
};

0 commit comments

Comments
 (0)