display and gem lgic seperate cpu cores, audio fixed, display scaling implemented, psram aktivatet for threads in core
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
idf_component_register(
|
||||
SRCS
|
||||
"st7789.c"
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
REQUIRES
|
||||
driver
|
||||
spi_flash
|
||||
SRCS "st7789.c"
|
||||
INCLUDE_DIRS "include" "${CMAKE_SOURCE_DIR}/main/include"
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
REQUIRES driver esp_timer spi_flash
|
||||
)
|
||||
|
||||
@@ -48,9 +48,20 @@ void st7789_draw_pixel(int16_t x, int16_t y, uint16_t color);
|
||||
* @param width Width of buffer
|
||||
* @param height Height of buffer
|
||||
*/
|
||||
void st7789_draw_buffer(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
void st7789_draw_buffer(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
int16_t width, int16_t height);
|
||||
|
||||
/**
|
||||
* @brief Draw buffer that is already byte-swapped (optimized, no allocation)
|
||||
* @param buffer Pointer to pre-swapped BGR565 framebuffer
|
||||
* @param x X start position
|
||||
* @param y Y start position
|
||||
* @param width Width of buffer
|
||||
* @param height Height of buffer
|
||||
*/
|
||||
void st7789_draw_buffer_preswapped(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
int16_t width, int16_t height);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+50
-84
@@ -1,12 +1,6 @@
|
||||
/**
|
||||
* @file st7789.c
|
||||
* @brief ST7789 Display Driver Implementation - COMPLETE!
|
||||
*
|
||||
* Full implementation with:
|
||||
* - Complete initialization sequence
|
||||
* - Fast DMA transfers
|
||||
* - Framebuffer rendering
|
||||
* - Backlight PWM control
|
||||
* @brief ST7789 Display Driver - 270° Rotation (USB left)
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -53,12 +47,9 @@ static spi_device_handle_t spi_handle = NULL;
|
||||
#define MADCTL_BGR 0x08
|
||||
#define MADCTL_MH 0x04
|
||||
|
||||
/**
|
||||
* @brief Send command to ST7789
|
||||
*/
|
||||
static void st7789_send_cmd(uint8_t cmd)
|
||||
{
|
||||
gpio_set_level(LCD_PIN_DC, 0); // Command mode
|
||||
gpio_set_level(LCD_PIN_DC, 0);
|
||||
spi_transaction_t t = {
|
||||
.length = 8,
|
||||
.tx_buffer = &cmd,
|
||||
@@ -68,12 +59,9 @@ static void st7789_send_cmd(uint8_t cmd)
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_handle, &t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send data byte to ST7789
|
||||
*/
|
||||
static void st7789_send_data(uint8_t data)
|
||||
{
|
||||
gpio_set_level(LCD_PIN_DC, 1); // Data mode
|
||||
gpio_set_level(LCD_PIN_DC, 1);
|
||||
spi_transaction_t t = {
|
||||
.length = 8,
|
||||
.tx_buffer = &data,
|
||||
@@ -83,14 +71,10 @@ static void st7789_send_data(uint8_t data)
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_handle, &t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send data buffer to ST7789
|
||||
*/
|
||||
static void st7789_send_data_buf(const uint8_t *data, size_t len)
|
||||
{
|
||||
if (len == 0) return;
|
||||
|
||||
gpio_set_level(LCD_PIN_DC, 1); // Data mode
|
||||
gpio_set_level(LCD_PIN_DC, 1);
|
||||
spi_transaction_t t = {
|
||||
.length = len * 8,
|
||||
.tx_buffer = data
|
||||
@@ -98,33 +82,23 @@ static void st7789_send_data_buf(const uint8_t *data, size_t len)
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_handle, &t));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set address window for drawing
|
||||
*/
|
||||
static void st7789_set_address_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
|
||||
{
|
||||
// Column address set
|
||||
st7789_send_cmd(ST7789_CASET);
|
||||
st7789_send_data(x0 >> 8);
|
||||
st7789_send_data(x0 & 0xFF);
|
||||
st7789_send_data(x1 >> 8);
|
||||
st7789_send_data(x1 & 0xFF);
|
||||
|
||||
// Row address set
|
||||
st7789_send_cmd(ST7789_RASET);
|
||||
st7789_send_data(y0 >> 8);
|
||||
st7789_send_data(y0 & 0xFF);
|
||||
st7789_send_data(y1 >> 8);
|
||||
st7789_send_data(y1 & 0xFF);
|
||||
|
||||
// Write to RAM
|
||||
st7789_send_cmd(ST7789_RAMWR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize backlight PWM
|
||||
*/
|
||||
static void st7789_backlight_init(void)
|
||||
{
|
||||
ledc_timer_config_t timer_conf = {
|
||||
@@ -151,7 +125,6 @@ esp_err_t st7789_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Initializing ST7789 display...");
|
||||
|
||||
// Configure GPIO pins
|
||||
gpio_config_t io_conf = {};
|
||||
io_conf.pin_bit_mask = (1ULL << LCD_PIN_DC) | (1ULL << LCD_PIN_RST);
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
@@ -159,7 +132,6 @@ esp_err_t st7789_init(void)
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// Configure SPI bus
|
||||
spi_bus_config_t buscfg = {
|
||||
.mosi_io_num = LCD_PIN_MOSI,
|
||||
.miso_io_num = LCD_PIN_MISO,
|
||||
@@ -167,10 +139,10 @@ esp_err_t st7789_init(void)
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = LCD_WIDTH * LCD_HEIGHT * 2 + 8,
|
||||
.flags = SPICOMMON_BUSFLAG_MASTER,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(LCD_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
// Configure SPI device
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.clock_speed_hz = LCD_PIXEL_CLOCK_HZ,
|
||||
.mode = 0,
|
||||
@@ -180,63 +152,41 @@ esp_err_t st7789_init(void)
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(LCD_SPI_HOST, &devcfg, &spi_handle));
|
||||
|
||||
// Initialize backlight
|
||||
st7789_backlight_init();
|
||||
st7789_set_backlight(0); // Start with backlight off
|
||||
st7789_set_backlight(0);
|
||||
|
||||
// Hardware reset
|
||||
gpio_set_level(LCD_PIN_RST, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
gpio_set_level(LCD_PIN_RST, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// ============================================
|
||||
// ST7789 Initialization Sequence
|
||||
// ============================================
|
||||
|
||||
// Software reset
|
||||
st7789_send_cmd(ST7789_SWRESET);
|
||||
vTaskDelay(pdMS_TO_TICKS(150));
|
||||
|
||||
// Out of sleep mode
|
||||
st7789_send_cmd(ST7789_SLPOUT);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
// Color mode: 16-bit/pixel (RGB565)
|
||||
st7789_send_cmd(ST7789_COLMOD);
|
||||
st7789_send_data(0x55); // 16-bit
|
||||
st7789_send_data(0x55);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
// Memory access control (rotation, RGB/BGR)
|
||||
// MADCTL: 270° = 90° CCW = USB on LEFT side
|
||||
// MV=1 (Row/Column exchange) + MY=1 (Mirror Y)
|
||||
st7789_send_cmd(ST7789_MADCTL);
|
||||
#if LCD_ROTATION == 0
|
||||
st7789_send_data(MADCTL_MX | MADCTL_MY | MADCTL_RGB);
|
||||
#elif LCD_ROTATION == 1
|
||||
st7789_send_data(MADCTL_MY | MADCTL_MV | MADCTL_RGB);
|
||||
#elif LCD_ROTATION == 2
|
||||
st7789_send_data(MADCTL_RGB);
|
||||
#elif LCD_ROTATION == 3
|
||||
st7789_send_data(MADCTL_MX | MADCTL_MV | MADCTL_RGB);
|
||||
#endif
|
||||
st7789_send_data(MADCTL_MV | MADCTL_MY | MADCTL_RGB);
|
||||
|
||||
// Inversion mode on
|
||||
st7789_send_cmd(ST7789_INVON);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
// Normal display mode on
|
||||
st7789_send_cmd(ST7789_NORON);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
// Display on
|
||||
st7789_send_cmd(ST7789_DISPON);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
ESP_LOGI(TAG, "✓ ST7789 initialized (%dx%d)", LCD_WIDTH, LCD_HEIGHT);
|
||||
ESP_LOGI(TAG, "✓ ST7789 initialized (%dx%d - 270° rotated, USB left)", LCD_WIDTH, LCD_HEIGHT);
|
||||
|
||||
// Set default backlight
|
||||
st7789_set_backlight(LCD_BCKL_DEFAULT);
|
||||
|
||||
// Clear screen to black
|
||||
st7789_fill_screen(0x0000);
|
||||
|
||||
return ESP_OK;
|
||||
@@ -252,20 +202,14 @@ void st7789_set_backlight(uint8_t brightness)
|
||||
|
||||
void st7789_fill_screen(uint16_t color)
|
||||
{
|
||||
ESP_LOGD(TAG, "Filling screen with color 0x%04X", color);
|
||||
|
||||
// Set full screen window
|
||||
st7789_set_address_window(0, 0, LCD_WIDTH - 1, LCD_HEIGHT - 1);
|
||||
|
||||
// Prepare color buffer (1 line)
|
||||
uint16_t line_buf[LCD_WIDTH];
|
||||
for (int i = 0; i < LCD_WIDTH; i++) {
|
||||
// Convert to big-endian for ST7789
|
||||
line_buf[i] = (color >> 8) | (color << 8);
|
||||
}
|
||||
|
||||
// Send line by line
|
||||
gpio_set_level(LCD_PIN_DC, 1); // Data mode
|
||||
gpio_set_level(LCD_PIN_DC, 1);
|
||||
for (int y = 0; y < LCD_HEIGHT; y++) {
|
||||
spi_transaction_t t = {
|
||||
.length = LCD_WIDTH * 16,
|
||||
@@ -277,16 +221,13 @@ void st7789_fill_screen(uint16_t color)
|
||||
|
||||
void st7789_draw_pixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if (x < 0 || x >= LCD_WIDTH || y < 0 || y >= LCD_HEIGHT) {
|
||||
return; // Out of bounds
|
||||
}
|
||||
if (x < 0 || x >= LCD_WIDTH || y < 0 || y >= LCD_HEIGHT) return;
|
||||
|
||||
st7789_set_address_window(x, y, x, y);
|
||||
|
||||
// Convert to big-endian
|
||||
uint8_t data[2] = {color >> 8, color & 0xFF};
|
||||
|
||||
gpio_set_level(LCD_PIN_DC, 1); // Data mode
|
||||
gpio_set_level(LCD_PIN_DC, 1);
|
||||
spi_transaction_t t = {
|
||||
.length = 16,
|
||||
.tx_buffer = data
|
||||
@@ -297,22 +238,15 @@ void st7789_draw_pixel(int16_t x, int16_t y, uint16_t color)
|
||||
void st7789_draw_buffer(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
int16_t width, int16_t height)
|
||||
{
|
||||
if (buffer == NULL || width <= 0 || height <= 0) {
|
||||
return;
|
||||
}
|
||||
if (buffer == NULL || width <= 0 || height <= 0) return;
|
||||
|
||||
// Bounds checking
|
||||
if (x < 0 || y < 0 || x + width > LCD_WIDTH || y + height > LCD_HEIGHT) {
|
||||
ESP_LOGW(TAG, "Buffer out of bounds: (%d,%d) %dx%d", x, y, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Drawing buffer at (%d,%d) size %dx%d", x, y, width, height);
|
||||
|
||||
// Set drawing window
|
||||
st7789_set_address_window(x, y, x + width - 1, y + height - 1);
|
||||
|
||||
// Prepare buffer with byte-swapped colors (ST7789 is big-endian)
|
||||
size_t buf_size = width * height;
|
||||
uint16_t *swap_buf = heap_caps_malloc(buf_size * 2, MALLOC_CAP_DMA);
|
||||
if (swap_buf == NULL) {
|
||||
@@ -320,13 +254,11 @@ void st7789_draw_buffer(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap bytes for ST7789
|
||||
for (size_t i = 0; i < buf_size; i++) {
|
||||
swap_buf[i] = (buffer[i] >> 8) | (buffer[i] << 8);
|
||||
}
|
||||
|
||||
// Send via DMA
|
||||
gpio_set_level(LCD_PIN_DC, 1); // Data mode
|
||||
gpio_set_level(LCD_PIN_DC, 1);
|
||||
spi_transaction_t t = {
|
||||
.length = buf_size * 16,
|
||||
.tx_buffer = swap_buf
|
||||
@@ -336,3 +268,37 @@ void st7789_draw_buffer(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
heap_caps_free(swap_buf);
|
||||
}
|
||||
|
||||
void st7789_draw_buffer_preswapped(const uint16_t *buffer, int16_t x, int16_t y,
|
||||
int16_t width, int16_t height)
|
||||
{
|
||||
if (buffer == NULL || width <= 0 || height <= 0) return;
|
||||
|
||||
if (x < 0 || y < 0 || x + width > LCD_WIDTH || y + height > LCD_HEIGHT) {
|
||||
ESP_LOGW(TAG, "Buffer out of bounds: (%d,%d) %dx%d", x, y, width, height);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set address window once for entire region
|
||||
st7789_set_address_window(x, y, x + width - 1, y + height - 1);
|
||||
|
||||
gpio_set_level(LCD_PIN_DC, 1);
|
||||
|
||||
// Split into DMA-safe chunks (max 32KB per transfer to be safe)
|
||||
// SPI will auto-split into smaller DMA descriptors internally
|
||||
const size_t max_chunk_size = 32768; // 32KB in bytes
|
||||
size_t total_bytes = width * height * 2;
|
||||
size_t offset = 0;
|
||||
|
||||
while (offset < total_bytes) {
|
||||
size_t chunk_size = (total_bytes - offset > max_chunk_size) ?
|
||||
max_chunk_size : (total_bytes - offset);
|
||||
|
||||
spi_transaction_t t = {
|
||||
.length = chunk_size * 8, // in bits
|
||||
.tx_buffer = (uint8_t*)buffer + offset
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_device_polling_transmit(spi_handle, &t));
|
||||
|
||||
offset += chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user