diff --git a/components/badge23/CMakeLists.txt b/components/badge23/CMakeLists.txt index 732edf14ee0793c536e049c1b9f274f0de538408..65959cc07b0844519af076d17349682758e801bc 100644 --- a/components/badge23/CMakeLists.txt +++ b/components/badge23/CMakeLists.txt @@ -13,6 +13,6 @@ idf_component_register( include REQUIRES badge23_hwconfig - gc9a01 + flow3r_bsp espressif__led_strip ) diff --git a/components/badge23/display.c b/components/badge23/display.c index 86b88cf63969ea495a3debeed450ff0a6f288660..92d234956b730875a4a8dac5691f80ea51d5b608 100644 --- a/components/badge23/display.c +++ b/components/badge23/display.c @@ -1,58 +1,83 @@ #include "badge23/display.h" -#include "gc9a01.h" -#include "esp_log.h" -#include <freertos/FreeRTOS.h> -#include <freertos/task.h> -#include <freertos/timers.h> -#include <freertos/queue.h> #include <stdio.h> #include <string.h> #include <math.h> +#include "esp_log.h" #include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + #include "../../usermodule/uctx/uctx/ctx.h" -volatile Ctx *the_ctx = NULL; +#include "flow3r_bsp.h" +static Ctx *the_ctx = NULL; +static volatile bool initialized = false; +static DMA_ATTR uint16_t ctx_framebuffer[FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT]; void display_ctx_init() { the_ctx = ctx_new_for_framebuffer( - ScreenBuff, - GC9A01_Width, - GC9A01_Height, - GC9A01_Width * 2, + ctx_framebuffer, + FLOW3R_BSP_DISPLAY_WIDTH, + FLOW3R_BSP_DISPLAY_HEIGHT, + FLOW3R_BSP_DISPLAY_WIDTH * 2, CTX_FORMAT_RGB565_BYTESWAPPED ); + int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2; + int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2; // rotate by 180 deg and translate x and y by 120 px to have (0,0) at the center of the screen - ctx_apply_transform(the_ctx,-1,0,120,0,-1,120,0,0,1); + ctx_apply_transform(the_ctx,-1,0,offset_x,0,-1,offset_y,0,0,1); } -void display_update(){ - GC9A01_Update(); -} +static void display_loading_splash(void) { + ctx_rgb(the_ctx, 0.157, 0.129, 0.167); + ctx_rectangle(the_ctx, -120, -120, 240, 240); + ctx_fill(the_ctx); + + ctx_move_to(the_ctx, 0, 0); + ctx_rgb(the_ctx, 0.9, 0.9, 0.9); + ctx_text_align(the_ctx, CTX_TEXT_ALIGN_CENTER); + ctx_text_baseline(the_ctx, CTX_TEXT_BASELINE_ALPHABETIC); + ctx_text(the_ctx, "Loading..."); -void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col){ - GC9A01_DrawPixel(x, y, col); + flow3r_bsp_display_send_fb(ctx_framebuffer); } -uint16_t display_get_pixel(uint8_t x, uint8_t y){ - return GC9A01_GetPixel(x,y); -} +void display_init() { + flow3r_bsp_display_init(); + display_ctx_init(); + display_loading_splash(); + // Delay turning on backlight, otherwise we get a flash of some old + // buffer..? Is the display RAMWR not synchronous..? + vTaskDelay(100 / portTICK_PERIOD_MS); + flow3r_bsp_display_set_backlight(100); + + memset(ctx_framebuffer, 0, FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT * 2); -void display_fill(uint16_t col){ - GC9A01_FillRect(0, 0, 240, 240, col); + initialized = true; } -void display_set_backlight(uint8_t percent) { - GC9A01_SetBL(percent); +void display_update(){ + if (!initialized) { + return; + } + flow3r_bsp_display_send_fb(ctx_framebuffer); } -void display_init() { - GC9A01_Init(); - GC9A01_Update(); - display_ctx_init(); +void display_set_backlight(uint8_t percent) { + if (!initialized) { + return; + } + flow3r_bsp_display_set_backlight(percent); } +Ctx *display_global_ctx(void) { + if (!initialized) { + return NULL; + } + return the_ctx; +} \ No newline at end of file diff --git a/components/badge23/espan.c b/components/badge23/espan.c index e9884458eee72a5fe2a0f019e2860f0a9e5adeee..9b6d75d4bd166be263ac5587f4517d795b7b2b02 100644 --- a/components/badge23/espan.c +++ b/components/badge23/espan.c @@ -93,6 +93,9 @@ void locks_init(){ void os_app_main(void) { + // Initialize display first as that gives us a nice splash screen. + display_init(); + locks_init(); ESP_LOGI(TAG, "Starting on %s...", badge23_hw_name); ESP_ERROR_CHECK(i2c_master_init()); @@ -106,7 +109,6 @@ void os_app_main(void) captouch_force_calibration(); - display_init(); i2c_queue = xQueueCreate(1,1); diff --git a/components/badge23/include/badge23/display.h b/components/badge23/include/badge23/display.h index d6a7e9faff1832ad51bb7df6dd98313b0d237fc0..ed043c27deb89247baaf3ca1825237a2721afd69 100644 --- a/components/badge23/include/badge23/display.h +++ b/components/badge23/include/badge23/display.h @@ -5,11 +5,10 @@ #include "../../usermodule/uctx/uctx/ctx.h" void display_init(); -void display_ctx_init(); -void display_update(); -void display_draw_pixel(uint8_t x, uint8_t y, uint16_t col); -uint16_t display_get_pixel(uint8_t x, uint8_t y); -void display_fill(uint16_t col); void display_set_backlight(uint8_t percent); -extern volatile Ctx *the_ctx; +// Transitional functionality operating on global framebuffer and global ctx. +// Will get replaced with 'real' ctx rendering system. +void display_ctx_init(); +void display_update(); +Ctx *display_global_ctx(void); diff --git a/components/flow3r_bsp/CMakeLists.txt b/components/flow3r_bsp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..52d3990ff90db2cccfc6b6ba6eff8bb02cc3bc6c --- /dev/null +++ b/components/flow3r_bsp/CMakeLists.txt @@ -0,0 +1,7 @@ +idf_component_register( + SRCS + flow3r_bsp_display.c + flow3r_bsp_gc9a01.c + INCLUDE_DIRS + . +) diff --git a/components/flow3r_bsp/flow3r_bsp.h b/components/flow3r_bsp/flow3r_bsp.h new file mode 100644 index 0000000000000000000000000000000000000000..ef1fd76cfec2b23d61df66e2c1989d45e4967dd3 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp.h @@ -0,0 +1,32 @@ +#pragma once + +#include <stdint.h> + +// Initialize badge display. An error will be reported if the initialization +// failed. +// +// Must be called exactly once from a task and cannot be called cocurrently with +// any other flow3r_bsp_display_* functions. +// +// Side effects: initializes singleton flow3r display object. All other +// flow3r_bsp_display_* functions operate on same object. +void flow3r_bsp_display_init(void); + +// Send a full framebuffer of 240x240 16bpp pixels to the display. No-op if +// display hasn't been succesfully initialized. +// +// Transfer will be performed using DMA/interrupts and will block the calling +// FreeRTOS task until finished. +// +// This must not be called if another transfer is alraedy being performed. The +// user code should sequence access and make sure not more than one transfer is +// performed simultaneously. +void flow3r_bsp_display_send_fb(uint16_t *fb_data); + +// Set display backlight, as integer percent value (from 0 to 100, clamped). +// No-op if display hasn't been succesfully initialized. +void flow3r_bsp_display_set_backlight(uint8_t percent); + +// Currently same on all generations. Might change on future revisions. +#define FLOW3R_BSP_DISPLAY_WIDTH 240 +#define FLOW3R_BSP_DISPLAY_HEIGHT 240 \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_display.c b/components/flow3r_bsp/flow3r_bsp_display.c new file mode 100644 index 0000000000000000000000000000000000000000..40f8941acddcf0d9c5786907f5503e3708fa3b53 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_display.c @@ -0,0 +1,86 @@ +#include "flow3r_bsp.h" + +#include <string.h> + +#include "esp_log.h" +#include "sdkconfig.h" + +#include "flow3r_bsp_gc9a01.h" + +static const char *TAG = "flow3r-bsp-display"; + +#if defined(CONFIG_BADGE23_HW_GEN_P1) +#define FLOW3R_BSP_GC9A01 +flow3r_bsp_gc9a01_config_t gc9a01_config = { + .reset_used = 1, + .backlight_used = 0, + + .pin_rst = 38, + .pin_sck = 39, + .pin_mosi = 41, + .pin_cs = 40, + .pin_dc = 42, + + .host = 2, +}; +#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6) +#define FLOW3R_BSP_GC9A01 +flow3r_bsp_gc9a01_config_t gc9a01_config = { + .reset_used = 0, + .backlight_used = 1, + + .pin_sck = 41, + .pin_mosi = 42, + .pin_cs = 40, + .pin_dc = 38, + .pin_backlight = 46, + + .host = 2, +}; +#else +#error "display unimplemented for this badge generation" +#endif + +#ifdef FLOW3R_BSP_GC9A01 + +static flow3r_bsp_gc9a01_t gc9a01; +static uint8_t gc9a01_initialized = 0; + +void flow3r_bsp_display_init(void) { + ESP_LOGI(TAG, "gc9a01 initializing..."); + esp_err_t ret = flow3r_bsp_gc9a01_init(&gc9a01, &gc9a01_config); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "gc9a01 init failed: %s", esp_err_to_name(ret)); + } else { + gc9a01_initialized = 1; + ESP_LOGI(TAG, "gc9a01 initialized"); + } +} + +void flow3r_bsp_display_send_fb(uint16_t *fb_data) { + if (!gc9a01_initialized) { + return; + } + static bool had_error = false; + + esp_err_t ret = flow3r_bsp_gc9a01_blit_full(&gc9a01, fb_data); + if (ret != ESP_OK) { + if (!had_error) { + ESP_LOGE(TAG, "display blit failed: %s", esp_err_to_name(ret)); + had_error = true; + } + } else { + if (had_error) { + ESP_LOGI(TAG, "display blit success!"); + had_error = false; + } + } +} + +void flow3r_bsp_display_set_backlight(uint8_t percent) { + if (!gc9a01_initialized) { + return; + } + flow3r_bsp_gc9a01_backlight_set(&gc9a01, percent); +} +#endif \ No newline at end of file diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.c b/components/flow3r_bsp/flow3r_bsp_gc9a01.c new file mode 100644 index 0000000000000000000000000000000000000000..0c7f51e98af5b4e76a19df43e7e9ae1e1994b7e5 --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.c @@ -0,0 +1,597 @@ +// Based on the gc9a01 library by Nadyrshin Ruslan / Liyanboy74. +// +// Copyright (c) 2021, liyanboy74 +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <stdint.h> +#include <string.h> + +#include "esp_log.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "flow3r_bsp_gc9a01.h" +#include "sdkconfig.h" + +#define Cmd_SLPIN 0x10 +#define Cmd_SLPOUT 0x11 +#define Cmd_INVOFF 0x20 +#define Cmd_INVON 0x21 +#define Cmd_DISPOFF 0x28 +#define Cmd_DISPON 0x29 +#define Cmd_CASET 0x2A +#define Cmd_RASET 0x2B +#define Cmd_RAMWR 0x2C +#define Cmd_TEON 0x35 // Tearing effect line ON +#define Cmd_MADCTL 0x36 // Memory data access control +#define Cmd_COLMOD 0x3A // Pixel format set + +#define Cmd_DisplayFunctionControl 0xB6 +#define Cmd_PWCTR1 0xC1 // Power control 1 +#define Cmd_PWCTR2 0xC3 // Power control 2 +#define Cmd_PWCTR3 0xC4 // Power control 3 +#define Cmd_PWCTR4 0xC9 // Power control 4 +#define Cmd_PWCTR7 0xA7 // Power control 7 + +#define Cmd_FRAMERATE 0xE8 +#define Cmd_InnerReg1Enable 0xFE +#define Cmd_InnerReg2Enable 0xEF + +#define Cmd_GAMMA1 0xF0 // Set gamma 1 +#define Cmd_GAMMA2 0xF1 // Set gamma 2 +#define Cmd_GAMMA3 0xF2 // Set gamma 3 +#define Cmd_GAMMA4 0xF3 // Set gamma 4 + +#define ColorMode_RGB_16bit 0x50 +#define ColorMode_RGB_18bit 0x60 +#define ColorMode_MCU_12bit 0x03 +#define ColorMode_MCU_16bit 0x05 +#define ColorMode_MCU_18bit 0x06 + +#define MADCTL_MY 0x80 +#define MADCTL_MX 0x40 +#define MADCTL_MV 0x20 +#define MADCTL_ML 0x10 +#define MADCTL_BGR 0x08 +#define MADCTL_MH 0x04 + +// Transaction 'user' structure as used by SPI transactions to the display. +// Provides enough data for the pre-transaction callback to be able to set the +// DC pin as needed. +typedef struct { + flow3r_bsp_gc9a01_t *gc9a01; + + // DC pin will be set to this in pre-SPI callback. + int dc; +} flow3r_bsp_gc9a01_tx_t; + + +// A full-framebuffer 'blit' operation descriptor. Keeps track of number of +// underlying DMA SPI transactions left until blit is done. +typedef struct { + flow3r_bsp_gc9a01_t *gc9a01; + const uint8_t *fb; + size_t left; + + flow3r_bsp_gc9a01_tx_t gc9a01_tx; + spi_transaction_t spi_tx; +} flow3r_bsp_gc9a01_blit_t; + +/* + The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. +*/ +typedef struct { + uint8_t cmd; + uint8_t data[16]; + uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds. +} flow3r_bsp_gc9a01_init_cmd_t; + +static const flow3r_bsp_gc9a01_init_cmd_t flow3r_bsp_gc9a01_init_cmds[] = { + {0xef,{0},0}, + {0xeb,{0x14},1}, + {0xfe,{0},0}, + {0xef,{0},0}, + {0xeb,{0x14},1}, + {0x84,{0x40},1}, + {0x85,{0xff},1}, + {0x86,{0xff},1}, + {0x87,{0xff},1}, + {0x88,{0x0a},1}, + {0x89,{0x21},1}, + {0x8a,{0x00},1}, + {0x8b,{0x80},1}, + {0x8c,{0x01},1}, + {0x8d,{0x01},1}, + {0x8e,{0xff},1}, + {0x8f,{0xff},1}, + {Cmd_DisplayFunctionControl,{0x00,0x20},2},// Scan direction S360 -> S1 + {0x90,{0x08,0x08,0x08,0x08},4}, + {0xbd,{0x06},1}, + {0xbc,{0x00},1}, + {0xff,{0x60,0x01,0x04},3}, + {Cmd_PWCTR2,{0x13},1}, + {Cmd_PWCTR3,{0x13},1}, + {Cmd_PWCTR4,{0x22},1}, + {0xbe,{0x11},1}, + {0xe1,{0x10,0x0e},2}, + {0xdf,{0x21,0x0c,0x02},3}, + {Cmd_GAMMA1,{0x45,0x09,0x08,0x08,0x26,0x2a},6}, + {Cmd_GAMMA2,{0x43,0x70,0x72,0x36,0x37,0x6f},6}, + {Cmd_GAMMA3,{0x45,0x09,0x08,0x08,0x26,0x2a},6}, + {Cmd_GAMMA4,{0x43,0x70,0x72,0x36,0x37,0x6f},6}, + {0xed,{0x1b,0x0b},2}, + {0xae,{0x77},1}, + {0xcd,{0x63},1}, + {0x70,{0x07,0x07,0x04,0x0e,0x0f,0x09,0x07,0x08,0x03},9}, + {Cmd_FRAMERATE,{0x34},1},// 4 dot inversion + {0x62,{0x18,0x0D,0x71,0xED,0x70,0x70,0x18,0x0F,0x71,0xEF,0x70,0x70},12}, + {0x63,{0x18,0x11,0x71,0xF1,0x70,0x70,0x18,0x13,0x71,0xF3,0x70,0x70},12}, + {0x64,{0x28,0x29,0xF1,0x01,0xF1,0x00,0x07},7}, + {0x66,{0x3C,0x00,0xCD,0x67,0x45,0x45,0x10,0x00,0x00,0x00},10}, + {0x67,{0x00,0x3C,0x00,0x00,0x00,0x01,0x54,0x10,0x32,0x98},10}, + {0x74,{0x10,0x85,0x80,0x00,0x00,0x4E,0x00},7}, + {0x98,{0x3e,0x07},2}, + {Cmd_TEON,{0},0},// Tearing effect line on + {0, {0}, 0xff},//END +}; + +// This function is called (in irq context!) just before a transmission starts. It will +// set the D/C line to the value indicated in the tx's dc field. +static IRAM_ATTR void flow3r_bsp_gc9a01_pre_transfer_callback(spi_transaction_t *t) +{ + flow3r_bsp_gc9a01_tx_t *tx = (flow3r_bsp_gc9a01_tx_t *)t->user; + gpio_set_level(tx->gc9a01->config->pin_dc, tx->dc); +} + +/* Send a command to the LCD. Uses spi_device_polling_transmit, which waits + * until the transfer is complete. + * + * Since command transactions are usually small, they are handled in polling + * mode for higher speed. The overhead of interrupt transactions is more than + * just waiting for the transaction to complete. + */ +esp_err_t flow3r_bsp_gc9a01_cmd_sync(flow3r_bsp_gc9a01_t *gc9a01, uint8_t cmd) +{ + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + + t.length = 8; + t.tx_buffer = &cmd; + + // As we're running a synchronous transaction, we can allocate the TX object + // on the stack, as this frame is guaranteed to be valid until the + // transaction completes. + flow3r_bsp_gc9a01_tx_t tx = { + .gc9a01 = gc9a01, + .dc = 0, + }; + + t.user = (void*)&tx; + esp_err_t res = spi_device_polling_transmit(gc9a01->spi, &t); + return res; +} + +/* Send data to the LCD. Uses spi_device_polling_transmit, which waits until the + * transfer is complete. + * + * Since data transactions are usually small, they are handled in polling + * mode for higher speed. The overhead of interrupt transactions is more than + * just waiting for the transaction to complete. + */ +esp_err_t flow3r_bsp_gc9a01_data_sync(flow3r_bsp_gc9a01_t *gc9a01, const uint8_t *data, int len) { + if (len == 0) { + return ESP_OK; + } + + // As we're running a synchronous transaction, we can allocate the TX object + // on the stack, as this frame is guaranteed to be valid until the + // transaction completes. + flow3r_bsp_gc9a01_tx_t tx = { + .gc9a01 = gc9a01, + // DC == 1 for data. + .dc = 1, + }; + /* + On certain MC's the max SPI DMA transfer length might be smaller than the buffer. We then have to split the transmissions. + */ + int offset = 0; + do { + spi_transaction_t t; + memset(&t, 0, sizeof(t)); //Zero out the transaction + + int tx_len = ((len - offset) < SPI_MAX_DMA_LEN) ? (len - offset) : SPI_MAX_DMA_LEN; + // Len is in bytes, transaction length is in bits. + t.length = tx_len * 8; + t.tx_buffer = data + offset; + t.user = (void*)&tx; + + // Transmit! + esp_err_t ret = spi_device_polling_transmit(gc9a01->spi, &t); + if (ret != ESP_OK) { + return ret; + } + offset += tx_len; + } + while (offset < len); + + return ESP_OK; +} + +esp_err_t flow3r_bsp_gc9a01_data_byte_sync(flow3r_bsp_gc9a01_t *gc9a01, const uint8_t data) { + return flow3r_bsp_gc9a01_data_sync(gc9a01, &data, 1); +} + +static esp_err_t flow3r_bsp_gc9a01_mem_access_mode_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t rotation, uint8_t vert_mirror, uint8_t horiz_mirror, uint8_t is_bgr) { + uint8_t val = 0; + rotation &= 7; + + switch (rotation) { + case 0: + val = 0; + break; + case 1: + val = MADCTL_MX; + break; + case 2: + val = MADCTL_MY; + break; + case 3: + val = MADCTL_MX | MADCTL_MY; + break; + case 4: + val = MADCTL_MV; + break; + case 5: + val = MADCTL_MV | MADCTL_MX; + break; + case 6: + val = MADCTL_MV | MADCTL_MY; + break; + case 7: + val = MADCTL_MV | MADCTL_MX | MADCTL_MY; + break; + } + + if (vert_mirror) + val = MADCTL_ML; + if (horiz_mirror) + val = MADCTL_MH; + + if (is_bgr) + val |= MADCTL_BGR; + + esp_err_t ret = flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_MADCTL); + if (ret != ESP_OK) { + return ret; + } + return flow3r_bsp_gc9a01_data_byte_sync(gc9a01, val); +} + +static esp_err_t flow3r_bsp_gc9a01_color_mode_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t color_mode) { + esp_err_t ret = flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_COLMOD); + if (ret != ESP_OK) { + return ret; + } + return flow3r_bsp_gc9a01_data_byte_sync(gc9a01, color_mode & 0x77); +} + +static esp_err_t flow3r_bsp_gc9a01_inversion_mode_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t mode) { + if (mode) + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_INVON); + else + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_INVOFF); +} + +static esp_err_t flow3r_bsp_gc9a01_sleep_mode_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t mode) { + if (mode) + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_SLPIN); + else + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_SLPOUT); + vTaskDelay(500 / portTICK_PERIOD_MS); +} + +static esp_err_t flow3r_bsp_gc9a01_power_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t mode) { + if (mode) + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_DISPON); + else + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_DISPOFF); +} + +static esp_err_t flow3r_bsp_gc9a01_column_set(flow3r_bsp_gc9a01_t *gc9a01, uint16_t start, uint16_t end) { + esp_err_t ret; + ret = flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_CASET); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_gc9a01_data_byte_sync(gc9a01, start >> 8); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_gc9a01_data_byte_sync(gc9a01, start & 0xFF); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_gc9a01_data_byte_sync(gc9a01, end >> 8); + if (ret != ESP_OK) { + return ret; + } + return flow3r_bsp_gc9a01_data_byte_sync(gc9a01, end & 0xFF); +} + +static esp_err_t flow3r_bsp_gc9a01_row_set(flow3r_bsp_gc9a01_t *gc9a01, uint16_t start, uint16_t end) { + esp_err_t ret; + ret = flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_RASET); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_gc9a01_data_byte_sync(gc9a01, start >> 8); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_gc9a01_data_byte_sync(gc9a01, start & 0xFF); + if (ret != ESP_OK) { + return ret; + } + ret = flow3r_bsp_gc9a01_data_byte_sync(gc9a01, end >> 8); + if (ret != ESP_OK) { + return ret; + } + return flow3r_bsp_gc9a01_data_byte_sync(gc9a01, end & 0xFF); +} + +esp_err_t flow3r_bsp_gc9a01_backlight_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t value) { + if (gc9a01->config->backlight_used == 0) { + return ESP_OK; + } + if (value > 100) { + value = 100; + } + + uint16_t max_duty = (1 << (int)gc9a01->bl_timer_config.duty_resolution) - 1; + uint16_t duty; + if (value >= 100) { + duty = max_duty; + } else { + duty = value * (max_duty / (float)100); + } + + gc9a01->bl_channel_config.duty = duty; + return ledc_channel_config(&gc9a01->bl_channel_config); +} + +esp_err_t flow3r_bsp_gc9a01_init(flow3r_bsp_gc9a01_t *gc9a01, flow3r_bsp_gc9a01_config_t *config) { + memset(gc9a01, 0, sizeof(flow3r_bsp_gc9a01_t)); + gc9a01->config = config; + + // Configure DC pin. + gpio_config_t gpiocfg = { + .pin_bit_mask = ((uint64_t)1UL << gc9a01->config->pin_dc), + .mode = GPIO_MODE_OUTPUT, + .pull_up_en = GPIO_PULLUP_DISABLE, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + esp_err_t res = gpio_config(&gpiocfg); + if (res != ESP_OK) { + return res; + } + gpio_set_level(gc9a01->config->pin_dc, 0); + + // Configure Reset pin if used. + if (gc9a01->config->reset_used) { + gpiocfg.pin_bit_mask |= ((uint64_t)1UL << gc9a01->config->pin_rst); + res = gpio_config(&gpiocfg); + if (res != ESP_OK) { + return res; + } + gpio_set_level(gc9a01->config->pin_rst, 1); + } + + // Configure SPI bus. + // + // TODO(q3k): don't do this here, do this higher up in the BSP. Even if + // nothing else sits on this bus. + spi_bus_config_t buscfg = { + .mosi_io_num = gc9a01->config->pin_mosi, + .miso_io_num = GPIO_NUM_NC, + .sclk_io_num = gc9a01->config->pin_sck, + .quadwp_io_num = GPIO_NUM_NC, + .quadhd_io_num = GPIO_NUM_NC, + .max_transfer_sz = 250*250*2, + }; + + // Configure SPI device on bus. + spi_device_interface_config_t devcfg = { + .clock_speed_hz = 80*1000*1000, + .mode = 0, + .spics_io_num = gc9a01->config->pin_cs, + .queue_size = 7, + .pre_cb = flow3r_bsp_gc9a01_pre_transfer_callback, + }; + + esp_err_t ret = spi_bus_initialize(gc9a01->config->host, &buscfg, SPI_DMA_CH_AUTO); + if (ret != ESP_OK) { + return ret; + } + + ret = spi_bus_add_device(gc9a01->config->host, &devcfg, &gc9a01->spi); + if (ret != ESP_OK) { + goto cleanup_spi_bus; + } + + // Configure backlight timer/channel if used. + if (gc9a01->config->backlight_used) { + gc9a01->bl_timer_config.speed_mode = LEDC_LOW_SPEED_MODE; + gc9a01->bl_timer_config.duty_resolution = LEDC_TIMER_8_BIT; + gc9a01->bl_timer_config.timer_num = LEDC_TIMER_0; + gc9a01->bl_timer_config.freq_hz=1000; + gc9a01->bl_timer_config.clk_cfg=LEDC_AUTO_CLK; + ret = ledc_timer_config(&gc9a01->bl_timer_config); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + + gc9a01->bl_channel_config.gpio_num = gc9a01->config->pin_backlight; + gc9a01->bl_channel_config.speed_mode = LEDC_LOW_SPEED_MODE; + gc9a01->bl_channel_config.channel = LEDC_CHANNEL_0; + gc9a01->bl_channel_config.intr_type = LEDC_INTR_DISABLE; + gc9a01->bl_channel_config.timer_sel = LEDC_TIMER_0; + gc9a01->bl_channel_config.duty = 0; + gc9a01->bl_channel_config.hpoint = 0; + ret = ledc_channel_config(&gc9a01->bl_channel_config); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + } + + // Issue reset if used. + if (gc9a01->config->reset_used) { + gpio_set_level(gc9a01->config->pin_rst, 0); + vTaskDelay(10 / portTICK_PERIOD_MS); + gpio_set_level(gc9a01->config->pin_rst, 1); + vTaskDelay(150 / portTICK_PERIOD_MS); + } + + // Send initialization commands. + int ix = 0; + while (flow3r_bsp_gc9a01_init_cmds[ix].databytes != 0xff) { + const flow3r_bsp_gc9a01_init_cmd_t *cmd = &flow3r_bsp_gc9a01_init_cmds[ix]; + flow3r_bsp_gc9a01_cmd_sync(gc9a01, cmd->cmd); + flow3r_bsp_gc9a01_data_sync(gc9a01, cmd->data, cmd->databytes & 0x1F); + if (cmd->databytes & 0x80) { + vTaskDelay(100 / portTICK_PERIOD_MS); + } + ix++; + } + + ret = flow3r_bsp_gc9a01_mem_access_mode_set(gc9a01, 0, 0, 0, 1); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + ret = flow3r_bsp_gc9a01_color_mode_set(gc9a01, ColorMode_MCU_16bit); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + ret = flow3r_bsp_gc9a01_inversion_mode_set(gc9a01, 1); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + ret = flow3r_bsp_gc9a01_sleep_mode_set(gc9a01, 0); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + vTaskDelay(120 / portTICK_PERIOD_MS); + + ret = flow3r_bsp_gc9a01_power_set(gc9a01, 1); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + vTaskDelay(20 / portTICK_PERIOD_MS); + + // We always write the entire framebuffer at once. + ret = flow3r_bsp_gc9a01_column_set(gc9a01, 0, 239); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + ret = flow3r_bsp_gc9a01_row_set(gc9a01, 0, 239); + if (ret != ESP_OK) { + goto cleanup_spi_device; + } + + return ret; + +cleanup_spi_device: + spi_bus_remove_device(gc9a01->spi); +cleanup_spi_bus: + spi_bus_free(gc9a01->config->host); + return ret; +} + +static esp_err_t flow3r_bsp_gc9a01_blit_next(flow3r_bsp_gc9a01_blit_t *blit) { + size_t size = blit->left; + if (size > SPI_MAX_DMA_LEN) { + size = SPI_MAX_DMA_LEN; + } + + blit->gc9a01_tx.gc9a01 = blit->gc9a01; + blit->gc9a01_tx.dc = 1; + + // Memzero spi_tx as it gets written by the SPI driver after each + // transaction. + memset(&blit->spi_tx, 0, sizeof(spi_transaction_t)); + blit->spi_tx.length = size * 8; + blit->spi_tx.tx_buffer = blit->fb; + blit->spi_tx.user = &blit->gc9a01_tx; + + blit->left -= size; + blit->fb += size; + + return spi_device_queue_trans(blit->gc9a01->spi, &blit->spi_tx, portMAX_DELAY); +} + +static esp_err_t flow3r_bsp_gc9a01_blit_start(flow3r_bsp_gc9a01_t *gc9a01, flow3r_bsp_gc9a01_blit_t *blit, const uint16_t *fb) { + memset(blit, 0, sizeof(flow3r_bsp_gc9a01_blit_t)); + + blit->gc9a01 = gc9a01; + blit->fb = (const uint8_t *)fb; + blit->left = 2 * 240 * 240; + + return flow3r_bsp_gc9a01_cmd_sync(gc9a01, Cmd_RAMWR); +} + +static uint8_t flow3r_bsp_gc9a01_blit_done(flow3r_bsp_gc9a01_blit_t *blit) { + return blit->left == 0; +} + +static esp_err_t flow3r_bsp_gc9a01_blit_wait_done(flow3r_bsp_gc9a01_blit_t *blit, TickType_t ticks_to_wait) { + spi_transaction_t *tx_done; + esp_err_t ret = spi_device_get_trans_result(blit->gc9a01->spi, &tx_done, ticks_to_wait); + // TODO(q3k): validate that tx_done corresponds to the spi_transaction_tx in + // bilt. If not, this means we got some sequencing failure to deal with. + return ret; +} + +esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01, const uint16_t *fb) { + flow3r_bsp_gc9a01_blit_t blit; + esp_err_t res = flow3r_bsp_gc9a01_blit_start(gc9a01, &blit, fb); + if (res != ESP_OK) { + return res; + } + + while (!flow3r_bsp_gc9a01_blit_done(&blit)) { + res = flow3r_bsp_gc9a01_blit_next(&blit); + if (res != ESP_OK) { + return res; + } + res = flow3r_bsp_gc9a01_blit_wait_done(&blit, portMAX_DELAY); + if (res != ESP_OK) { + return res; + } + } + return ESP_OK; +} diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.h b/components/flow3r_bsp/flow3r_bsp_gc9a01.h new file mode 100644 index 0000000000000000000000000000000000000000..38225683717128001719bb8096cbea9caae5259f --- /dev/null +++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.h @@ -0,0 +1,69 @@ +#pragma once + +#include <stdint.h> + +#include "driver/spi_master.h" +#include "driver/ledc.h" + +// Configuration structure for display. +// +// The display expects to be the only device on an SPI bus. +typedef struct { + // Boolean: whether the display as a reset pin connected. + uint8_t reset_used; + // Boolean: whether the display as backlight control connected to the ESP + // LED Control peripheral. + uint8_t backlight_used; + + // Reset pin, if reset_used. + uint8_t pin_rst; + // SPI SCK pin. + uint8_t pin_sck; + // SPI MOSI pin. + uint8_t pin_mosi; + // SPI CS pin. + uint8_t pin_cs; + // Data/Command pin. + uint8_t pin_dc; + // Backlight control pin, if backlight_used. + uint8_t pin_backlight; + + // Nubmer of SPI host device (ie. bus) that the display will use. + spi_host_device_t host; +} flow3r_bsp_gc9a01_config_t; + +typedef struct { + const flow3r_bsp_gc9a01_config_t *config; + + // Allocatged SPI device handle on configured bus. + spi_device_handle_t spi; + + // Only if using backlight. + ledc_channel_config_t bl_channel_config; + ledc_timer_config_t bl_timer_config; + +} flow3r_bsp_gc9a01_t; + +// Initialize display structure based on config, and then actually initialize +// display hardware and ESP peripherals. +// +// The given gc9a01 structure does not need to be zeroed out. +// +// The given config structure must live as long as the display object lives. As +// currently displays cannot be de-initialized, this means that the +// configuration structure must live forever. +// +// An error will be returned if initialization failed. Initialization can be +// re-tried. +esp_err_t flow3r_bsp_gc9a01_init(flow3r_bsp_gc9a01_t *gc9a01, flow3r_bsp_gc9a01_config_t *config); + +// Send a full-sized framebuffer to the display using interrupts/DMA, blocking +// FreeRTOS task until done. +// +// This must not be called if another blit is being performed. The user code +// should sequence access and make sure not more than one blit is performed +// simultaneously. +esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01, const uint16_t *fb); + +// Set backlight for display, using integer percent value (0-100, clamped). +esp_err_t flow3r_bsp_gc9a01_backlight_set(flow3r_bsp_gc9a01_t *gc9a01, uint8_t value); \ No newline at end of file diff --git a/components/gc9a01/CMakeLists.txt b/components/gc9a01/CMakeLists.txt deleted file mode 100644 index 739a7727e21526a3b2b0828c0d7337cd601aa58c..0000000000000000000000000000000000000000 --- a/components/gc9a01/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -idf_component_register(SRCS "gc9a01.c" REQUIRES driver badge23_hwconfig INCLUDE_DIRS ".") diff --git a/components/gc9a01/LICENSE b/components/gc9a01/LICENSE deleted file mode 100644 index 9fd35d36ac2d0b39c3051d6874c9aae48f08cc13..0000000000000000000000000000000000000000 --- a/components/gc9a01/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2021, liyanboy74 -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/components/gc9a01/gc9a01.c b/components/gc9a01/gc9a01.c deleted file mode 100644 index 0870dc5eb4822f4ac0c045aa10dd1f8b7210902c..0000000000000000000000000000000000000000 --- a/components/gc9a01/gc9a01.c +++ /dev/null @@ -1,648 +0,0 @@ -//-------------------------------------------------------------------------------------------------------- -// Nadyrshin Ruslan - [YouTube-channel: https://www.youtube.com/channel/UChButpZaL5kUUl_zTyIDFkQ] -// Liyanboy74 -//-------------------------------------------------------------------------------------------------------- -#include <stdio.h> -#include <string.h> - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "driver/gpio.h" -#include "driver/spi_master.h" -#include "driver/ledc.h" - -#include "sdkconfig.h" -#include "gc9a01.h" - -#if (GC9A01_RESET_USED) -#define RESET_HIGH() gpio_set_level(GC9A01_PIN_NUM_RST,1) -#define RESET_LOW() gpio_set_level(GC9A01_PIN_NUM_RST,0) -#endif - -#if(GC9A01_CONTROL_BACK_LIGHT_USED) -#define BLK_HIGH() gpio_set_level(GC9A01_PIN_NUM_BCKL,1) -#define BLK_LOW() gpio_set_level(GC9A01_PIN_NUM_BCKL,0) -#endif - -#define Cmd_SLPIN 0x10 -#define Cmd_SLPOUT 0x11 -#define Cmd_INVOFF 0x20 -#define Cmd_INVON 0x21 -#define Cmd_DISPOFF 0x28 -#define Cmd_DISPON 0x29 -#define Cmd_CASET 0x2A -#define Cmd_RASET 0x2B -#define Cmd_RAMWR 0x2C -#define Cmd_TEON 0x35 // Tearing effect line ON -#define Cmd_MADCTL 0x36 // Memory data access control -#define Cmd_COLMOD 0x3A // Pixel format set - -#define Cmd_DisplayFunctionControl 0xB6 -#define Cmd_PWCTR1 0xC1 // Power control 1 -#define Cmd_PWCTR2 0xC3 // Power control 2 -#define Cmd_PWCTR3 0xC4 // Power control 3 -#define Cmd_PWCTR4 0xC9 // Power control 4 -#define Cmd_PWCTR7 0xA7 // Power control 7 - -#define Cmd_FRAMERATE 0xE8 -#define Cmd_InnerReg1Enable 0xFE -#define Cmd_InnerReg2Enable 0xEF - -#define Cmd_GAMMA1 0xF0 // Set gamma 1 -#define Cmd_GAMMA2 0xF1 // Set gamma 2 -#define Cmd_GAMMA3 0xF2 // Set gamma 3 -#define Cmd_GAMMA4 0xF3 // Set gamma 4 - -#define ColorMode_RGB_16bit 0x50 -#define ColorMode_RGB_18bit 0x60 -#define ColorMode_MCU_12bit 0x03 -#define ColorMode_MCU_16bit 0x05 -#define ColorMode_MCU_18bit 0x06 - -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 -#define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 - -uint8_t GC9A01_X_Start = 0, GC9A01_Y_Start = 0; - -#if (GC9A01_BUFFER_MODE) -DMA_ATTR uint16_t ScreenBuff[GC9A01_Height * GC9A01_Width]; -#endif - -//SPI Config -spi_device_handle_t spi; -spi_host_device_t LCD_HOST=GC9A01_SPI_HOST; - -//LEDC Config -#if(GC9A01_CONTROL_BACK_LIGHT_USED) -#if(GC9A01_CONTROL_BACK_LIGHT_MODE) -ledc_channel_config_t ledc_cConfig; -ledc_timer_config_t ledc_tConfig; -void LEDC_PWM_Duty_Set(uint8_t DutyP); -#endif -#endif - -/* - The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. -*/ -typedef struct { - uint8_t cmd; - uint8_t data[16]; - uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds. -} lcd_init_cmd_t; - -static const lcd_init_cmd_t lcd_init_cmds[]={ - {0xef,{0},0}, - {0xeb,{0x14},1}, - {0xfe,{0},0}, - {0xef,{0},0}, - {0xeb,{0x14},1}, - {0x84,{0x40},1}, - {0x85,{0xff},1}, - {0x86,{0xff},1}, - {0x87,{0xff},1}, - {0x88,{0x0a},1}, - {0x89,{0x21},1}, - {0x8a,{0x00},1}, - {0x8b,{0x80},1}, - {0x8c,{0x01},1}, - {0x8d,{0x01},1}, - {0x8e,{0xff},1}, - {0x8f,{0xff},1}, - {Cmd_DisplayFunctionControl,{0x00,0x20},2},// Scan direction S360 -> S1 - //{Cmd_MADCTL,{0x08},1},//MemAccessModeSet(0, 0, 0, 1); - //{Cmd_COLMOD,{ColorMode_MCU_16bit&0x77},1}, - {0x90,{0x08,0x08,0x08,0x08},4}, - {0xbd,{0x06},1}, - {0xbc,{0x00},1}, - {0xff,{0x60,0x01,0x04},3}, - {Cmd_PWCTR2,{0x13},1}, - {Cmd_PWCTR3,{0x13},1}, - {Cmd_PWCTR4,{0x22},1}, - {0xbe,{0x11},1}, - {0xe1,{0x10,0x0e},2}, - {0xdf,{0x21,0x0c,0x02},3}, - {Cmd_GAMMA1,{0x45,0x09,0x08,0x08,0x26,0x2a},6}, - {Cmd_GAMMA2,{0x43,0x70,0x72,0x36,0x37,0x6f},6}, - {Cmd_GAMMA3,{0x45,0x09,0x08,0x08,0x26,0x2a},6}, - {Cmd_GAMMA4,{0x43,0x70,0x72,0x36,0x37,0x6f},6}, - {0xed,{0x1b,0x0b},2}, - {0xae,{0x77},1}, - {0xcd,{0x63},1}, - {0x70,{0x07,0x07,0x04,0x0e,0x0f,0x09,0x07,0x08,0x03},9}, - {Cmd_FRAMERATE,{0x34},1},// 4 dot inversion - {0x62,{0x18,0x0D,0x71,0xED,0x70,0x70,0x18,0x0F,0x71,0xEF,0x70,0x70},12}, - {0x63,{0x18,0x11,0x71,0xF1,0x70,0x70,0x18,0x13,0x71,0xF3,0x70,0x70},12}, - {0x64,{0x28,0x29,0xF1,0x01,0xF1,0x00,0x07},7}, - {0x66,{0x3C,0x00,0xCD,0x67,0x45,0x45,0x10,0x00,0x00,0x00},10}, - {0x67,{0x00,0x3C,0x00,0x00,0x00,0x01,0x54,0x10,0x32,0x98},10}, - {0x74,{0x10,0x85,0x80,0x00,0x00,0x4E,0x00},7}, - {0x98,{0x3e,0x07},2}, - {Cmd_TEON,{0},0},// Tearing effect line on - {0, {0}, 0xff},//END -}; - -//This function is called (in irq context!) just before a transmission starts. It will -//set the D/C line to the value indicated in the user field. -static IRAM_ATTR void lcd_spi_pre_transfer_callback(spi_transaction_t *t) -{ - int dc=(int)t->user; - gpio_set_level(GC9A01_PIN_NUM_DC, dc); -} - -/* Send a command to the LCD. Uses spi_device_polling_transmit, which waits - * until the transfer is complete. - * - * Since command transactions are usually small, they are handled in polling - * mode for higher speed. The overhead of interrupt transactions is more than - * just waiting for the transaction to complete. - */ -void lcd_cmd(uint8_t cmd) -{ - esp_err_t ret; - spi_transaction_t t; - memset(&t, 0, sizeof(t)); //Zero out the transaction - t.length=8; //Command is 8 bits - t.tx_buffer=&cmd; //The data is the cmd itself - t.user=(void*)0; //D/C needs to be set to 0 - ret=spi_device_polling_transmit(spi, &t); //Transmit! - assert(ret==ESP_OK); //Should have had no issues. -} - -/* Send data to the LCD. Uses spi_device_polling_transmit, which waits until the - * transfer is complete. - * - * Since data transactions are usually small, they are handled in polling - * mode for higher speed. The overhead of interrupt transactions is more than - * just waiting for the transaction to complete. - */ -void lcd_data(const uint8_t *data, int len) -{ - esp_err_t ret; - if (len==0) return; //no need to send anything - - /* - On certain MC's the max SPI DMA transfer length might be smaller than the buffer. We then have to split the transmissions. - */ - int offset = 0; - do { - spi_transaction_t t; - memset(&t, 0, sizeof(t)); //Zero out the transaction - - int tx_len = ((len - offset) < SPI_MAX_DMA_LEN) ? (len - offset) : SPI_MAX_DMA_LEN; - t.length=tx_len * 8; //Len is in bytes, transaction length is in bits. - t.tx_buffer= data + offset; //Data - t.user=(void*)1; //D/C needs to be set to 1 - ret=spi_device_polling_transmit(spi, &t); //Transmit! - assert(ret==ESP_OK); //Should have had no issues. - offset += tx_len; // Add the transmission length to the offset - } - while (offset < len); -} - -void lcd_send_byte(uint8_t Data) -{ - lcd_data(&Data,1); -} - -void delay_ms (uint32_t Delay_ms) -{ - vTaskDelay(Delay_ms/portTICK_PERIOD_MS); -} - -uint16_t GC9A01_GetWidth() { - return GC9A01_Width; -} - -uint16_t GC9A01_GetHeight() { - return GC9A01_Height; -} - -void GC9A01_HardReset(void) { - #if (GC9A01_RESET_USED) - RESET_LOW(); - delay_ms(10); - RESET_HIGH(); - delay_ms(150); - #endif -} - -void GC9A01_SleepMode(uint8_t Mode) { - if (Mode) - lcd_cmd(Cmd_SLPIN); - else - lcd_cmd(Cmd_SLPOUT); - - delay_ms(500); -} - -void GC9A01_InversionMode(uint8_t Mode) { - if (Mode) - lcd_cmd(Cmd_INVON); - else - lcd_cmd(Cmd_INVOFF); -} - -void GC9A01_DisplayPower(uint8_t On) { - if (On) - lcd_cmd(Cmd_DISPON); - else - lcd_cmd(Cmd_DISPOFF); -} - -static void ColumnSet(uint16_t ColumnStart, uint16_t ColumnEnd) { - if (ColumnStart > ColumnEnd) - return; - if (ColumnEnd > GC9A01_Width) - return; - - ColumnStart += GC9A01_X_Start; - ColumnEnd += GC9A01_X_Start; - - lcd_cmd(Cmd_CASET); - lcd_send_byte(ColumnStart >> 8); - lcd_send_byte(ColumnStart & 0xFF); - lcd_send_byte(ColumnEnd >> 8); - lcd_send_byte(ColumnEnd & 0xFF); -} - -static void RowSet(uint16_t RowStart, uint16_t RowEnd) { - if (RowStart > RowEnd) - return; - if (RowEnd > GC9A01_Height) - return; - - RowStart += GC9A01_Y_Start; - RowEnd += GC9A01_Y_Start; - - lcd_cmd(Cmd_RASET); - lcd_send_byte(RowStart >> 8); - lcd_send_byte(RowStart & 0xFF); - lcd_send_byte(RowEnd >> 8); - lcd_send_byte(RowEnd & 0xFF); -} - -void GC9A01_SetWindow(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) { - ColumnSet(x0, x1); - RowSet(y0, y1); - - lcd_cmd(Cmd_RAMWR); -} - -static void ColorModeSet(uint8_t ColorMode) { - lcd_cmd(Cmd_COLMOD); - lcd_send_byte(ColorMode & 0x77); -} - -static void MemAccessModeSet(uint8_t Rotation, uint8_t VertMirror, - uint8_t HorizMirror, uint8_t IsBGR) { - uint8_t Ret=0; - Rotation &= 7; - - lcd_cmd(Cmd_MADCTL); - - switch (Rotation) { - case 0: - Ret = 0; - break; - case 1: - Ret = MADCTL_MX; - break; - case 2: - Ret = MADCTL_MY; - break; - case 3: - Ret = MADCTL_MX | MADCTL_MY; - break; - case 4: - Ret = MADCTL_MV; - break; - case 5: - Ret = MADCTL_MV | MADCTL_MX; - break; - case 6: - Ret = MADCTL_MV | MADCTL_MY; - break; - case 7: - Ret = MADCTL_MV | MADCTL_MX | MADCTL_MY; - break; - } - - if (VertMirror) - Ret = MADCTL_ML; - if (HorizMirror) - Ret = MADCTL_MH; - - if (IsBGR) - Ret |= MADCTL_BGR; - - lcd_send_byte(Ret); -} - -void GC9A01_SetBL(uint8_t Value) -{ - if (Value > 100) Value = 100; - #if(GC9A01_CONTROL_BACK_LIGHT_USED) - #if(GC9A01_CONTROL_BACK_LIGHT_MODE) - LEDC_PWM_Duty_Set(Value); - #else - if (Value) BLK_HIGH(); - else BLK_LOW(); - #endif - #endif -} - -//Direct Mode -#if (!GC9A01_BUFFER_MODE) - - void GC9A01_RamWrite(uint16_t *pBuff, uint16_t Len) - { - while (Len--) - { - lcd_send_byte(*pBuff >> 8); - lcd_send_byte(*pBuff & 0xFF); - } - } - - void GC9A01_DrawPixel(int16_t x, int16_t y, uint16_t color) - { - if ((x < 0) ||(x >= GC9A01_Width) || (y < 0) || (y >= GC9A01_Height)) - return; - - GC9A01_SetWindow(x, y, x, y); - GC9A01_RamWrite(&color, 1); - } - - void GC9A01_FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) - { - if ((x >= GC9A01_Width) || (y >= GC9A01_Height)) - return; - - if ((x + w) > GC9A01_Width) - w = GC9A01_Width - x; - - if ((y + h) > GC9A01_Height) - h = GC9A01_Height - y; - - GC9A01_SetWindow(x, y, x + w - 1, y + h - 1); - - for (uint32_t i = 0; i < (h * w); i++) - GC9A01_RamWrite(&color, 1); - } - -//Buffer mode -#else - - static void SwapBytes(uint16_t *color) { - uint8_t temp = *color >> 8; - *color = (*color << 8) | temp; - } - - uint16_t GC9A01_GetPixel(int16_t x, int16_t y) { - if ((x < 0) || (x >= GC9A01_Width) || (y < 0) || (y >= GC9A01_Height)) - return 0; - - uint16_t color = ScreenBuff[y * GC9A01_Width + x]; - SwapBytes(&color); - return color; - } - - void GC9A01_DrawPixel(int16_t x, int16_t y, uint16_t color) { - if ((x < 0) || (x >= GC9A01_Width) || (y < 0) || (y >= GC9A01_Height)) - return; - SwapBytes(&color); - ScreenBuff[y * GC9A01_Width + x] = color; - } - - void GC9A01_FillRect(int16_t x, int16_t y, int16_t w, int16_t h, - uint16_t color) { - if ((w <= 0) || (h <= 0) || (x >= GC9A01_Width) || (y >= GC9A01_Height)) - return; - - if (x < 0) { - w += x; - x = 0; - } - if (y < 0) { - h += y; - y = 0; - } - - if ((w <= 0) || (h <= 0)) - return; - - if ((x + w) > GC9A01_Width) - w = GC9A01_Width - x; - if ((y + h) > GC9A01_Height) - h = GC9A01_Height - y; - - SwapBytes(&color); - - for (uint16_t row = 0; row < h; row++) { - for (uint16_t col = 0; col < w; col++) - //GC9A01_DrawPixel(col, row, color); - ScreenBuff[(y + row) * GC9A01_Width + x + col] = color; - } - } - - void GC9A01_Update() - { - int len = GC9A01_Width * GC9A01_Height; - GC9A01_SetWindow(0, 0, GC9A01_Width - 1, GC9A01_Height - 1); - lcd_data((uint8_t*) &ScreenBuff[0], len*2); - } - - void GC9A01_Clear(void) - { - GC9A01_FillRect(0, 0, GC9A01_Width, GC9A01_Height, 0x0000); - } - -#endif - -static void gc9a01_GPIO_init(void) -{ - gpio_config_t gpiocfg={ - .pin_bit_mask= ((uint64_t)1UL<<GC9A01_PIN_NUM_DC), - .mode=GPIO_MODE_OUTPUT, - .pull_up_en=GPIO_PULLUP_DISABLE, - .pull_down_en=GPIO_PULLDOWN_DISABLE, - .intr_type=GPIO_INTR_DISABLE, - }; - - gpio_config(&gpiocfg); - gpio_set_level(GC9A01_PIN_NUM_DC,0); - - #if(GC9A01_RESET_USED) - gpiocfg.pin_bit_mask|=((uint64_t)1UL<<GC9A01_PIN_NUM_RST); - gpio_config(&gpiocfg); - gpio_set_level(GC9A01_PIN_NUM_RST,1); - #endif - - #if(GC9A01_CONTROL_BACK_LIGHT_USED) - #if(!GC9A01_CONTROL_BACK_LIGHT_MODE) - gpiocfg.pin_bit_mask|=((uint64_t)1UL<<GC9A01_PIN_NUM_BCKL); - gpio_config(&gpiocfg); - gpio_set_level(GC9A01_PIN_NUM_BCKL,0); - #endif - #endif - -} - -void gc9a01_SPI_init(void) -{ - esp_err_t ret; - spi_bus_config_t buscfg={ - .mosi_io_num=GC9A01_PIN_NUM_MOSI, - .miso_io_num=GPIO_NUM_NC, - .sclk_io_num=GC9A01_PIN_NUM_SCK, - .quadwp_io_num=-1, - .quadhd_io_num=-1, - .max_transfer_sz=250*250*2, - }; - spi_device_interface_config_t devcfg={ - .clock_speed_hz=GC9A01_SPI_SCK_FREQ_M*1000*1000, - .mode=0, - .spics_io_num=GC9A01_PIN_NUM_CS, - .queue_size=7, - .pre_cb=lcd_spi_pre_transfer_callback, - }; - - ret=spi_bus_initialize(LCD_HOST,&buscfg,SPI_DMA_CH_AUTO); - ESP_ERROR_CHECK(ret); - - ret=spi_bus_add_device(LCD_HOST,&devcfg,&spi); - ESP_ERROR_CHECK(ret); -} - -#if(GC9A01_CONTROL_BACK_LIGHT_USED) -#if(GC9A01_CONTROL_BACK_LIGHT_MODE) -void LEDC_PWM_Duty_Set(uint8_t DutyP) -{ - uint16_t Duty,MaxD; - - MaxD=(1<<(int)ledc_tConfig.duty_resolution)-1; - - if(DutyP>=100)Duty=MaxD; - else - { - Duty=DutyP*(MaxD/(float)100); - } - ledc_cConfig.duty=Duty; - ledc_channel_config(&ledc_cConfig); -} - -void LEDC_Channel_Config(void) -{ - ledc_cConfig.gpio_num=GC9A01_PIN_NUM_BCKL; - ledc_cConfig.speed_mode=LEDC_LOW_SPEED_MODE; - ledc_cConfig.channel=LEDC_CHANNEL_0; - ledc_cConfig.intr_type=LEDC_INTR_DISABLE; - ledc_cConfig.timer_sel=LEDC_TIMER_0; - ledc_cConfig.duty=0; - ledc_cConfig.hpoint=0; - ledc_channel_config(&ledc_cConfig); -} - -void LEDC_Timer_Config(void) -{ - ledc_tConfig.speed_mode=LEDC_LOW_SPEED_MODE ; - ledc_tConfig.duty_resolution=LEDC_TIMER_8_BIT; - //ledc_tConfig.bit_num=LEDC_TIMER_8_BIT; - ledc_tConfig.timer_num=LEDC_TIMER_0; - ledc_tConfig.freq_hz=1000; - ledc_tConfig.clk_cfg=LEDC_AUTO_CLK; - ledc_timer_config(&ledc_tConfig); -} -#endif -#endif - -void GC9A01_Init() -{ - int cmd=0; - - GC9A01_X_Start = 0; - GC9A01_Y_Start = 0; - - gc9a01_GPIO_init(); - gc9a01_SPI_init(); - - #if(GC9A01_CONTROL_BACK_LIGHT_USED) - #if(GC9A01_CONTROL_BACK_LIGHT_MODE) - LEDC_Timer_Config(); - LEDC_Channel_Config(); - #endif - #endif - - #if(GC9A01_RESET_USED) - GC9A01_HardReset(); - #endif - - //Send all the commands - while (lcd_init_cmds[cmd].databytes!=0xff) - { - lcd_cmd(lcd_init_cmds[cmd].cmd); - lcd_data(lcd_init_cmds[cmd].data, lcd_init_cmds[cmd].databytes&0x1F); - if (lcd_init_cmds[cmd].databytes&0x80) - { - delay_ms(100); - } - cmd++; - } - - MemAccessModeSet(0,0,0,1); - ColorModeSet(ColorMode_MCU_16bit); - - GC9A01_InversionMode(1); - GC9A01_SleepMode(0); - - delay_ms(120); - GC9A01_DisplayPower(1); - delay_ms(20); - - #if(GC9A01_BUFFER_MODE) - GC9A01_Clear(); - GC9A01_Update(); - delay_ms(30); - #endif - - #if(GC9A01_CONTROL_BACK_LIGHT_USED) - GC9A01_SetBL(100); - #endif -} - -#if(GC9A01_BUFFER_MODE) -void GC9A01_Screen_Shot(uint16_t x,uint16_t y,uint16_t width ,uint16_t height,uint16_t * Buffer) -{ - uint16_t i,j; - for (i=0;i<height;i++) - { - for(j=0;j<width;j++) - { - #if(!GC9A01_BUFFER_SCREEN_FAST_MODE) - Buffer[i*width+j]=GC9A01_GetPixel(x+j,y+i); - #else - Buffer[i*width+j]=ScreenBuff[((y+i) * GC9A01_Width )+ (x+j)]; - #endif - } - } -} -void GC9A01_Screen_Load(uint16_t x,uint16_t y,uint16_t width ,uint16_t height,uint16_t * Buffer) -{ - uint16_t i,j; - for (i=0;i<height;i++) - { - for(j=0;j<width;j++) - { - #if(!GC9A01_BUFFER_SCREEN_FAST_MODE) - GC9A01_DrawPixel(x+j,y+i,Buffer[i*width+j]); - #else - ScreenBuff[((y+i) * GC9A01_Width )+ (x+j)] = Buffer[i*width+j]; - #endif - } - } -} -#endif diff --git a/components/gc9a01/gc9a01.h b/components/gc9a01/gc9a01.h deleted file mode 100644 index 34c6a8ae83b6eeed09ea1559e78c9bc2b10ba1fc..0000000000000000000000000000000000000000 --- a/components/gc9a01/gc9a01.h +++ /dev/null @@ -1,67 +0,0 @@ -//-------------------------------------------------------------------------------------------------------- -// Nadyrshin Ruslan - [YouTube-channel: https://www.youtube.com/channel/UChButpZaL5kUUl_zTyIDFkQ] -// Liyanboy74 -//-------------------------------------------------------------------------------------------------------- -#ifndef _GC9A01_H -#define _GC9A01_H - -#include "sdkconfig.h" -#include <stdint.h> -#include "badge23_hwconfig.h" - - -#ifdef CONFIG_GC9A01_PIN_NUM_MOSI -#warning "idf menuconfig is ignored for display config, it breaks hardware revision switching atm" -#endif - -#if defined(CONFIG_BADGE23_HW_GEN_P1) -#define USE_SPI3_HOST 1 -#define GC9A01_SPI_HOST 2 -#define GC9A01_PIN_NUM_SCK 39 -#define GC9A01_PIN_NUM_MOSI 41 -#define GC9A01_PIN_NUM_CS 40 -#define GC9A01_PIN_NUM_DC 42 -#define GC9A01_SPI_SCK_FREQ_M 80 -#define GC9A01_RESET_USED 1 -#define GC9A01_PIN_NUM_RST 38 -#define GC9A01_BUFFER_MODE 1 - -#elif defined(CONFIG_BADGE23_HW_GEN_P3) || defined(CONFIG_BADGE23_HW_GEN_P4) || defined(CONFIG_BADGE23_HW_GEN_P6) -#define USE_SPI3_HOST 1 -#define GC9A01_SPI_HOST 2 -#define GC9A01_PIN_NUM_SCK 41 -#define GC9A01_PIN_NUM_MOSI 42 -#define GC9A01_PIN_NUM_CS 40 -#define GC9A01_PIN_NUM_DC 38 -#define GC9A01_SPI_SCK_FREQ_M 80 -#define GC9A01_CONTROL_BACK_LIGHT_USED 1 -#define GC9A01_PIN_NUM_BCKL 46 -#define GC9A01_BACK_LIGHT_MODE_PWM 1 -#define GC9A01_CONTROL_BACK_LIGHT_MODE 1 -#define GC9A01_BUFFER_MODE 1 - -#else -#error "gc9a01 unimplemented for this badge generation" -#endif - -#define GC9A01_Width 240 -#define GC9A01_Height 240 - -extern uint16_t ScreenBuff[GC9A01_Height * GC9A01_Width]; - -uint16_t GC9A01_GetWidth(); -uint16_t GC9A01_GetHeight(); - -void GC9A01_Init(); -void GC9A01_SleepMode(uint8_t Mode); -void GC9A01_DisplayPower(uint8_t On); -void GC9A01_DrawPixel(int16_t x, int16_t y, uint16_t color); -void GC9A01_FillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); -void GC9A01_Update(); -void GC9A01_SetBL(uint8_t Value); -uint16_t GC9A01_GetPixel(int16_t x, int16_t y); - -void GC9A01_Screen_Shot(uint16_t x,uint16_t y,uint16_t width ,uint16_t height,uint16_t * Buffer); -void GC9A01_Screen_Load(uint16_t x,uint16_t y,uint16_t width ,uint16_t height,uint16_t * Buffer); - -#endif diff --git a/components/gc9a01/readme.md b/components/gc9a01/readme.md deleted file mode 100644 index 46156f31f42a3177b151ba8045dd86fcecb72434..0000000000000000000000000000000000000000 --- a/components/gc9a01/readme.md +++ /dev/null @@ -1,51 +0,0 @@ -# GC9A01 ESP-IDF Component - -Clone to `components` folder and run `idf.py menuconfig` - - - -**Add as submodule:** - -`git submodule add https://github.com/liyanboy74/gc9a01-esp-idf.git components/gc9a01` - -**Example Test:** - -```c -#include <stdio.h> -#include <string.h> -#include <math.h> -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "driver/gpio.h" -#include "sdkconfig.h" - -#include "gc9a01.h" - -#define STACK_SIZE 2048 - -void LCD(void * arg) -{ - uint16_t Color; - GC9A01_Init(); - for(;;) - { - Color=rand(); - GC9A01_FillRect(0,0,239,239,Color); - GC9A01_Update(); - vTaskDelay(1000/portTICK_PERIOD_MS); - } -} - -void app_main(void) -{ - TaskHandle_t LCDHandle; - - xTaskCreate(LCD,"Test LCD",STACK_SIZE,NULL,tskIDLE_PRIORITY,&LCDHandle); - configASSERT(LCDHandle); -} - -``` - -- If you succeed, it's time to go one layer higher! Try [Dispcolor](https://github.com/liyanboy74/dispcolor) -- You can also use the [BMP24 to RGB565](https://github.com/liyanboy74/bmp24-to-rgb565) tools to convert and display images - diff --git a/sdkconfig.p1 b/sdkconfig.p1 index dfa66a8b35f4606c1287f81d017ea1a49a659172..9d58c19655bb26aa3e875ee6f56a41c1ac7b9348 100644 --- a/sdkconfig.p1 +++ b/sdkconfig.p1 @@ -12,6 +12,10 @@ CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_ESPPSRAM64=y +CONFIG_SPIRAM_SPEED_80M=y CONFIG_PM_ENABLE=y CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set diff --git a/sdkconfig.p3 b/sdkconfig.p3 index 1680de7e8e6690eb6531b519983cf998ca72beb2..1b06862f23efb6b225a524bf504ef092fc4cdca3 100644 --- a/sdkconfig.p3 +++ b/sdkconfig.p3 @@ -12,6 +12,10 @@ CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_ESPPSRAM64=y +CONFIG_SPIRAM_SPEED_80M=y CONFIG_PM_ENABLE=y CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set diff --git a/sdkconfig.p4 b/sdkconfig.p4 index 3244f8307c78e2e3e2ed23ce8d138ec81a41df61..632271f522d54663acf3e17c0d0fda14ddb31e2c 100644 --- a/sdkconfig.p4 +++ b/sdkconfig.p4 @@ -12,6 +12,10 @@ CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_ESPPSRAM64=y +CONFIG_SPIRAM_SPEED_80M=y CONFIG_PM_ENABLE=y CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set @@ -26,4 +30,4 @@ CONFIG_LOG_DEFAULT_LEVEL_ERROR=y CONFIG_LWIP_PPP_SUPPORT=y CONFIG_LWIP_PPP_PAP_SUPPORT=y CONFIG_LWIP_PPP_CHAP_SUPPORT=y -CONFIG_BADGE23_HW_GEN_P4=y \ No newline at end of file +CONFIG_BADGE23_HW_GEN_P4=y diff --git a/sdkconfig.p6 b/sdkconfig.p6 index 022e70a5d015e78b16c4f99d31b21ab2256a054e..8d298d5bfaba5c174cd4846038d5e2d89867a42b 100644 --- a/sdkconfig.p6 +++ b/sdkconfig.p6 @@ -12,6 +12,10 @@ CONFIG_BT_ENABLED=y CONFIG_BT_NIMBLE_ENABLED=y CONFIG_BT_NIMBLE_MAX_CONNECTIONS=4 CONFIG_BT_NIMBLE_PINNED_TO_CORE_1=y +CONFIG_ESP32S3_SPIRAM_SUPPORT=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_TYPE_ESPPSRAM64=y +CONFIG_SPIRAM_SPEED_80M=y CONFIG_PM_ENABLE=y CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y # CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 is not set diff --git a/usermodule/mp_hardware.c b/usermodule/mp_hardware.c index fa7dec9ffb64fc5122e73fa8278314987eb9ef9f..ed5cf36587339395ce51ba88b37d04ed2e893c06 100644 --- a/usermodule/mp_hardware.c +++ b/usermodule/mp_hardware.c @@ -172,12 +172,13 @@ STATIC mp_obj_t mp_version(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mp_version_obj, mp_version); STATIC mp_obj_t mp_get_ctx(size_t n_args, const mp_obj_t *args) { + Ctx *ctx = NULL; // This might be called before the ctx is ready. // HACK: this will go away with the new drawing API. - while (the_ctx == NULL) { + while ((ctx = display_global_ctx()) == NULL) { vTaskDelay(100 / portTICK_PERIOD_MS); } - mp_obj_t mp_ctx = mp_ctx_from_ctx(the_ctx); + mp_obj_t mp_ctx = mp_ctx_from_ctx(ctx); return mp_ctx; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_get_ctx_obj, 0, 0, mp_get_ctx);