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