From 205aa6a21025e1c57b922aedec16d4153e432705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eckhard=20V=C3=B6llm?= Date: Sun, 21 Nov 2021 21:35:40 +0100 Subject: [PATCH 1/2] added draft esp32 hal (based on arduino ATM) and ili9341 --- eglib/display/ili9341.c | 644 ++++++++++++++++++ eglib/display/ili9341.h | 131 ++++ .../hal/four_wire_spi/esp32/esp32_ili9341.cpp | 97 +++ eglib/hal/four_wire_spi/esp32/esp32_ili9341.h | 34 + 4 files changed, 906 insertions(+) create mode 100644 eglib/display/ili9341.c create mode 100644 eglib/display/ili9341.h create mode 100644 eglib/hal/four_wire_spi/esp32/esp32_ili9341.cpp create mode 100644 eglib/hal/four_wire_spi/esp32/esp32_ili9341.h diff --git a/eglib/display/ili9341.c b/eglib/display/ili9341.c new file mode 100644 index 00000000..6fb53139 --- /dev/null +++ b/eglib/display/ili9341.c @@ -0,0 +1,644 @@ +#include "ili9341.h" +#include "frame_buffer.h" +#include + + +// +// Timings +// + +#define ILI9341_RESX_PULSE_MS 10 +#define ILI9341_RESX_CANCEL_MS 120 + +#define ILI9341_SOFTWARE_RESET_DELAY_MS 5 +#define ILI9341_SOFTWARE_RESET_SLEEP_MODE_DELAY_MS 120 + +#define ILI9341_SLEEP_IN_DELAY_MS 5 +#define ILI9341_SLEEP_OUT_DELAY_MS 120 + +// +// Commands +// + +#define ILI9341_NO_OPERATION 0x00 + +#define ILI9341_SOFTWARE_RESET 0x01 + +#define ILI9341_READ_DISPLAY_ID 0x04 + +#define ILI9341_READ_DISPLAY_STATUS 0x09 + +#define ILI9341_READ_DISPLAY_POWER_MODE 0x0a + +#define ILI9341_READ_DISPLAY_MADCTL 0x0b + +#define ILI9341_READ_DISPLAY_PIXEL_FORMAT 0x0c + +#define ILI9341_READ_DISPLAY_IMAGE_MODE 0x0d + +#define ILI9341_READ_DISPLAY_SIGNAL_MODE 0x0e + +#define ILI9341_READ_DISPLAY_SELF_DIAGNOSTIC_RESULT 0x0f + +#define ILI9341_SLEEP_IN 0x10 + +#define ILI9341_SLEEP_OUT 0x11 + +#define ILI9341_PARTIAL_DISPLAY_MODE_ON 0x12 + +#define ILI9341_NORMAL_DISPLAY_MODE_ON 0x13 + +#define ILI9341_DISPLAY_INVERSION_OFF 0x20 + +#define ILI9341_DISPLAY_INVERSION_ON 0x21 + +#define ILI9341_GAMMA_SET 0x26 + +#define ILI9341_DISPLAY_OFF 0x28 + +#define ILI9341_DISPLAY_ON 0x29 + +#define ILI9341_COLUMN_ADDRESS_SET 0x2a + +#define ILI9341_ROW_ADDRESS_SET 0x2b + +#define ILI9341_MEMORY_WRITE 0x2c + +#define ILI9341_MEMORY_READ 0x2e + +#define ILI9341_COLOR_SET 0x2d + +#define ILI9341_PARTIAL_AREA 0x30 + +#define ILI9341_VERTICAL_SCROLLING_DEFINITION 0x33 + +#define ILI9341_TEARING_EFFECT_LINE_OFF 0x34 + +#define ILI9341_TEARING_EFFECT_LINE_ON 0x35 + +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL 0x36 + +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_ADDRESS_TOP_TO_BOTTOM (0<<7) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_ADDRESS_BOTTOM_TO_TOP (1<<7) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_COLUMN_ADDRESS_LEFT_TO_RIGHT (0<<6) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_COLUMN_ADDRESS_RIGHT_TO_LEFT (1<<6) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_COLUMN_ORDER_NORMAL (0<<5) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_COLUMN_ORDER_REVERSE (1<<5) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_LINE_ADDRESS_ORDER_LCD_REFRESH_TOP_TO_BOTTOM (0<<4) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_LINE_ADDRESS_ORDER_LCD_REFRESH_BOTTOM_TO_TOP (1<<4) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_RGB (0<<3) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_BGR (1<<3) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_DISPLAY_DATA_LATCH_DATA_ORDER_LCD_REFRESH_LEFT_TO_RIGHT (0<<0) +#define ILI9341_MEMORY_DATA_ACCESS_CONTROL_DISPLAY_DATA_LATCH_DATA_ORDER_LCD_REFRESH_RIGHT_TO_LEFT (1<<0) + +#define ILI9341_VERTICAL_SCROLL_START_ADDRESS_OF_RAM 0x37 + +#define ILI9341_IDLE_MODE_OFF 0x38 + +#define ILI9341_IDLE_MODE_ON 0x39 + +#define ILI9341_INTERFACE_PIXEL_FORMAT 0x3a + +#define ILI9341_INTERFACE_PIXEL_FORMAT_RGB_INTERFACE_BIT 4 +#define ILI9341_INTERFACE_PIXEL_FORMAT_RGB_INTERFACE_65K (5<color) { + case ILI9341_COLOR_12_BIT: + interface_pixel_format |= ILI9341_INTERFACE_PIXEL_FORMAT_COLOR_12BIT; + break; + case ILI9341_COLOR_16_BIT: + interface_pixel_format |= ILI9341_INTERFACE_PIXEL_FORMAT_COLOR_16BIT; + break; + case ILI9341_COLOR_18_BIT: + interface_pixel_format |= ILI9341_INTERFACE_PIXEL_FORMAT_COLOR_18BIT; + break; + } + eglib_SendCommandByte(eglib, ILI9341_INTERFACE_PIXEL_FORMAT); + eglib_SendDataByte(eglib, interface_pixel_format); +} + +static void set_memory_data_access_control(eglib_t *eglib) { + ili9341_config_t *display_config; + uint8_t memory_data_access_control; + + display_config = eglib_GetDisplayConfig(eglib); + + memory_data_access_control = 0; + switch(display_config->page_address) { + case ILI9341_PAGE_ADDRESS_TOP_TO_BOTTOM: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_ADDRESS_TOP_TO_BOTTOM; + break; + case ILI9341_PAGE_ADDRESS_BOTTOM_TO_TOP: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_ADDRESS_BOTTOM_TO_TOP; + break; + } + switch(display_config->colum_address) { + case ILI9341_COLUMN_ADDRESS_LEFT_TO_RIGHT: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_COLUMN_ADDRESS_LEFT_TO_RIGHT; + break; + case ILI9341_COLUMN_ADDRESS_RIGHT_TO_LEFT: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_COLUMN_ADDRESS_RIGHT_TO_LEFT; + break; + } + switch(display_config->page_column_order) { + case ILI9341_PAGE_COLUMN_ORDER_NORMAL: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_COLUMN_ORDER_NORMAL; + break; + case ILI9341_PAGE_COLUMN_ORDER_REVERSE: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_PAGE_COLUMN_ORDER_REVERSE; + break; + } + switch(display_config->vertical_refresh) { + case ILI9341_VERTICAL_REFRESH_TOP_TO_BOTTOM: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_LINE_ADDRESS_ORDER_LCD_REFRESH_TOP_TO_BOTTOM; + break; + case ILI9341_VERTICAL_REFRESH_BOTTOM_TO_TOP: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_LINE_ADDRESS_ORDER_LCD_REFRESH_BOTTOM_TO_TOP; + break; + } + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_BGR; + switch(display_config->horizontal_refresh) { + case ILI9341_HORIZONTAL_REFRESH_LEFT_TO_RIGHT: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_DISPLAY_DATA_LATCH_DATA_ORDER_LCD_REFRESH_LEFT_TO_RIGHT; + break; + case ILI9341_HORIZONTAL_REFRESH_RIGHT_TO_LEFT: + memory_data_access_control |= ILI9341_MEMORY_DATA_ACCESS_CONTROL_DISPLAY_DATA_LATCH_DATA_ORDER_LCD_REFRESH_RIGHT_TO_LEFT; + break; + } + eglib_SendCommandByte(eglib, ILI9341_MEMORY_DATA_ACCESS_CONTROL); + eglib_SendDataByte(eglib, memory_data_access_control); +} + +static void set_column_address(eglib_t *eglib, uint16_t x_start, uint16_t x_end) { + uint8_t buff[4]; + + eglib_SendCommandByte(eglib, ILI9341_COLUMN_ADDRESS_SET); + buff[0] = (x_start&0xFF00)>>8; + buff[1] = x_start&0xFF; + buff[2] = (x_end&0xFF00)>>8; + buff[3] = x_end&0xFF; + eglib_SendData(eglib, buff, sizeof(buff)); +} + +static void set_row_address(eglib_t *eglib, uint16_t y_start, uint16_t y_end) { + uint8_t buff[4]; + + eglib_SendCommandByte(eglib, ILI9341_ROW_ADDRESS_SET); + buff[0] = (y_start&0xFF00)>>8; + buff[1] = y_start&0xFF; + buff[2] = (y_end&0xFF00)>>8; + buff[3] = y_end&0xFF; + eglib_SendData(eglib, buff, sizeof(buff)); +} + +static uint8_t get_bits_per_pixel(eglib_t *eglib) { + ili9341_config_t *display_config; + + display_config = eglib_GetDisplayConfig(eglib); + + switch(display_config->color) { + case ILI9341_COLOR_12_BIT: + return 12; + break; + case ILI9341_COLOR_16_BIT: + return 16; + break; + case ILI9341_COLOR_18_BIT: + return 24; + break; + default: + while(true); + } +} + +static void clear_memory(eglib_t *eglib) { + return; // +++++++++++++++++++++++++++++++++++++++++ return to help debugging + ili9341_config_t *display_config; + uint32_t memory_size; + display_config = eglib_GetDisplayConfig(eglib); + + memory_size = (display_config->width * display_config->height * get_bits_per_pixel(eglib)) / 8; + ESP_LOGI("ili9341", "memory size: %d %d %d %d", memory_size, display_config->width, display_config->height, get_bits_per_pixel(eglib) ); + + set_column_address(eglib, 0, display_config->width - 1); + set_row_address(eglib, 0, display_config->height - 1); + eglib_SendCommandByte(eglib, ILI9341_MEMORY_WRITE); + uint8_t buf[256] = { 255 }; + for(uint32_t addr=0 ; addr < memory_size ; addr+= 256 ){ + ESP_LOGI("ili9341", "addr: %d", addr ); + eglib_SendData(eglib, buf, 256 ); + } +} + +static void send_pixel(eglib_t *eglib, color_t color) { + ili9341_config_t *display_config; + uint8_t buff[3]; + + display_config = eglib_GetDisplayConfig(eglib); + + switch(display_config->color) { + case ILI9341_COLOR_12_BIT: + buff[0] = color.r & 0xf0; + buff[0] |= (color.g & 0xf0) >> 4; + buff[1] = color.b & 0xf0; + for(uint8_t i=0 ; i < 2 ; i++) + eglib_SendDataByte(eglib, buff[i]); + break; + case ILI9341_COLOR_16_BIT: + buff[0] = color.r & 0xf8; + buff[0] |= color.g >> 5; + buff[1] = (color.g >> 2) << 5; + buff[1] |= color.b >> 3; + for(uint8_t i=0 ; i < 2 ; i++) + eglib_SendDataByte(eglib, buff[i]); + break; + case ILI9341_COLOR_18_BIT: + buff[0] = color.r & ~0x03; + buff[1] = color.g & ~0x03; + buff[2] = color.b & ~0x03; + for(uint8_t i=0 ; i < 3 ; i++) + eglib_SendDataByte(eglib, buff[i]); + break; + default: + while(true); + } +} + +// +// Display +// + +static void init(eglib_t *eglib) { + // Hardware reset + eglib_SetReset(eglib, 0); + eglib_DelayMs(eglib, ILI9341_RESX_PULSE_MS); + eglib_SetReset(eglib, 1); + eglib_DelayMs(eglib, ILI9341_RESX_CANCEL_MS); + + // Software reset + eglib_CommBegin(eglib); + eglib_SendCommandByte(eglib, ILI9341_SOFTWARE_RESET); + eglib_CommEnd(eglib); + eglib_DelayMs(eglib, ILI9341_SOFTWARE_RESET_DELAY_MS); + + // comm begin again after SW reset + eglib_CommBegin(eglib); + + // Out of sleep mode + eglib_SendCommandByte(eglib, ILI9341_SLEEP_OUT); + eglib_DelayMs(eglib, ILI9341_SLEEP_OUT_DELAY_MS); + + // Set color mode + set_interface_pixel_format(eglib); + + // Memory Data Access Control + set_memory_data_access_control(eglib); + + // we need invers, datasheet says oposite + eglib_SendCommandByte(eglib, ILI9341_DISPLAY_INVERSION_OFF); + // after sw reset, but unless we explicitly set it, + // ILI9341_DISPLAY_INVERSION_ON will have no effect. + eglib_SendCommandByte(eglib, ILI9341_NORMAL_DISPLAY_MODE_ON); + + // UCG_C11(0x03a, 0x066), /* set pixel format to 18 bit */ + eglib_SendCommandByte(eglib, ILI9341_INTERFACE_PIXEL_FORMAT); + eglib_SendDataByte(eglib, ILI9341_INTERFACE_PIXEL_FORMAT_RGB_INTERFACE_262K | ILI9341_INTERFACE_PIXEL_FORMAT_COLOR_18BIT ); + + // UCG_C14(0x0b6, 0x00a, 0x082 | (1<<5), 0x027, 0x000), /* display function control (POR values, except for shift direction bit) */ + eglib_SendCommandByte(eglib, 0xb6 ); + eglib_SendDataByte(eglib,0x0a ); + eglib_SendDataByte(eglib, 0x082 | (1<<5) ); + eglib_SendDataByte(eglib,0x27 ); + eglib_SendDataByte(eglib,0x00 ); + + // UCG_C11(0x0c0, 0x021), /* power control 1 (reference voltage level), POR=21 */ + eglib_SendCommandByte(eglib, 0xc0 ); + eglib_SendDataByte(eglib,0x21 ); + + // UCG_C11(0x0c1, 0x002), /* power control 2 (step up factor), POR=2 */ + eglib_SendCommandByte(eglib, 0xc1 ); + eglib_SendDataByte(eglib,0x02 ); + + // UCG_C11(0x0c7, 0x0c0), /* VCOM control 2, enable VCOM control 1 */ + eglib_SendCommandByte(eglib, 0xc7 ); + eglib_SendDataByte(eglib,0xc0 ); + + // UCG_C12(0x0c5, 0x031, 0x03c), /* VCOM control 1, POR=31,3C */ + eglib_SendCommandByte(eglib, 0xc5 ); + eglib_SendDataByte(eglib,0x31 ); + eglib_SendDataByte(eglib,0x3c ); + + // UCG_C15(0x0cb, 0x039, 0x02c, 0x000, 0x034, 0x002), /* power control A (POR values) */ + eglib_SendCommandByte(eglib, 0xcb ); + uint8_t seqpc[] = { 0x039, 0x02c, 0x000, 0x034, 0x002 }; + eglib_Send(eglib, HAL_DATA, seqpc, sizeof(seqpc) ); + + + // UCG_C13(0x0cf, 0x000, 0x081, 0x030), /* power control B (POR values) */ + eglib_SendCommandByte(eglib, 0xcf ); + uint8_t seqcb[] = { 0x000, 0x081, 0x030 }; + eglib_Send(eglib, HAL_DATA, seqcb, sizeof(seqcb) ); + + // UCG_C13(0x0e8, 0x084, 0x011, 0x07a), /* timer driving control A (POR values) */ + eglib_SendCommandByte(eglib, 0xe8 ); + uint8_t seqca[] = { 0x084, 0x011, 0x07a }; + eglib_Send(eglib, HAL_DATA, seqca, sizeof(seqca) ); + + // UCG_C12(0x0ea, 0x066, 0x000), /* timer driving control B (POR values) */ + eglib_SendCommandByte(eglib, 0xe8 ); + uint8_t seqcp[] = { 0x066, 0x000 }; + eglib_Send(eglib, HAL_DATA, seqcp, sizeof(seqcp) ); + + // UCG_C10(0x029), /* display on */ + eglib_SendCommandByte(eglib, ILI9341_DISPLAY_ON ); + + // UCG_C14( 0x02a, 0x000, 0x000, 0x000, 0x0ef), /* Horizontal GRAM Address Set */ + eglib_SendCommandByte(eglib, ILI9341_COLUMN_ADDRESS_SET ); + uint8_t seqga[] = { 0x000, 0x000, 0x000, 0x0ef }; + eglib_Send(eglib, HAL_DATA, seqga, sizeof(seqga) ); + + // UCG_C14( 0x02b, 0x000, 0x000, 0x001, 0x03f), /* Vertical GRAM Address Set */ + eglib_SendCommandByte(eglib, ILI9341_ROW_ADDRESS_SET ); + uint8_t seqra[] = {0x000, 0x000, 0x001, 0x03f }; + eglib_Send(eglib, HAL_DATA, seqra, sizeof(seqra) ); + + // UCG_C10( 0x02c), /* Write Data to GRAM */ + eglib_SendCommandByte(eglib, ILI9341_MEMORY_WRITE ); + + // Clear RAM + // clear_memory(eglib); + + // Main screen turn on + // eglib_SendCommandByte(eglib, ILI9341_DISPLAY_ON); + + eglib_CommEnd(eglib); +}; + +static void sleep_in(eglib_t *eglib) { + eglib_CommBegin(eglib); + eglib_SendCommandByte(eglib, ILI9341_SLEEP_IN); + eglib_CommEnd(eglib); + eglib_DelayMs(eglib, ILI9341_SLEEP_IN_DELAY_MS); +}; + +static void sleep_out(eglib_t *eglib) { + eglib_CommBegin(eglib); + eglib_SendCommandByte(eglib, ILI9341_SLEEP_OUT); + eglib_CommEnd(eglib); + eglib_DelayMs(eglib, ILI9341_SLEEP_OUT_DELAY_MS); +}; + +static void get_dimension( + eglib_t *eglib, + coordinate_t *width, coordinate_t*height +) { + ili9341_config_t *display_config; + + display_config = eglib_GetDisplayConfig(eglib); + + *width = display_config->width;; + *height = display_config->height; +}; + +static void get_pixel_format(eglib_t *eglib, enum pixel_format_t *pixel_format) { + ili9341_config_t *display_config; + + display_config = eglib_GetDisplayConfig(eglib); + + switch(display_config->color) { + case ILI9341_COLOR_12_BIT: + *pixel_format = PIXEL_FORMAT_12BIT_RGB; + break; + case ILI9341_COLOR_16_BIT: + *pixel_format = PIXEL_FORMAT_16BIT_RGB; + break; + case ILI9341_COLOR_18_BIT: + *pixel_format = PIXEL_FORMAT_18BIT_RGB_24BIT; + break; + default: + while(true); + } +} + +static void draw_pixel_color( + eglib_t *eglib, + coordinate_t x, coordinate_t y, color_t color +) { + eglib_CommBegin(eglib); + + set_column_address(eglib, x, x); + set_row_address(eglib, y, y); + + eglib_SendCommandByte(eglib, ILI9341_MEMORY_WRITE); + + send_pixel(eglib, color); + + eglib_CommEnd(eglib); +}; + +static void draw_line( + eglib_t *eglib, + coordinate_t x, + coordinate_t y, + enum display_line_direction_t direction, + coordinate_t length, + color_t (*get_next_color)(eglib_t *eglib) +) { + // ESP_LOGI("drawLine","x:%d y:%d dir:%d", x, y, direction ); + if(direction == DISPLAY_LINE_DIRECTION_RIGHT) { + eglib_CommBegin(eglib); + + set_column_address(eglib, x, x + length); + set_row_address(eglib, y, y); + + eglib_SendCommandByte(eglib, ILI9341_MEMORY_WRITE); + + for(length++ ; length-- ; ) + send_pixel(eglib, get_next_color(eglib)); + + eglib_CommEnd(eglib); + } else { + display_default_draw_line( + eglib, + x, y, + direction, length, + get_next_color + ); + } +} + +static void send_buffer( + eglib_t *eglib, + void *buffer_ptr, + coordinate_t x, coordinate_t y, + coordinate_t width, coordinate_t height +) { + ili9341_config_t *display_config; + uint8_t *buffer = (uint8_t *)buffer_ptr; + + display_config = eglib_GetDisplayConfig(eglib); + + if((uint32_t)x * get_bits_per_pixel(eglib) % 8) + x -= 1; + + eglib_CommBegin(eglib); + set_column_address(eglib, x, x + width); + for(coordinate_t v=y ; v < y + height ; v++) { + set_row_address(eglib, v, v); + eglib_SendCommandByte(eglib, ILI9341_MEMORY_WRITE); + eglib_SendData( + eglib, + buffer + ( + display_config->width * v + x + ) * get_bits_per_pixel(eglib) / 8, + (uint32_t)width * get_bits_per_pixel(eglib) / 8 + ); + } + eglib_CommEnd(eglib); +} + +static bool refresh(eglib_t *eglib) { + (void)eglib; + return false; +} + +const display_t ili9341 = { + .comm = { + .four_wire_spi = &((hal_four_wire_spi_config_t){ + .mode = 0, + .bit_numbering = HAL_MSB_FIRST, + .cs_setup_ns = 15, + .cs_hold_ns = 15, + .cs_disable_ns = 40, + .dc_setup_ns = 10, + .dc_hold_ns = 10, + .sck_cycle_ns = 66, // 15.1MHz Datasheet + // .sck_cycle_ns = 47, // 21.2MHz Overclock + }), + .i2c = NULL, + .parallel_8_bit_8080 = &((hal_parallel_8_bit_8080_config_t){ + .csx_setup_ns = 15, + .csx_hold_ns = 10, + .csx_disable_ns = 0, + .dcx_setup_ns = 0, + .wrx_cycle_ns = 66, + .wrx_high_ns = 15, + .wrx_low_ns = 15, + }), + }, + .init = init, + .sleep_in = sleep_in, + .sleep_out = sleep_out, + .get_dimension = get_dimension, + .get_pixel_format = get_pixel_format, + .draw_pixel_color = draw_pixel_color, + .draw_line = draw_line, + .send_buffer = send_buffer, + .refresh = refresh, +}; + +// +// Custom functions +// + +void ili9341_SetDisplayInversion(eglib_t *eglib, bool inversion) { + eglib_CommBegin(eglib); + if(inversion) + eglib_SendCommandByte(eglib, ILI9341_DISPLAY_INVERSION_OFF); + else + eglib_SendCommandByte(eglib, ILI9341_DISPLAY_INVERSION_ON); + eglib_CommEnd(eglib); +} + +void ili9341_SetIdleMode(eglib_t *eglib, bool idle) { + eglib_CommBegin(eglib); + if(idle) + eglib_SendCommandByte(eglib, ILI9341_IDLE_MODE_ON); + else + eglib_SendCommandByte(eglib, ILI9341_IDLE_MODE_OFF); + eglib_CommEnd(eglib); +} + diff --git a/eglib/display/ili9341.h b/eglib/display/ili9341.h new file mode 100644 index 00000000..e4ed5750 --- /dev/null +++ b/eglib/display/ili9341.h @@ -0,0 +1,131 @@ +#ifndef EGLIB_DISPLAY_ILI9341_H +#define EGLIB_DISPLAY_ILI9341_H + +#include "../../eglib.h" +#include + +/** + * Types + * ===== + */ + +/** + * Display color depth. Higher color depths require more data to be transfered, + * meaning slower refresh rates and more memory required when using a frame + * buffer. + */ +typedef enum { + /** 12 bit */ + ILI9341_COLOR_12_BIT, + /** 16 bit */ + ILI9341_COLOR_16_BIT, + /** 18 bit (encoded as 24 bit in memory) */ + ILI9341_COLOR_18_BIT, +} ili9341_color_t; + +/** Memory data access control: page address order. */ +typedef enum { + /** Top to bottom. */ + ILI9341_PAGE_ADDRESS_TOP_TO_BOTTOM, + /** Bottom to top. */ + ILI9341_PAGE_ADDRESS_BOTTOM_TO_TOP, +} ili9341_page_address_t; + +/** Memory data access control: column address order. */ +typedef enum { + /** Left to right. */ + ILI9341_COLUMN_ADDRESS_LEFT_TO_RIGHT, + /** Right to left. */ + ILI9341_COLUMN_ADDRESS_RIGHT_TO_LEFT, +} ili9341_colum_address_t; + +/** Memory data access control: page/column order. */ +typedef enum { + /** Normal mode */ + ILI9341_PAGE_COLUMN_ORDER_NORMAL, + /** Reverse mode */ + ILI9341_PAGE_COLUMN_ORDER_REVERSE, +} ili9341_page_colum_order_t; + + +/** Memory data access control: line address order. */ +typedef enum { + /** LCD refresh top to bottom. */ + ILI9341_VERTICAL_REFRESH_TOP_TO_BOTTOM, + /** LCD refresh bottom to top. */ + ILI9341_VERTICAL_REFRESH_BOTTOM_TO_TOP, +} ili9341_vertical_refresh_t; + +/** Memory data access control: display data latch data order. */ +typedef enum { + /** LCD refresh left to right. */ + ILI9341_HORIZONTAL_REFRESH_LEFT_TO_RIGHT, + /** LCD refresh right to left. */ + ILI9341_HORIZONTAL_REFRESH_RIGHT_TO_LEFT, +} ili9341_horizontal_refresh_t; + +/** + * Configuration + * ============= + */ + +/** + * Configuration for :c:data:`ili9341`. + * + * :See also: :c:func:`eglib_Init`. + */ +typedef struct { + /** Display width. */ + coordinate_t width; + /** Display height. */ + coordinate_t height; + /** Display color depth. */ + ili9341_color_t color : 2; + /** Page address order. */ + ili9341_page_address_t page_address : 1; + /** Column address order. */ + ili9341_colum_address_t colum_address : 1; + /** Page/column order. */ + ili9341_page_colum_order_t page_column_order : 1; + /** Vertical refresh direction. */ + ili9341_vertical_refresh_t vertical_refresh : 1; + /** Horizontal refresh direction. */ + ili9341_horizontal_refresh_t horizontal_refresh : 1; +} ili9341_config_t; + +/** + * Driver + * ====== + */ + +/** + * ILI9341 display driver. + * + * This driver supports the following data buses: + * + * - 4-Wire SPI. + * + * :See also: :c:func:`eglib_Init`. + * :See also: `Datasheet `_. + */ +extern const display_t ili9341; + +/** + * Functions + * ========= + * + * These functions can be used exclusively with :c:type:`eglib_t` initialized + * with :c:data:`ili9341`. + */ + +/**Set display inversion on/off. */ +void ili9341_SetDisplayInversion(eglib_t *eglib, bool inversion); + +/** + * Set display idle mode on/off. + * + * When in idle on mode, colors are reduced to 8. + */ +void ili9341_SetIdleMode(eglib_t *eglib, bool idle); + +#endif diff --git a/eglib/hal/four_wire_spi/esp32/esp32_ili9341.cpp b/eglib/hal/four_wire_spi/esp32/esp32_ili9341.cpp new file mode 100644 index 00000000..bb006902 --- /dev/null +++ b/eglib/hal/four_wire_spi/esp32/esp32_ili9341.cpp @@ -0,0 +1,97 @@ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "SPI.h" +#include "driver/gpio.h" +#include + +extern "C" { +#include "esp32_ili9341.h" + +static esp32_hal_config_t *config; + +static void einit(eglib_t *eglib) { + ESP_LOGI("ILI9341","init()"); + config = (esp32_hal_config_t *)eglib_GetHalConfig(eglib); + // SPI.begin( config->gpio_scl, config->gpio_sdo, config->gpio_sda, config->gpio_cs ); // done already by sensors and CS handled in here + // init GPIO pins of 4 WIRE SPI bus + gpio_reset_pin(config->gpio_cs); + gpio_reset_pin(config->gpio_rs); + gpio_reset_pin(config->gpio_dc); + gpio_set_direction(config->gpio_cs, GPIO_MODE_OUTPUT); + gpio_set_direction(config->gpio_rs, GPIO_MODE_OUTPUT); + gpio_set_direction(config->gpio_dc, GPIO_MODE_OUTPUT); + // set default state for all output pins + gpio_set_level(config->gpio_rs, 1); + gpio_set_level(config->gpio_dc, 1 ); + gpio_set_level(config->gpio_cs, 1 ); + + // hal_four_wire_spi_config_t * fwc = eglib_GetHalFourWireSpiConfigComm(eglib); + SPI.setClockDivider( SPI_CLOCK_DIV2 ); +} + +static void esleep_in(eglib_t *_eglib) { + ESP_LOGI("ILI9341","sleep in"); + vTaskDelay( 120 / portTICK_PERIOD_MS); +} + +static void esleep_out(eglib_t *_eglib) { + ESP_LOGI("ILI9341","sleep out"); + vTaskDelay( 120 / portTICK_PERIOD_MS); +} + +static void edelay_ns(eglib_t *_eglib, uint32_t ns) { + ESP_LOGI("ILI9341","delay %d ms", ns/1000000 ); + vTaskDelay( (ns/1000000) / portTICK_PERIOD_MS); +} + +static void eset_reset(eglib_t *_eglib, bool state) { + ESP_LOGI("ILI9341","reset IO:%d state=%d", config->gpio_rs, state ); + gpio_set_level(config->gpio_rs, (unsigned int)state ); +} + +static bool eget_busy(eglib_t *_eglib) { + return false; +} + +static void ecomm_begin(eglib_t *_eglib) { + // ESP_LOGI("ILI9341", "comm begin(): eglib:%x config:%x CS-PIN:%d", (unsigned int)_eglib, (unsigned int)config, (unsigned int)config->gpio_cs ); + gpio_set_level(config->gpio_cs, 0 ); + SPI.beginTransaction(SPISettings( config->freq, config->bitOrder, config->dataMode )); // *3 +} + +void esend( + eglib_t *_eglib, + enum hal_dc_t dc, + uint8_t *bytes, + uint32_t length ) +{ + // ESP_LOGI("ILI9341", "esend() DC-IO:%d dc:%s len:%d\n",config->gpio_dc, dc?"DAT":"CMD", length ); + // ESP_LOG_BUFFER_HEXDUMP("ILI9341", bytes, length, ESP_LOG_INFO); + if( dc == HAL_DATA ){ + gpio_set_level(config->gpio_dc, 1 ); + } + else{ + gpio_set_level(config->gpio_dc, 0 ); + } + SPI.transfer( bytes, length ); +} + +static void ecomm_end(eglib_t *_eglib) { + // ESP_LOGI("ILI9341","comm end()"); + SPI.endTransaction(); + gpio_set_level(config->gpio_cs, 1 ); +} + +hal_t esp32_ili9341 = { + .init = einit, + .sleep_in = esleep_in, + .sleep_out = esleep_out, + .delay_ns = edelay_ns, + .set_reset = eset_reset, + .get_busy = eget_busy, + .comm_begin = ecomm_begin, + .send = esend, + .comm_end = ecomm_end, +}; +} diff --git a/eglib/hal/four_wire_spi/esp32/esp32_ili9341.h b/eglib/hal/four_wire_spi/esp32/esp32_ili9341.h new file mode 100644 index 00000000..b0065a73 --- /dev/null +++ b/eglib/hal/four_wire_spi/esp32/esp32_ili9341.h @@ -0,0 +1,34 @@ +#pragma once + +/** + * Driver + * ====== + */ + +/** + * 4-Wire SPI HAL driver for ESP32 ILI9341 four wire SPI IPS display module + * + * + * :See also: :c:func:`eglib_Init`. + */ + + +#include "hal.h" +#include "driver/gpio.h" + +extern hal_t esp32_ili9341; + +typedef struct esp32_hal_config{ + uint8_t spi_num; + uint32_t freq; + uint8_t dataMode; + uint8_t bitOrder; + gpio_num_t gpio_scl; + gpio_num_t gpio_sda; + gpio_num_t gpio_sdo; + gpio_num_t gpio_cs; + gpio_num_t gpio_dc; + gpio_num_t gpio_rs; +}esp32_hal_config_t; + +// void send( eglib_t *_eglib, enum hal_dc_t dc, uint8_t *bytes, uint32_t length ); From a1199a209b1e5fac95dd81f35561b9cc7e6edea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eckhard=20V=C3=B6llm?= Date: Sun, 21 Nov 2021 23:11:36 +0100 Subject: [PATCH 2/2] return cursor advance from eglib_DrawFilledWChar --- eglib/drawing.c | 5 +++-- eglib/drawing.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/eglib/drawing.c b/eglib/drawing.c index 626bad96..48c09c96 100644 --- a/eglib/drawing.c +++ b/eglib/drawing.c @@ -708,7 +708,7 @@ void eglib_DrawWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar_t uni } } -void eglib_DrawFilledWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar_t unicode_char) { +size_t eglib_DrawFilledWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar_t unicode_char) { color_channel_t old_r0, old_g0, old_b0; const struct font_t *font; const struct glyph_t *glyph; @@ -742,6 +742,7 @@ void eglib_DrawFilledWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar eglib_SetIndexColor(eglib, 0, old_r0, old_g0, old_b0); eglib_DrawGlyph(eglib, x, y, glyph); + return glyph->advance; } #define isutf(c) (((c)&0xC0)!=0x80) @@ -798,4 +799,4 @@ coordinate_t eglib_GetTextWidth(eglib_t *eglib, const char *utf8_text) { } return width; -} \ No newline at end of file +} diff --git a/eglib/drawing.h b/eglib/drawing.h index 694bb02c..b833f612 100644 --- a/eglib/drawing.h +++ b/eglib/drawing.h @@ -762,7 +762,7 @@ void eglib_DrawWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar_t uni * .. image:: eglib_DrawFilledWChar.png * :width: 200 */ -void eglib_DrawFilledWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar_t unicode_char); +size_t eglib_DrawFilledWChar(eglib_t *eglib, coordinate_t x, coordinate_t y, wchar_t unicode_char); /** * Draw given UTF-8 text starting at ``(x, y)``. @@ -802,4 +802,4 @@ void eglib_DrawText(eglib_t *eglib, coordinate_t x, coordinate_t y, const char * */ coordinate_t eglib_GetTextWidth(eglib_t *eglib, const char *utf8_text); -#endif \ No newline at end of file +#endif