drv_ili9486.c 9.6 KB

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