1 /** 2 * @file lv_port_lcd_stm32_template.c 3 * 4 * Example implementation of the LVGL LCD display drivers on the STM32 platform 5 */ 6 7 /*Copy this file as "lv_port_disp.c" and set this value to "1" to enable content*/ 8 #if 0 9 10 /********************* 11 * INCLUDES 12 *********************/ 13 /* Include STM32Cube files here, e.g.: 14 #include "stm32f7xx_hal.h" 15 */ 16 17 #include "lv_port_disp.h" 18 #include "./src/drivers/display/st7789/lv_st7789.h" 19 20 /********************* 21 * DEFINES 22 *********************/ 23 #ifndef MY_DISP_HOR_RES 24 #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now. 25 #define MY_DISP_HOR_RES 320 26 #endif 27 28 #ifndef MY_DISP_VER_RES 29 #warning Please define or replace the macro MY_DISP_VER_RES with the actual screen height, default value 240 is used for now. 30 #define MY_DISP_VER_RES 240 31 #endif 32 33 #define BUS_SPI1_POLL_TIMEOUT 0x1000U 34 35 /********************** 36 * TYPEDEFS 37 **********************/ 38 39 /********************** 40 * STATIC PROTOTYPES 41 **********************/ 42 static void lcd_color_transfer_ready_cb(SPI_HandleTypeDef * hspi); 43 static int32_t lcd_io_init(void); 44 static void lcd_send_cmd(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, const uint8_t * param, 45 size_t param_size); 46 static void lcd_send_color(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, uint8_t * param, 47 size_t param_size); 48 49 /********************** 50 * STATIC VARIABLES 51 **********************/ 52 static lv_display_t * lcd_disp; 53 static volatile int lcd_bus_busy = 0; 54 55 /********************** 56 * MACROS 57 **********************/ 58 59 /********************** 60 * GLOBAL FUNCTIONS 61 **********************/ 62 63 void lv_port_display_init(void) 64 { 65 /* Initialize LCD I/O */ 66 if(lcd_io_init() != 0) 67 return; 68 69 /* Create the LVGL display object and the ST7789 LCD display driver */ 70 lcd_disp = lv_st7789_create(MY_DISP_HOR_RES, MY_DISP_VER_RES, LV_LCD_FLAG_NONE, lcd_send_cmd, lcd_send_color); 71 lv_display_set_rotation(lcd_disp, LV_DISPLAY_ROTATION_270); /* set landscape orientation */ 72 73 /* Example: two dynamically allocated buffers for partial rendering */ 74 uint8_t * buf1 = NULL; 75 uint8_t * buf2 = NULL; 76 77 uint32_t buf_size = MY_DISP_HOR_RES * MY_DISP_VER_RES / 10 * lv_color_format_get_size(lv_display_get_color_format( 78 lcd_disp)); 79 80 buf1 = lv_malloc(buf_size); 81 if(buf1 == NULL) { 82 LV_LOG_ERROR("display draw buffer malloc failed"); 83 return; 84 } 85 86 buf2 = lv_malloc(buf_size); 87 if(buf2 == NULL) { 88 LV_LOG_ERROR("display buffer malloc failed"); 89 lv_free(buf1); 90 return; 91 } 92 lv_display_set_buffers(lcd_disp, buf1, buf2, buf_size, LV_DISPLAY_RENDER_MODE_PARTIAL); 93 } 94 95 /********************** 96 * STATIC FUNCTIONS 97 **********************/ 98 99 /* Callback is called when background transfer finished */ 100 static void lcd_color_transfer_ready_cb(SPI_HandleTypeDef * hspi) 101 { 102 /* CS high */ 103 HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); 104 lcd_bus_busy = 0; 105 lv_display_flush_ready(lcd_disp); 106 } 107 108 /* Initialize LCD I/O bus, reset LCD */ 109 static int32_t lcd_io_init(void) 110 { 111 /* Register SPI Tx Complete Callback */ 112 HAL_SPI_RegisterCallback(&hspi1, HAL_SPI_TX_COMPLETE_CB_ID, lcd_color_transfer_ready_cb); 113 114 /* reset LCD */ 115 HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_RESET); 116 HAL_Delay(100); 117 HAL_GPIO_WritePin(LCD_RESET_GPIO_Port, LCD_RESET_Pin, GPIO_PIN_SET); 118 HAL_Delay(100); 119 120 HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); 121 HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); 122 123 return HAL_OK; 124 } 125 126 /* Platform-specific implementation of the LCD send command function. In general this should use polling transfer. */ 127 static void lcd_send_cmd(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, const uint8_t * param, 128 size_t param_size) 129 { 130 LV_UNUSED(disp); 131 while(lcd_bus_busy); /* wait until previous transfer is finished */ 132 /* Set the SPI in 8-bit mode */ 133 hspi1.Init.DataSize = SPI_DATASIZE_8BIT; 134 HAL_SPI_Init(&hspi1); 135 /* DCX low (command) */ 136 HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET); 137 /* CS low */ 138 HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); 139 /* send command */ 140 if(HAL_SPI_Transmit(&hspi1, cmd, cmd_size, BUS_SPI1_POLL_TIMEOUT) == HAL_OK) { 141 /* DCX high (data) */ 142 HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); 143 /* for short data blocks we use polling transfer */ 144 HAL_SPI_Transmit(&hspi1, (uint8_t *)param, (uint16_t)param_size, BUS_SPI1_POLL_TIMEOUT); 145 /* CS high */ 146 HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET); 147 } 148 } 149 150 /* Platform-specific implementation of the LCD send color function. For better performance this should use DMA transfer. 151 * In case of a DMA transfer a callback must be installed to notify LVGL about the end of the transfer. 152 */ 153 static void lcd_send_color(lv_display_t * disp, const uint8_t * cmd, size_t cmd_size, uint8_t * param, 154 size_t param_size) 155 { 156 LV_UNUSED(disp); 157 while(lcd_bus_busy); /* wait until previous transfer is finished */ 158 /* Set the SPI in 8-bit mode */ 159 hspi1.Init.DataSize = SPI_DATASIZE_8BIT; 160 HAL_SPI_Init(&hspi1); 161 /* DCX low (command) */ 162 HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_RESET); 163 /* CS low */ 164 HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET); 165 /* send command */ 166 if(HAL_SPI_Transmit(&hspi1, cmd, cmd_size, BUS_SPI1_POLL_TIMEOUT) == HAL_OK) { 167 /* DCX high (data) */ 168 HAL_GPIO_WritePin(LCD_DCX_GPIO_Port, LCD_DCX_Pin, GPIO_PIN_SET); 169 /* for color data use DMA transfer */ 170 /* Set the SPI in 16-bit mode to match endianness */ 171 hspi1.Init.DataSize = SPI_DATASIZE_16BIT; 172 HAL_SPI_Init(&hspi1); 173 lcd_bus_busy = 1; 174 HAL_SPI_Transmit_DMA(&hspi1, param, (uint16_t)param_size / 2); 175 /* NOTE: CS will be reset in the transfer ready callback */ 176 } 177 } 178 179 #else /*Enable this file at the top*/ 180 181 /*This dummy typedef exists purely to silence -Wpedantic.*/ 182 typedef int keep_pedantic_happy; 183 #endif 184