1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-10-18 Meco Man The first version
9 * 2021-12-24 Rb Refresh using dma2d
10 */
11 #include <lvgl.h>
12
13 //#define DRV_DEBUG
14 #define LOG_TAG "LVGL.port.disp"
15 #include <drv_log.h>
16
17 #if LV_USE_NXP_SOC
18 #include "fsl_gpio.h"
19 #include "fsl_elcdif.h"
20 #include "fsl_cache.h"
21 #endif
22
23 /*A static or global variable to store the buffers*/
24 static lv_disp_draw_buf_t disp_buf;
25
26 static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
27
28 /* Macros for panel. */
29 #define LCD_FB_BYTE_PER_PIXEL 2
30 #define LCD_POL_FLAGS \
31 (kELCDIF_DataEnableActiveHigh | kELCDIF_VsyncActiveLow | kELCDIF_HsyncActiveLow | kELCDIF_DriveDataOnRisingClkEdge)
32 #define LCD_LCDIF_DATA_BUS kELCDIF_DataBus16Bit
33
34 /* Back light. */
35 #define LCD_BL_GPIO GPIO2
36 #define LCD_BL_GPIO_PIN 31
37
38 #define DEMO_FB_ALIGN LV_ATTRIBUTE_MEM_ALIGN_SIZE
39 #define DISP_BUF_SIZE (((LCD_WIDTH * LCD_HEIGHT * LCD_FB_BYTE_PER_PIXEL) + DEMO_FB_ALIGN - 1) & ~(DEMO_FB_ALIGN - 1))
40
41 /*******************************************************************************
42 * Variables
43 ******************************************************************************/
44 static volatile bool s_framePending;
45
46 static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/
47
48 SDK_ALIGN(static uint8_t s_frameBuffer[2][DISP_BUF_SIZE], DEMO_FB_ALIGN);
49
50 static rt_sem_t s_frameSema = RT_NULL;
51
lcd_fb_flush(lv_disp_drv_t * disp_drv,const lv_area_t * area,lv_color_t * color_p)52 static void lcd_fb_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
53 {
54 rt_sem_take(s_frameSema, RT_WAITING_FOREVER);
55
56 DCACHE_CleanInvalidateByRange((uint32_t)color_p, DISP_BUF_SIZE);
57
58 ELCDIF_SetNextBufferAddr(LCDIF, (uint32_t)color_p);
59
60 s_framePending = true;
61 }
62
DEMO_InitLcdClock(void)63 static void DEMO_InitLcdClock(void)
64 {
65 /*
66 * The desired output frame rate is 60Hz. So the pixel clock frequency is:
67 * (480 + 41 + 4 + 18) * (272 + 10 + 4 + 2) * 60 = 9.2M.
68 * Here set the LCDIF pixel clock to 9.3M.
69 */
70
71 /*
72 * Initialize the Video PLL.
73 * Video PLL output clock is OSC24M * (loopDivider + (denominator / numerator)) / postDivider = 93MHz.
74 */
75 clock_video_pll_config_t config =
76 {
77 .loopDivider = 31,
78 .postDivider = 8,
79 .numerator = 0,
80 .denominator = 0,
81 };
82
83 CLOCK_InitVideoPll(&config);
84
85 /*
86 * 000 derive clock from PLL2
87 * 001 derive clock from PLL3 PFD3
88 * 010 derive clock from PLL5
89 * 011 derive clock from PLL2 PFD0
90 * 100 derive clock from PLL2 PFD1
91 * 101 derive clock from PLL3 PFD1
92 */
93 CLOCK_SetMux(kCLOCK_LcdifPreMux, 2);
94
95 CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 4);
96
97 CLOCK_SetDiv(kCLOCK_LcdifDiv, 1);
98 }
99
DEMO_InitLcdBackLight(void)100 static void DEMO_InitLcdBackLight(void)
101 {
102 const gpio_pin_config_t config =
103 {
104 kGPIO_DigitalOutput,
105 1,
106 kGPIO_NoIntmode,
107 };
108
109 /* Backlight. */
110 GPIO_PinInit(LCD_BL_GPIO, LCD_BL_GPIO_PIN, &config);
111 }
112
113 #if LV_USE_GPU_NXP_PXP
DEMO_CleanInvalidateCache(lv_disp_drv_t * disp_drv)114 static void DEMO_CleanInvalidateCache(lv_disp_drv_t *disp_drv)
115 {
116 SCB_CleanInvalidateDCache();
117 }
118 #endif
119
DEMO_InitLcd(void)120 static void DEMO_InitLcd(void)
121 {
122 /* Initialize the display. */
123 const elcdif_rgb_mode_config_t config =
124 {
125 .panelWidth = LCD_WIDTH,
126 .panelHeight = LCD_HEIGHT,
127 .hsw = LCD_HSW,
128 .hfp = LCD_HFP,
129 .hbp = LCD_HBP,
130 .vsw = LCD_VSW,
131 .vfp = LCD_VFP,
132 .vbp = LCD_VBP,
133 .polarityFlags = LCD_POL_FLAGS,
134 /* lvgl starts render in frame buffer 0, so show frame buffer 1 first. */
135 .bufferAddr = (uint32_t)s_frameBuffer[1],
136 .pixelFormat = kELCDIF_PixelFormatRGB565,
137 .dataBus = LCD_LCDIF_DATA_BUS,
138 };
139
140 /* Clear frame buffer. */
141 rt_memset((void *)s_frameBuffer, 0, sizeof(s_frameBuffer));
142
143 s_frameSema = rt_sem_create("lvgl_sem", 1, RT_IPC_FLAG_PRIO);
144
145 if (RT_NULL == s_frameSema)
146 {
147 rt_kprintf("lvgl semaphore create failed\r\n");
148 RT_ASSERT(0);
149 }
150
151 /* No frame pending. */
152 s_framePending = false;
153
154 NVIC_SetPriority(LCDIF_IRQn, 3);
155
156 DEMO_InitLcdClock();
157
158 ELCDIF_RgbModeInit(LCDIF, &config);
159
160 ELCDIF_EnableInterrupts(LCDIF, kELCDIF_CurFrameDoneInterruptEnable);
161
162 NVIC_EnableIRQ(LCDIF_IRQn);
163
164 ELCDIF_RgbModeStart(LCDIF);
165
166 DEMO_InitLcdBackLight();
167 }
168
LCDIF_IRQHandler(void)169 void LCDIF_IRQHandler(void)
170 {
171 rt_interrupt_enter();
172
173 uint32_t intStatus = ELCDIF_GetInterruptStatus(LCDIF);
174
175 ELCDIF_ClearInterruptStatus(LCDIF, intStatus);
176
177 if (s_framePending)
178 {
179 if (intStatus & kELCDIF_CurFrameDone)
180 {
181 /* IMPORTANT!!!
182 * Inform the graphics library that you are ready with the flushing*/
183 lv_disp_flush_ready(&disp_drv);
184
185 s_framePending = false;
186
187 rt_sem_release(s_frameSema);
188 }
189 }
190
191 rt_interrupt_leave();
192
193 SDK_ISR_EXIT_BARRIER;
194 }
195
lv_port_disp_init(void)196 void lv_port_disp_init(void)
197 {
198 lv_disp_draw_buf_init(&disp_buf, s_frameBuffer[0], s_frameBuffer[1], LCD_WIDTH * LCD_HEIGHT);
199
200 /*-------------------------
201 * Initialize your display
202 * -----------------------*/
203 DEMO_InitLcd();
204
205 /*-----------------------------------
206 * Register the display in LittlevGL
207 *----------------------------------*/
208
209 lv_disp_drv_init(&disp_drv); /*Basic initialization*/
210
211 /*Set up the functions to access to your display*/
212
213 /*Set the resolution of the display*/
214 disp_drv.hor_res = LCD_WIDTH;
215 disp_drv.ver_res = LCD_HEIGHT;
216
217 /*Used to copy the buffer's content to the display*/
218 disp_drv.flush_cb = lcd_fb_flush;
219
220 #if LV_USE_GPU_NXP_PXP
221 disp_drv.clean_dcache_cb = DEMO_CleanInvalidateCache;
222 #endif
223
224 /*Set a display buffer*/
225 disp_drv.draw_buf = &disp_buf;
226
227 /* Partial refresh */
228 disp_drv.full_refresh = 1;
229
230 /*Finally register the driver*/
231 lv_disp_drv_register(&disp_drv);
232 }
233