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