spi_master_example_main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /* SPI Master example
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "freertos/FreeRTOS.h"
  11. #include "freertos/task.h"
  12. #include "esp_system.h"
  13. #include "driver/spi_master.h"
  14. #include "soc/gpio_struct.h"
  15. #include "driver/gpio.h"
  16. /*
  17. This code displays some fancy graphics on the ILI9341-based 320x240 LCD on an ESP-WROVER_KIT board.
  18. It is not very fast, even when the SPI transfer itself happens at 8MHz and with DMA, because
  19. the rest of the code is not very optimized. Especially calculating the image line-by-line
  20. is inefficient; it would be quicker to send an entire screenful at once. This example does, however,
  21. demonstrate the use of both spi_device_transmit as well as spi_device_queue_trans/spi_device_get_trans_result
  22. as well as pre-transmit callbacks.
  23. Some info about the ILI9341: It has an C/D line, which is connected to a GPIO here. It expects this
  24. line to be low for a command and high for data. We use a pre-transmit callback here to control that
  25. line: every transaction has as the user-definable argument the needed state of the D/C line and just
  26. before the transaction is sent, the callback will set this line to the correct state.
  27. */
  28. #define PIN_NUM_MISO 25
  29. #define PIN_NUM_MOSI 23
  30. #define PIN_NUM_CLK 19
  31. #define PIN_NUM_CS 22
  32. #define PIN_NUM_DC 21
  33. #define PIN_NUM_RST 18
  34. #define PIN_NUM_BCKL 5
  35. /*
  36. The ILI9341 needs a bunch of command/argument values to be initialized. They are stored in this struct.
  37. */
  38. typedef struct {
  39. uint8_t cmd;
  40. uint8_t data[16];
  41. uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
  42. } ili_init_cmd_t;
  43. static const ili_init_cmd_t ili_init_cmds[]={
  44. {0xCF, {0x00, 0x83, 0X30}, 3},
  45. {0xED, {0x64, 0x03, 0X12, 0X81}, 4},
  46. {0xE8, {0x85, 0x01, 0x79}, 3},
  47. {0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
  48. {0xF7, {0x20}, 1},
  49. {0xEA, {0x00, 0x00}, 2},
  50. {0xC0, {0x26}, 1},
  51. {0xC1, {0x11}, 1},
  52. {0xC5, {0x35, 0x3E}, 2},
  53. {0xC7, {0xBE}, 1},
  54. {0x36, {0x28}, 1},
  55. {0x3A, {0x55}, 1},
  56. {0xB1, {0x00, 0x1B}, 2},
  57. {0xF2, {0x08}, 1},
  58. {0x26, {0x01}, 1},
  59. {0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0X87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15},
  60. {0XE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15},
  61. {0x2A, {0x00, 0x00, 0x00, 0xEF}, 4},
  62. {0x2B, {0x00, 0x00, 0x01, 0x3f}, 4},
  63. {0x2C, {0}, 0},
  64. {0xB7, {0x07}, 1},
  65. {0xB6, {0x0A, 0x82, 0x27, 0x00}, 4},
  66. {0x11, {0}, 0x80},
  67. {0x29, {0}, 0x80},
  68. {0, {0}, 0xff},
  69. };
  70. //Send a command to the ILI9341. Uses spi_device_transmit, which waits until the transfer is complete.
  71. void ili_cmd(spi_device_handle_t spi, const uint8_t cmd)
  72. {
  73. esp_err_t ret;
  74. spi_transaction_t t;
  75. memset(&t, 0, sizeof(t)); //Zero out the transaction
  76. t.length=8; //Command is 8 bits
  77. t.tx_buffer=&cmd; //The data is the cmd itself
  78. t.user=(void*)0; //D/C needs to be set to 0
  79. ret=spi_device_transmit(spi, &t); //Transmit!
  80. assert(ret==ESP_OK); //Should have had no issues.
  81. }
  82. //Send data to the ILI9341. Uses spi_device_transmit, which waits until the transfer is complete.
  83. void ili_data(spi_device_handle_t spi, const uint8_t *data, int len)
  84. {
  85. esp_err_t ret;
  86. spi_transaction_t t;
  87. if (len==0) return; //no need to send anything
  88. memset(&t, 0, sizeof(t)); //Zero out the transaction
  89. t.length=len*8; //Len is in bytes, transaction length is in bits.
  90. t.tx_buffer=data; //Data
  91. t.user=(void*)1; //D/C needs to be set to 1
  92. ret=spi_device_transmit(spi, &t); //Transmit!
  93. assert(ret==ESP_OK); //Should have had no issues.
  94. }
  95. //This function is called (in irq context!) just before a transmission starts. It will
  96. //set the D/C line to the value indicated in the user field.
  97. void ili_spi_pre_transfer_callback(spi_transaction_t *t)
  98. {
  99. int dc=(int)t->user;
  100. gpio_set_level(PIN_NUM_DC, dc);
  101. }
  102. //Initialize the display
  103. void ili_init(spi_device_handle_t spi)
  104. {
  105. int cmd=0;
  106. //Initialize non-SPI GPIOs
  107. gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT);
  108. gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT);
  109. gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT);
  110. //Reset the display
  111. gpio_set_level(PIN_NUM_RST, 0);
  112. vTaskDelay(100 / portTICK_RATE_MS);
  113. gpio_set_level(PIN_NUM_RST, 1);
  114. vTaskDelay(100 / portTICK_RATE_MS);
  115. //Send all the commands
  116. while (ili_init_cmds[cmd].databytes!=0xff) {
  117. ili_cmd(spi, ili_init_cmds[cmd].cmd);
  118. ili_data(spi, ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes&0x1F);
  119. if (ili_init_cmds[cmd].databytes&0x80) {
  120. vTaskDelay(100 / portTICK_RATE_MS);
  121. }
  122. cmd++;
  123. }
  124. ///Enable backlight
  125. gpio_set_level(PIN_NUM_BCKL, 0);
  126. }
  127. //To send a line we have to send a command, 2 data bytes, another command, 2 more data bytes and another command
  128. //before sending the line data itself; a total of 6 transactions. (We can't put all of this in just one transaction
  129. //because the D/C line needs to be toggled in the middle.)
  130. //This routine queues these commands up so they get sent as quickly as possible.
  131. static void send_line(spi_device_handle_t spi, int ypos, uint16_t *line)
  132. {
  133. esp_err_t ret;
  134. int x;
  135. //Transaction descriptors. Declared static so they're not allocated on the stack; we need this memory even when this
  136. //function is finished because the SPI driver needs access to it even while we're already calculating the next line.
  137. static spi_transaction_t trans[6];
  138. //In theory, it's better to initialize trans and data only once and hang on to the initialized
  139. //variables. We allocate them on the stack, so we need to re-init them each call.
  140. for (x=0; x<6; x++) {
  141. memset(&trans[x], 0, sizeof(spi_transaction_t));
  142. if ((x&1)==0) {
  143. //Even transfers are commands
  144. trans[x].length=8;
  145. trans[x].user=(void*)0;
  146. } else {
  147. //Odd transfers are data
  148. trans[x].length=8*4;
  149. trans[x].user=(void*)1;
  150. }
  151. trans[x].flags=SPI_TRANS_USE_TXDATA;
  152. }
  153. trans[0].tx_data[0]=0x2A; //Column Address Set
  154. trans[1].tx_data[0]=0; //Start Col High
  155. trans[1].tx_data[1]=0; //Start Col Low
  156. trans[1].tx_data[2]=(320)>>8; //End Col High
  157. trans[1].tx_data[3]=(320)&0xff; //End Col Low
  158. trans[2].tx_data[0]=0x2B; //Page address set
  159. trans[3].tx_data[0]=ypos>>8; //Start page high
  160. trans[3].tx_data[1]=ypos&0xff; //start page low
  161. trans[3].tx_data[2]=(ypos+1)>>8; //end page high
  162. trans[3].tx_data[3]=(ypos+1)&0xff; //end page low
  163. trans[4].tx_data[0]=0x2C; //memory write
  164. trans[5].tx_buffer=line; //finally send the line data
  165. trans[5].length=320*2*8; //Data length, in bits
  166. trans[5].flags=0; //undo SPI_TRANS_USE_TXDATA flag
  167. //Queue all transactions.
  168. for (x=0; x<6; x++) {
  169. ret=spi_device_queue_trans(spi, &trans[x], portMAX_DELAY);
  170. assert(ret==ESP_OK);
  171. }
  172. //When we are here, the SPI driver is busy (in the background) getting the transactions sent. That happens
  173. //mostly using DMA, so the CPU doesn't have much to do here. We're not going to wait for the transaction to
  174. //finish because we may as well spend the time calculating the next line. When that is done, we can call
  175. //send_line_finish, which will wait for the transfers to be done and check their status.
  176. }
  177. static void send_line_finish(spi_device_handle_t spi)
  178. {
  179. spi_transaction_t *rtrans;
  180. esp_err_t ret;
  181. //Wait for all 6 transactions to be done and get back the results.
  182. for (int x=0; x<6; x++) {
  183. ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
  184. assert(ret==ESP_OK);
  185. //We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though.
  186. }
  187. }
  188. //Simple routine to generate some patterns and send them to the LCD. Don't expect anything too
  189. //impressive. Because the SPI driver handles transactions in the background, we can calculate the next line
  190. //while the previous one is being sent.
  191. static void display_pretty_colors(spi_device_handle_t spi)
  192. {
  193. uint16_t line[2][320];
  194. int x, y, frame=0;
  195. //Indexes of the line currently being sent to the LCD and the line we're calculating.
  196. int sending_line=-1;
  197. int calc_line=0;
  198. while(1) {
  199. frame++;
  200. for (y=0; y<240; y++) {
  201. //Calculate a line.
  202. for (x=0; x<320; x++) {
  203. line[calc_line][x]=((x<<3)^(y<<3)^(frame+x*y));
  204. }
  205. //Finish up the sending process of the previous line, if any
  206. if (sending_line!=-1) send_line_finish(spi);
  207. //Swap sending_line and calc_line
  208. sending_line=calc_line;
  209. calc_line=(calc_line==1)?0:1;
  210. //Send the line we currently calculated.
  211. send_line(spi, y, line[sending_line]);
  212. //The line is queued up for sending now; the actual sending happens in the
  213. //background. We can go on to calculate the next line as long as we do not
  214. //touch line[sending_line]; the SPI sending process is still reading from that.
  215. }
  216. }
  217. }
  218. void app_main()
  219. {
  220. esp_err_t ret;
  221. spi_device_handle_t spi;
  222. spi_bus_config_t buscfg={
  223. .miso_io_num=PIN_NUM_MISO,
  224. .mosi_io_num=PIN_NUM_MOSI,
  225. .sclk_io_num=PIN_NUM_CLK,
  226. .quadwp_io_num=-1,
  227. .quadhd_io_num=-1
  228. };
  229. spi_device_interface_config_t devcfg={
  230. .clock_speed_hz=10000000, //Clock out at 10 MHz
  231. .mode=0, //SPI mode 0
  232. .spics_io_num=PIN_NUM_CS, //CS pin
  233. .queue_size=7, //We want to be able to queue 7 transactions at a time
  234. .pre_cb=ili_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
  235. };
  236. //Initialize the SPI bus
  237. ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
  238. assert(ret==ESP_OK);
  239. //Attach the LCD to the SPI bus
  240. ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
  241. assert(ret==ESP_OK);
  242. //Initialize the LCD
  243. ili_init(spi);
  244. //Go do nice stuff.
  245. display_pretty_colors(spi);
  246. }