1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author         Notes
8  * 2020-11-08     bigmagic       first version
9  */
10 #include <rtthread.h>
11 #include <rtdevice.h>
12 
13 #include <raspi4.h>
14 #include <drv_spi.h>
15 #include "drv_ili9486.h"
16 
17 #ifdef USING_LCD_CONSOLE
18 #include "lcd_console.h"
19 #endif
20 
21 //http://www.lcdwiki.com/MHS-3.5inch_RPi_Display
22 #define LCD_DEVICE_NAME       ("spi0.0")
23 
24 #define LCD_SPI_SEND_FAST
25 //waveshare
26 #define LCD_SCREEN_WIDTH      (320)
27 #define LCD_SCREEN_HEIGHT     (480)
28 
29 #define LCD_RESET_PIN         (25)
30 #define LCD_RS_PIN            (24)
31 
32 #define LCD_SPI_FREQ_MAX      (125*1000*1000)
33 
34 uint16_t LCD_HEIGHT = LCD_SCREEN_HEIGHT;
35 uint16_t LCD_WIDTH  = LCD_SCREEN_WIDTH;
36 
37 #define SCREEN_VERTICAL_1           (0)
38 #define SCREEN_HORIZONTAL_1         (1)
39 #define SCREEN_VERTICAL_2           (2)
40 #define SCREEN_HORIZONTAL_2         (3)
41 
42 struct rt_semaphore lcd_spi_lock;
43 struct rt_semaphore lcd_lock;
44 
45 //rgb565 lcd buffer
46 uint16_t _lcd_buffer[LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT];
47 uint16_t send_buffer[LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT];
48 
49 static struct rt_spi_device *lcd_dev;
50 
send_cmd(void)51 static inline void send_cmd(void)
52 {
53     rt_pin_write(LCD_RS_PIN, PIN_LOW);
54 }
55 
send_data(void)56 static inline void send_data(void)
57 {
58     rt_pin_write(LCD_RS_PIN, PIN_HIGH);
59 }
60 
writeData16(rt_uint16_t data)61 void writeData16(rt_uint16_t data)
62 {
63     rt_uint8_t send_data[2];
64     send_data[1] = data & 0x00FF;
65     send_data[0] = ((data >> 8) & 0x00FF);
66     rt_spi_transfer(lcd_dev, &send_data[0], RT_NULL, 2);
67 }
68 
writeData(void * dev,rt_uint8_t data)69 void writeData(void* dev,rt_uint8_t data)
70 {
71     writeData16((rt_uint16_t)(data));
72 }
73 
writeCommand(void * dev,rt_uint8_t cmd)74 void writeCommand(void* dev, rt_uint8_t cmd)
75 {
76     send_cmd();
77     writeData16((rt_uint16_t)(cmd));
78     send_data();
79 }
80 
lcd_write_commmand(rt_uint8_t cmd)81 void lcd_write_commmand(rt_uint8_t cmd)
82 {
83     writeCommand(lcd_dev, cmd);
84 }
85 
lcd_write_data(rt_uint8_t data)86 void lcd_write_data(rt_uint8_t data)
87 {
88     writeData(lcd_dev, data);
89 }
90 
91 /*Ser rotation of the screen - changes x0 and y0*/
lcd_set_rotation(uint8_t rotation)92 static inline void lcd_set_rotation(uint8_t rotation)
93 {
94     writeCommand(lcd_dev, 0x36);
95     rt_thread_mdelay(100);
96 
97     switch(rotation) {
98         case SCREEN_VERTICAL_1:
99             writeData(lcd_dev, 0x48);
100             LCD_WIDTH  = 320;
101             LCD_HEIGHT = 480;
102             break;
103         case SCREEN_HORIZONTAL_1:
104             writeData(lcd_dev, 0x28);
105             LCD_WIDTH  = 480;
106             LCD_HEIGHT = 320;
107             break;
108         case SCREEN_VERTICAL_2:
109             writeData(lcd_dev, 0x98);
110             LCD_WIDTH  = 320;
111             LCD_HEIGHT = 480;
112             break;
113         case SCREEN_HORIZONTAL_2:
114             writeData(lcd_dev, 0xF8);
115             LCD_WIDTH  = 480;
116             LCD_HEIGHT = 320;
117             break;
118         default:
119             //EXIT IF SCREEN ROTATION NOT VALID!
120             break;
121     }
122 
123     if((rotation == SCREEN_VERTICAL_1) || (rotation == SCREEN_VERTICAL_2))
124     {
125         lcd_write_commmand(0x2A);
126         lcd_write_data(0x00);
127         lcd_write_data(0x00);
128         lcd_write_data(0x01);
129         lcd_write_data(0x3F);
130 
131         lcd_write_commmand(0x2B);
132         lcd_write_data(0x00);
133         lcd_write_data(0x00);
134         lcd_write_data(0x01);
135         lcd_write_data(0xE0);
136     }
137 
138     if((rotation == SCREEN_HORIZONTAL_1) || (rotation == SCREEN_HORIZONTAL_2))
139     {
140         lcd_write_commmand(0x2B);
141         lcd_write_data(0x00);
142         lcd_write_data(0x00);
143         lcd_write_data(0x01);
144         lcd_write_data(0x3F);
145 
146         lcd_write_commmand(0x2A);
147         lcd_write_data(0x00);
148         lcd_write_data(0x00);
149         lcd_write_data(0x01);
150         lcd_write_data(0xE0);
151     }
152 }
153 
fast_send_data(void)154 static inline void fast_send_data(void)
155 {
156     rt_uint32_t ii = 0;
157     rt_uint32_t tx_index = 0;
158     char *tx_data = (char *)send_buffer;
159     rt_sem_take(&lcd_spi_lock, RT_WAITING_FOREVER);
160 
161     SPI_REG_CS(SPI_0_BASE) &= (~(3 << 0));
162     SPI_REG_CLK(SPI_0_BASE) = 4;
163     SPI_REG_CS(SPI_0_BASE) |= SPI_CS_TA;
164     for(tx_index=0;tx_index<(LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT) * 2;tx_index++)
165     {
166         for(ii = 0; ii < 32; ii = ii + 2)
167         {
168             SPI_REG_FIFO(SPI_0_BASE) = tx_data[tx_index + ii + 1];
169             SPI_REG_FIFO(SPI_0_BASE) = tx_data[tx_index + ii];
170         }
171         while (!(SPI_REG_CS(SPI_0_BASE) & SPI_CS_DONE));
172         SPI_REG_CS(SPI_0_BASE) |= (SPI_CS_CLEAR_TX) | (SPI_CS_CLEAR_RX);
173         tx_index = tx_index + 31;
174     }
175     SPI_REG_CS(SPI_0_BASE) |= (SPI_CS_CLEAR_TX) | (SPI_CS_CLEAR_RX);
176     SPI_REG_CS(SPI_0_BASE) &= (~SPI_CS_TA);
177     rt_sem_release(&lcd_spi_lock);
178 }
179 
lcd_show(void)180 static inline void lcd_show(void)
181 {
182 
183     lcd_write_commmand(0x2C); // Memory write?
184 
185     //rt_thread_mdelay(150);
186 
187 #ifdef LCD_SPI_SEND_FAST
188     fast_send_data();
189 #else
190     int i, j;
191     for (i = 0 ; i < 30  ; i ++)
192     {
193         uint16_t *tx_data = (uint16_t*)&send_buffer[5120* i];
194         int32_t data_sz = 5120;
195         for( j=0; j<data_sz; j++)
196         {
197             writeData16(tx_data[j]);
198         }
199     }
200 #endif
201 
202 }
203 
lcd_init(void)204 static void lcd_init(void)
205 {
206     writeCommand(lcd_dev, 0x28);
207     rt_thread_mdelay(150);
208 
209     writeCommand(lcd_dev, 0x3A);    // Interface Pixel Format
210     writeData(lcd_dev, 0x55);       // 16 bit/pixe
211 
212     writeCommand(lcd_dev, 0xC2);    // Interface Pixel Format
213     writeData(lcd_dev, 0x44);
214 
215     writeCommand(lcd_dev, 0xC5);     // VCOM Control
216     writeData(lcd_dev, 0x00);
217     writeData(lcd_dev, 0x00);
218     writeData(lcd_dev, 0x00);
219     writeData(lcd_dev, 0x00);
220 
221     writeCommand(lcd_dev, 0xE0);     // PGAMCTRL(Positive Gamma Control)
222     writeData(lcd_dev, 0x0F);
223     writeData(lcd_dev, 0x1F);
224     writeData(lcd_dev, 0x1C);
225     writeData(lcd_dev, 0x0C);
226     writeData(lcd_dev, 0x0F);
227     writeData(lcd_dev, 0x08);
228     writeData(lcd_dev, 0x48);
229     writeData(lcd_dev, 0x98);
230     writeData(lcd_dev, 0x37);
231     writeData(lcd_dev, 0x0A);
232     writeData(lcd_dev, 0x13);
233     writeData(lcd_dev, 0x04);
234     writeData(lcd_dev, 0x11);
235     writeData(lcd_dev, 0x0D);
236     writeData(lcd_dev, 0x00);
237 
238     writeCommand(lcd_dev, 0xE1);     // NGAMCTRL (Negative Gamma Correction)
239     writeData(lcd_dev, 0x0F);
240     writeData(lcd_dev, 0x32);
241     writeData(lcd_dev, 0x2E);
242     writeData(lcd_dev, 0x0B);
243     writeData(lcd_dev, 0x0D);
244     writeData(lcd_dev, 0x05);
245     writeData(lcd_dev, 0x47);
246     writeData(lcd_dev, 0x75);
247     writeData(lcd_dev, 0x37);
248     writeData(lcd_dev, 0x06);
249     writeData(lcd_dev, 0x10);
250     writeData(lcd_dev, 0x03);
251     writeData(lcd_dev, 0x24);
252     writeData(lcd_dev, 0x20);
253     writeData(lcd_dev, 0x00);
254 
255     writeCommand(lcd_dev, 0x11); // Sleep out, also SW reset
256     rt_thread_mdelay(150);
257 
258     writeCommand(lcd_dev, 0x20);   // Display Inversion OFF   RPi LCD (A)
259     //writeCommand(lcd_dev, 0x21); // Display Inversion ON    RPi LCD (B)
260 
261     lcd_set_rotation(SCREEN_VERTICAL_2);
262     writeCommand(lcd_dev, 0x29);   // Display ON
263     rt_thread_mdelay(150);
264 }
265 
lcd_reset(void)266 static inline void lcd_reset(void)
267 {
268     //Reset signal, low reset (pin22)
269     rt_pin_mode(LCD_RESET_PIN,PIN_MODE_OUTPUT);
270 
271     rt_pin_write(LCD_RESET_PIN, PIN_HIGH);
272     rt_thread_mdelay(100);
273     rt_pin_write(LCD_RESET_PIN, PIN_LOW);
274     rt_thread_mdelay(100);
275     rt_pin_write(LCD_RESET_PIN, PIN_HIGH);
276 }
277 
278 
ili9486_open(rt_device_t dev,rt_uint16_t oflag)279 rt_err_t ili9486_open(rt_device_t dev, rt_uint16_t oflag)
280 {
281     return RT_EOK;
282 }
283 
ili9486_close(rt_device_t dev)284 rt_err_t ili9486_close(rt_device_t dev)
285 {
286     return RT_EOK;
287 }
288 
ili9486_read(rt_device_t dev,rt_off_t pos,void * buf,rt_size_t size)289 rt_size_t ili9486_read(rt_device_t dev, rt_off_t pos, void *buf, rt_size_t size)
290 {
291     return 0;
292 }
293 
ili9486_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)294 rt_size_t ili9486_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
295 {
296 #ifdef USING_LCD_CONSOLE
297     fb_print((char*)buffer);
298 #endif
299     return size;
300 }
301 
ili9486_control(rt_device_t dev,int cmd,void * args)302 rt_err_t ili9486_control(rt_device_t dev, int cmd, void *args)
303 {
304     rt_sem_take(&lcd_lock, RT_WAITING_FOREVER);
305     switch (cmd)
306     {
307     case RTGRAPHIC_CTRL_RECT_UPDATE:
308         {
309             struct rt_device_rect_info *info = (struct rt_device_rect_info*)args;
310             info = info;
311             rt_memcpy(send_buffer, _lcd_buffer, LCD_SCREEN_WIDTH * LCD_SCREEN_HEIGHT * 2);
312             lcd_show();
313         }
314         break;
315 
316     case RTGRAPHIC_CTRL_GET_INFO:
317         {
318            struct rt_device_graphic_info* info = (struct rt_device_graphic_info*)args;
319 
320             RT_ASSERT(info != RT_NULL);
321             info->pixel_format  = RTGRAPHIC_PIXEL_FORMAT_RGB565;
322             info->bits_per_pixel= 16;
323             info->width         = LCD_WIDTH;
324             info->height        = LCD_HEIGHT;
325             info->framebuffer   = (void *)_lcd_buffer;//lcd->fb;
326         }
327         break;
328     }
329     rt_sem_release(&lcd_lock);
330     return RT_EOK;
331 }
332 
333 #ifdef RT_USING_DEVICE_OPS
334 const static struct rt_device_ops ili9486_ops =
335 {
336     RT_NULL,
337     ili9486_open,
338     ili9486_close,
339     ili9486_read,
340     ili9486_write,
341     ili9486_control,
342 };
343 #endif
344 
hw_ili9486_lcd_init(void)345 static int hw_ili9486_lcd_init(void)
346 {
347     struct rt_device *device;
348     device = rt_malloc(sizeof(struct rt_device));
349     rt_memset(device, 0, sizeof(struct rt_device));
350 
351     lcd_reset();
352     rt_pin_mode(LCD_RS_PIN, PIN_MODE_OUTPUT);
353     lcd_dev = (struct rt_spi_device *)rt_device_find(LCD_DEVICE_NAME);
354     if (!lcd_dev)
355     {
356         rt_kprintf("no %s!\n", LCD_DEVICE_NAME);
357     }
358     lcd_dev->config.max_hz = LCD_SPI_FREQ_MAX;//125M
359     lcd_init();
360 
361     rt_sem_init(&lcd_spi_lock, "lcd_spi_lock", 1, RT_IPC_FLAG_FIFO);
362     rt_sem_init(&lcd_lock, "lcd_spi_lock", 1, RT_IPC_FLAG_FIFO);
363      /* set device type */
364     device->type = RT_Device_Class_Graphic;
365     /* initialize device interface */
366 #ifdef RT_USING_DEVICE_OPS
367     device->ops = &ili9486_ops;
368 #else
369     device->init = RT_NULL;
370     device->open = ili9486_open;
371     device->close = ili9486_close;
372     device->read = ili9486_read;
373     device->write = ili9486_write;
374     device->control = ili9486_control;
375 #endif
376     /* register to device manager */
377     rt_device_register(device, "lcd", RT_DEVICE_FLAG_RDWR);
378 
379     return RT_EOK;
380 }
381 INIT_DEVICE_EXPORT(hw_ili9486_lcd_init);
382