Skip to content

Commit 129b5d2

Browse files
committed
WIP LovyanGFX
1 parent da405d4 commit 129b5d2

File tree

6 files changed

+104
-45
lines changed

6 files changed

+104
-45
lines changed

.claude/settings.local.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
"permissions": {
33
"allow": [
44
"Bash(pio)",
5-
"Bash(pio run)"
5+
"Bash(pio run)",
6+
"WebSearch",
7+
"Bash(pio run:*)",
8+
"WebFetch(domain:github.com)"
69
],
710
"deny": []
811
}

inc/sp140/lvgl/lvgl_core.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
#define LVGL_CORE_H
33

44
#include <lvgl.h>
5-
#include <Adafruit_ST7735.h>
5+
#define LGFX_ESP32_S3
6+
#include <LovyanGFX.hpp>
67
#include "../structs.h"
78
// FreeRTOS for mutex used to guard shared SPI bus
89
#include <freertos/FreeRTOS.h>
@@ -27,7 +28,7 @@ extern lv_disp_drv_t disp_drv;
2728
extern lv_disp_draw_buf_t draw_buf;
2829
extern lv_color_t buf[LVGL_BUFFER_SIZE];
2930
extern lv_color_t buf2[LVGL_BUFFER_SIZE]; // Second buffer for double buffering
30-
extern Adafruit_ST7735* tft_driver;
31+
extern lgfx::LGFX_Device* tft_driver;
3132
extern uint32_t lvgl_last_update;
3233
// Shared SPI bus mutex (guards TFT + MCP2515 access)
3334
extern SemaphoreHandle_t spiBusMutex;
@@ -40,4 +41,7 @@ void lv_tick_handler();
4041
void updateLvgl();
4142
void displayLvglSplash(const STR_DEVICE_DATA_140_V1& deviceData, int duration);
4243

44+
// Shared SPI helper functions
45+
SPIClass* getSharedSPI(); // Get shared SPI instance for other devices
46+
4347
#endif // LVGL_CORE_H

platformio.ini

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ lib_deps =
4747
Time@1.6.1
4848
adafruit/Adafruit BusIO@1.17.2
4949
adafruit/Adafruit BMP3XX Library@2.1.6
50-
adafruit/Adafruit ST7735 and ST7789 Library@1.11.0
50+
lovyan03/LovyanGFX@^1.1.16
5151
adafruit/Adafruit NeoPixel@1.15.1
5252
adafruit/Adafruit CAN@0.2.1
5353
adafruit/Adafruit MCP2515@0.2.1

src/sp140/bms.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,17 @@ void updateBMSData() {
2222
if (bms_can == nullptr || !bmsCanInitialized) return;
2323

2424
// TODO track bms incrementing cycle count
25-
// Ensure display CS is deselected and BMS CS is selected
26-
digitalWrite(displayCS, HIGH);
25+
2726
// Take the shared SPI mutex to prevent contention with TFT flush
2827
if (spiBusMutex != NULL) {
2928
xSemaphoreTake(spiBusMutex, portMAX_DELAY);
3029
}
30+
31+
// Begin SPI transaction for MCP2515 (adjust settings as needed for your MCP2515)
32+
SPIClass* spi = getSharedSPI();
33+
if (spi) {
34+
spi->beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); // 10MHz, Mode 0 for MCP2515
35+
}
3136
digitalWrite(bmsCS, LOW);
3237

3338
// USBSerial.println("Updating BMS Data");
@@ -83,8 +88,12 @@ void updateBMSData() {
8388
}
8489
// printBMSData();
8590

86-
// Deselect BMS CS when done and release mutex
91+
// End SPI transaction and cleanup
8792
digitalWrite(bmsCS, HIGH);
93+
if (spi) {
94+
spi->endTransaction();
95+
}
96+
8897
if (spiBusMutex != NULL) {
8998
xSemaphoreGive(spiBusMutex);
9099
}

src/sp140/lvgl/lvgl_core.cpp

Lines changed: 78 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,57 @@ lv_disp_drv_t disp_drv;
88
lv_disp_draw_buf_t draw_buf;
99
lv_color_t buf[LVGL_BUFFER_SIZE];
1010
lv_color_t buf2[LVGL_BUFFER_SIZE]; // Second buffer for double buffering
11-
Adafruit_ST7735* tft_driver = nullptr;
11+
lgfx::LGFX_Device* tft_driver = nullptr;
12+
extern SPIClass* hardwareSPI; // External reference to shared SPI instance
13+
14+
// Custom LovyanGFX configuration for ST7735
15+
class LGFX_ST7735 : public lgfx::LGFX_Device {
16+
lgfx::Panel_ST7735S _panel_instance;
17+
lgfx::Bus_SPI _bus_instance;
18+
19+
public:
20+
LGFX_ST7735() {
21+
{
22+
auto cfg = _bus_instance.config();
23+
cfg.spi_host = SPI2_HOST; // Use SPI2 (HSPI)
24+
cfg.spi_mode = 0;
25+
cfg.freq_write = 27000000; // SPI speed for writing
26+
cfg.freq_read = 16000000; // SPI speed for reading
27+
cfg.spi_3wire = false;
28+
cfg.use_lock = true;
29+
cfg.dma_channel = SPI_DMA_CH_AUTO;
30+
cfg.pin_sclk = 12;
31+
cfg.pin_mosi = 11;
32+
cfg.pin_miso = 13;
33+
cfg.pin_dc = 14;
34+
_bus_instance.config(cfg);
35+
_panel_instance.setBus(&_bus_instance);
36+
}
37+
{
38+
auto cfg = _panel_instance.config();
39+
cfg.pin_cs = 10;
40+
cfg.pin_rst = 15;
41+
cfg.pin_busy = -1;
42+
cfg.memory_width = 160;
43+
cfg.memory_height = 128;
44+
cfg.panel_width = 160;
45+
cfg.panel_height = 128;
46+
// ST7735 BLACKTAB variant - specific settings for 160x128 display
47+
cfg.offset_x = 0;
48+
cfg.offset_y = 0;
49+
cfg.offset_rotation = 0;
50+
cfg.dummy_read_pixel = 8;
51+
cfg.dummy_read_bits = 1;
52+
cfg.readable = false;
53+
cfg.invert = false; // User reported darker display, so no invert needed
54+
cfg.rgb_order = false; // Try RGB order instead of BGR
55+
cfg.dlen_16bit = false;
56+
cfg.bus_shared = true; // Important for shared SPI
57+
_panel_instance.config(cfg);
58+
}
59+
setPanel(&_panel_instance);
60+
}
61+
};
1262
uint32_t lvgl_last_update = 0;
1363
// Define the shared SPI bus mutex
1464
SemaphoreHandle_t spiBusMutex = NULL;
@@ -31,6 +81,7 @@ void setupLvglDisplay(
3181
int8_t rst_pin,
3282
SPIClass* spi
3383
) {
84+
// Note: TFT_eSPI doesn't use the spi parameter - it's configured via build flags
3485
USBSerial.println("Setting up LVGL display");
3586

3687
// Create SPI bus mutex on first use if not already created
@@ -41,18 +92,26 @@ void setupLvglDisplay(
4192
}
4293
}
4394

44-
// Create the TFT driver instance if not already created
95+
// Create the LovyanGFX driver instance if not already created
4596
if (tft_driver == nullptr) {
46-
tft_driver = new Adafruit_ST7735(spi, displayCS, dc_pin, rst_pin);
47-
48-
// Initialize the display
49-
tft_driver->initR(INITR_BLACKTAB);
50-
tft_driver->setRotation(deviceData.screen_rotation);
97+
// Store the shared SPI instance
98+
hardwareSPI = spi;
5199

52-
// Optimize SPI speed - limited by MCP2515 max of 10MHz on shared bus
53-
tft_driver->setSPISpeed(10000000); // 10MHz - safe for both ST7735 and MCP2515
100+
// Create custom ST7735 configuration for LovyanGFX
101+
tft_driver = new LGFX_ST7735();
54102

55-
tft_driver->fillScreen(ST77XX_BLACK);
103+
// Initialize display with custom configuration
104+
if (tft_driver->init()) {
105+
tft_driver->setRotation(deviceData.screen_rotation);
106+
107+
// Clear screen with a test pattern to verify it's working
108+
tft_driver->fillScreen(0x0000); // Black
109+
tft_driver->fillRect(10, 10, 50, 50, 0xF800); // Red square for testing
110+
111+
USBSerial.println("LovyanGFX ST7735 initialized successfully");
112+
} else {
113+
USBSerial.println("ERROR: LovyanGFX ST7735 initialization failed!");
114+
}
56115
}
57116

58117
// Initialize LVGL buffer
@@ -81,40 +140,22 @@ void setupLvglDisplay(
81140
lv_disp_set_theme(lv_disp_get_default(), theme);
82141
}
83142

84-
// Optimized flush callback to minimize tearing and improve performance
85-
// CS pin management is handled here where actual SPI communication occurs
143+
// High-performance flush callback using LovyanGFX with DMA
86144
void lvgl_flush_cb(lv_disp_drv_t* disp, const lv_area_t* area, lv_color_t* color_p) {
87145
uint32_t w = (area->x2 - area->x1 + 1);
88146
uint32_t h = (area->y2 - area->y1 + 1);
89-
uint32_t len = w * h;
90147

91-
// Guard shared SPI bus for display flush
148+
// LovyanGFX handles SPI transactions internally, but we still guard for MCP2515
92149
if (spiBusMutex != NULL) {
93150
xSemaphoreTake(spiBusMutex, portMAX_DELAY);
94151
}
95152

96-
// Disable interrupts during critical display update to prevent tearing
97-
portDISABLE_INTERRUPTS();
98-
99-
// Make sure display CS is selected
100-
digitalWrite(displayCS, LOW);
101-
102-
// Start optimized write sequence
153+
// LovyanGFX DMA-optimized pixel transfer
103154
tft_driver->startWrite();
104155
tft_driver->setAddrWindow(area->x1, area->y1, w, h);
105-
106-
// Push colors using DMA for optimal performance
107-
tft_driver->writePixels((uint16_t*)color_p, len); // NOLINT(readability/casting)
108-
109-
// Complete write sequence
156+
tft_driver->writePixels((uint16_t*)color_p, w * h); // NOLINT(readability/casting)
110157
tft_driver->endWrite();
111158

112-
// Deselect display CS when done
113-
digitalWrite(displayCS, HIGH);
114-
115-
// Re-enable interrupts
116-
portENABLE_INTERRUPTS();
117-
118159
if (spiBusMutex != NULL) {
119160
xSemaphoreGive(spiBusMutex);
120161
}
@@ -134,7 +175,11 @@ void lv_tick_handler() {
134175
}
135176
}
136177

137-
// Update LVGL - call this regularly
178+
// Shared SPI helper function
179+
SPIClass* getSharedSPI() {
180+
return hardwareSPI;
181+
}
182+
138183
void updateLvgl() {
139184
uint32_t current_ms = millis();
140185

src/sp140/sp140.ino

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -632,17 +632,15 @@ void setup() {
632632
// First initialize the shared SPI bus
633633
setupSPI(board_config);
634634

635-
// Then setup the display - use LVGL display instead of the old one
636-
// setupDisplay(deviceData, board_config, hardwareSPI);
637-
// Pass hardcoded pin values for DC and RST
635+
// Setup Adafruit_ST7735 display with shared SPI
638636
setupLvglDisplay(deviceData, board_config.tft_dc, board_config.tft_rst, hardwareSPI);
639637

640638
// Initialise alert display aggregation & UI
641639
initAlertDisplay();
642640

643641
#ifndef SCREEN_DEBUG
644-
// Pass the hardware SPI instance to the BMS_CAN initialization
645-
initBMSCAN(hardwareSPI);
642+
// Use shared SPI instance for BMS CAN
643+
initBMSCAN(getSharedSPI());
646644
#endif
647645

648646
initESC();

0 commit comments

Comments
 (0)