ili9341.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /**
  2. * Copyright (c) 2017 - 2019, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include "sdk_common.h"
  41. #if NRF_MODULE_ENABLED(ILI9341)
  42. #include "nrf_lcd.h"
  43. #include "nrf_drv_spi.h"
  44. #include "nrf_delay.h"
  45. #include "nrf_gpio.h"
  46. #include "boards.h"
  47. // Set of commands described in ILI9341 datasheet.
  48. #define ILI9341_NOP 0x00
  49. #define ILI9341_SWRESET 0x01
  50. #define ILI9341_RDDID 0x04
  51. #define ILI9341_RDDST 0x09
  52. #define ILI9341_SLPIN 0x10
  53. #define ILI9341_SLPOUT 0x11
  54. #define ILI9341_PTLON 0x12
  55. #define ILI9341_NORON 0x13
  56. #define ILI9341_RDMODE 0x0A
  57. #define ILI9341_RDMADCTL 0x0B
  58. #define ILI9341_RDPIXFMT 0x0C
  59. #define ILI9341_RDIMGFMT 0x0D
  60. #define ILI9341_RDSELFDIAG 0x0F
  61. #define ILI9341_INVOFF 0x20
  62. #define ILI9341_INVON 0x21
  63. #define ILI9341_GAMMASET 0x26
  64. #define ILI9341_DISPOFF 0x28
  65. #define ILI9341_DISPON 0x29
  66. #define ILI9341_CASET 0x2A
  67. #define ILI9341_PASET 0x2B
  68. #define ILI9341_RAMWR 0x2C
  69. #define ILI9341_RAMRD 0x2E
  70. #define ILI9341_PTLAR 0x30
  71. #define ILI9341_MADCTL 0x36
  72. #define ILI9341_PIXFMT 0x3A
  73. #define ILI9341_FRMCTR1 0xB1
  74. #define ILI9341_FRMCTR2 0xB2
  75. #define ILI9341_FRMCTR3 0xB3
  76. #define ILI9341_INVCTR 0xB4
  77. #define ILI9341_DFUNCTR 0xB6
  78. #define ILI9341_PWCTR1 0xC0
  79. #define ILI9341_PWCTR2 0xC1
  80. #define ILI9341_PWCTR3 0xC2
  81. #define ILI9341_PWCTR4 0xC3
  82. #define ILI9341_PWCTR5 0xC4
  83. #define ILI9341_VMCTR1 0xC5
  84. #define ILI9341_VMCTR2 0xC7
  85. #define ILI9341_PWCTRSEQ 0xCB
  86. #define ILI9341_PWCTRA 0xCD
  87. #define ILI9341_PWCTRB 0xCF
  88. #define ILI9341_RDID1 0xDA
  89. #define ILI9341_RDID2 0xDB
  90. #define ILI9341_RDID3 0xDC
  91. #define ILI9341_RDID4 0xDD
  92. #define ILI9341_GMCTRP1 0xE0
  93. #define ILI9341_GMCTRN1 0xE1
  94. #define ILI9341_DGMCTR1 0xE2
  95. #define ILI9341_DGMCTR2 0xE3
  96. #define ILI9341_TIMCTRA 0xE8
  97. #define ILI9341_TIMCTRB 0xEA
  98. #define ILI9341_ENGMCTR 0xF2
  99. #define ILI9341_INCTR 0xF6
  100. #define ILI9341_PUMP 0xF7
  101. #define ILI9341_MADCTL_MY 0x80
  102. #define ILI9341_MADCTL_MX 0x40
  103. #define ILI9341_MADCTL_MV 0x20
  104. #define ILI9341_MADCTL_ML 0x10
  105. #define ILI9341_MADCTL_RGB 0x00
  106. #define ILI9341_MADCTL_BGR 0x08
  107. #define ILI9341_MADCTL_MH 0x04
  108. static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(ILI9341_SPI_INSTANCE);
  109. static inline void spi_write(const void * data, size_t size)
  110. {
  111. APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data, size, NULL, 0));
  112. }
  113. static inline void write_command(uint8_t c)
  114. {
  115. nrf_gpio_pin_clear(ILI9341_DC_PIN);
  116. spi_write(&c, sizeof(c));
  117. }
  118. static inline void write_data(uint8_t c)
  119. {
  120. nrf_gpio_pin_set(ILI9341_DC_PIN);
  121. spi_write(&c, sizeof(c));
  122. }
  123. static void set_addr_window(uint16_t x_0, uint16_t y_0, uint16_t x_1, uint16_t y_1)
  124. {
  125. ASSERT(x_0 <= x_1);
  126. ASSERT(y_0 <= y_1);
  127. write_command(ILI9341_CASET);
  128. write_data(x_0 >> 8);
  129. write_data(x_0);
  130. write_data(x_1 >> 8);
  131. write_data(x_1);
  132. write_command(ILI9341_PASET);
  133. write_data(y_0 >> 8);
  134. write_data(y_0);
  135. write_data(y_1 >> 8);
  136. write_data(y_1);
  137. write_command(ILI9341_RAMWR);
  138. }
  139. static void command_list(void)
  140. {
  141. write_command(ILI9341_SWRESET);
  142. nrf_delay_ms(120);
  143. write_command(ILI9341_DISPOFF);
  144. nrf_delay_ms(120);
  145. write_command(ILI9341_PWCTRB);
  146. write_data(0x00);
  147. write_data(0XC1);
  148. write_data(0X30);
  149. write_command(ILI9341_TIMCTRA);
  150. write_data(0x85);
  151. write_data(0x00);
  152. write_data(0x78);
  153. write_command(ILI9341_PWCTRSEQ);
  154. write_data(0x39);
  155. write_data(0x2C);
  156. write_data(0x00);
  157. write_data(0x34);
  158. write_data(0x02);
  159. write_command(ILI9341_PUMP);
  160. write_data(0x20);
  161. write_command(ILI9341_TIMCTRB);
  162. write_data(0x00);
  163. write_data(0x00);
  164. write_command(ILI9341_PWCTR1);
  165. write_data(0x23);
  166. write_command(ILI9341_PWCTR2);
  167. write_data(0x10);
  168. write_command(ILI9341_VMCTR1);
  169. write_data(0x3e);
  170. write_data(0x28);
  171. write_command(ILI9341_VMCTR2);
  172. write_data(0x86);
  173. write_command(ILI9341_MADCTL);
  174. write_data(0x48);
  175. write_command(ILI9341_PIXFMT);
  176. write_data(0x55);
  177. write_command(ILI9341_FRMCTR1);
  178. write_data(0x00);
  179. write_data(0x18);
  180. write_command(ILI9341_DFUNCTR);
  181. write_data(0x08);
  182. write_data(0x82);
  183. write_data(0x27);
  184. write_command(ILI9341_ENGMCTR);
  185. write_data(0x00);
  186. write_command(ILI9341_GAMMASET);
  187. write_data(0x01);
  188. write_command(ILI9341_GMCTRP1);
  189. write_data(0x0F);
  190. write_data(0x31);
  191. write_data(0x2B);
  192. write_data(0x0C);
  193. write_data(0x0E);
  194. write_data(0x08);
  195. write_data(0x4E);
  196. write_data(0xF1);
  197. write_data(0x37);
  198. write_data(0x07);
  199. write_data(0x10);
  200. write_data(0x03);
  201. write_data(0x0E);
  202. write_data(0x09);
  203. write_data(0x00);
  204. write_command(ILI9341_GMCTRN1);
  205. write_data(0x00);
  206. write_data(0x0E);
  207. write_data(0x14);
  208. write_data(0x03);
  209. write_data(0x11);
  210. write_data(0x07);
  211. write_data(0x31);
  212. write_data(0xC1);
  213. write_data(0x48);
  214. write_data(0x08);
  215. write_data(0x0F);
  216. write_data(0x0C);
  217. write_data(0x31);
  218. write_data(0x36);
  219. write_data(0x0F);
  220. write_command(ILI9341_SLPOUT);
  221. nrf_delay_ms(120);
  222. write_command(ILI9341_DISPON);
  223. }
  224. static ret_code_t hardware_init(void)
  225. {
  226. ret_code_t err_code;
  227. nrf_gpio_cfg_output(ILI9341_DC_PIN);
  228. nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
  229. spi_config.sck_pin = ILI9341_SCK_PIN;
  230. spi_config.miso_pin = ILI9341_MISO_PIN;
  231. spi_config.mosi_pin = ILI9341_MOSI_PIN;
  232. spi_config.ss_pin = ILI9341_SS_PIN;
  233. err_code = nrf_drv_spi_init(&spi, &spi_config, NULL, NULL);
  234. return err_code;
  235. }
  236. static ret_code_t ili9341_init(void)
  237. {
  238. ret_code_t err_code;
  239. err_code = hardware_init();
  240. if (err_code != NRF_SUCCESS)
  241. {
  242. return err_code;
  243. }
  244. command_list();
  245. return err_code;
  246. }
  247. static void ili9341_uninit(void)
  248. {
  249. nrf_drv_spi_uninit(&spi);
  250. }
  251. static void ili9341_pixel_draw(uint16_t x, uint16_t y, uint32_t color)
  252. {
  253. set_addr_window(x, y, x, y);
  254. const uint8_t data[2] = {color >> 8, color};
  255. nrf_gpio_pin_set(ILI9341_DC_PIN);
  256. spi_write(data, sizeof(data));
  257. nrf_gpio_pin_clear(ILI9341_DC_PIN);
  258. }
  259. static void ili9341_rect_draw(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color)
  260. {
  261. set_addr_window(x, y, x + width - 1, y + height - 1);
  262. const uint8_t data[2] = {color >> 8, color};
  263. nrf_gpio_pin_set(ILI9341_DC_PIN);
  264. // Duff's device algorithm for optimizing loop.
  265. uint32_t i = (height * width + 7) / 8;
  266. /*lint -save -e525 -e616 -e646 */
  267. switch ((height * width) % 8) {
  268. case 0:
  269. do {
  270. spi_write(data, sizeof(data));
  271. case 7:
  272. spi_write(data, sizeof(data));
  273. case 6:
  274. spi_write(data, sizeof(data));
  275. case 5:
  276. spi_write(data, sizeof(data));
  277. case 4:
  278. spi_write(data, sizeof(data));
  279. case 3:
  280. spi_write(data, sizeof(data));
  281. case 2:
  282. spi_write(data, sizeof(data));
  283. case 1:
  284. spi_write(data, sizeof(data));
  285. } while (--i > 0);
  286. default:
  287. break;
  288. }
  289. /*lint -restore */
  290. nrf_gpio_pin_clear(ILI9341_DC_PIN);
  291. }
  292. static void ili9341_dummy_display(void)
  293. {
  294. /* No implementation needed. */
  295. }
  296. static void ili9341_rotation_set(nrf_lcd_rotation_t rotation)
  297. {
  298. write_command(ILI9341_MADCTL);
  299. switch (rotation) {
  300. case NRF_LCD_ROTATE_0:
  301. write_data(ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR);
  302. break;
  303. case NRF_LCD_ROTATE_90:
  304. write_data(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
  305. break;
  306. case NRF_LCD_ROTATE_180:
  307. write_data(ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR);
  308. break;
  309. case NRF_LCD_ROTATE_270:
  310. write_data(ILI9341_MADCTL_MX | ILI9341_MADCTL_MY | ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
  311. break;
  312. default:
  313. break;
  314. }
  315. }
  316. static void ili9341_display_invert(bool invert)
  317. {
  318. write_command(invert ? ILI9341_INVON : ILI9341_INVOFF);
  319. }
  320. static lcd_cb_t ili9341_cb = {
  321. .height = ILI9341_HEIGHT,
  322. .width = ILI9341_WIDTH
  323. };
  324. const nrf_lcd_t nrf_lcd_ili9341 = {
  325. .lcd_init = ili9341_init,
  326. .lcd_uninit = ili9341_uninit,
  327. .lcd_pixel_draw = ili9341_pixel_draw,
  328. .lcd_rect_draw = ili9341_rect_draw,
  329. .lcd_display = ili9341_dummy_display,
  330. .lcd_rotation_set = ili9341_rotation_set,
  331. .lcd_display_invert = ili9341_display_invert,
  332. .p_lcd_cb = &ili9341_cb
  333. };
  334. #endif // NRF_MODULE_ENABLED(ILI9341)