From ec5f642e8173f973a6c6c5b7fd80564091485f36 Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 3 Nov 2020 23:53:19 +0100 Subject: [PATCH] structure libary & code cleanup --- README.md | 4 +- main/.vscode/c_cpp_properties.json | 16 ++ main/Driver.c | 366 +++++++++++++++++++++++------ main/Driver.h | 10 +- main/Example_Main.c | 47 ++-- main/LCD.c | 211 ++++------------- main/LCD.h | 17 +- workspace.code-workspace | 3 + 8 files changed, 395 insertions(+), 279 deletions(-) create mode 100644 main/.vscode/c_cpp_properties.json create mode 100644 workspace.code-workspace diff --git a/README.md b/README.md index 1bde722..a413eb8 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # ESP32-WROVER-KIT-LCD-DRIVER -LCD Driver for ST7789V used ESP32-WROVER-KIT V4.1 +LCD Driver for ST7789V/ILI9341 used ESP32-WROVER-KIT V4.1 ## WIP Using parts from: https://github.com/Everlers/demo_esp_lcd_st7789v -https://github.com/espressif/esp-idf/blob/master/examples/peripherals/spi_master/lcd \ No newline at end of file +https://github.com/espressif/esp-idf/blob/master/examples/peripherals/spi_master/lcd diff --git a/main/.vscode/c_cpp_properties.json b/main/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..88f7c97 --- /dev/null +++ b/main/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/usr/bin/clang", + "cStandard": "c11", + "cppStandard": "c++14", + "intelliSenseMode": "clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/main/Driver.c b/main/Driver.c index d6e917a..52a5c27 100644 --- a/main/Driver.c +++ b/main/Driver.c @@ -1,6 +1,6 @@ /*! @file Driver.c - @brief + @brief write the Framebuffer @author Hendrik Schutter @version V1.0 @date 03.11.2020 @@ -10,6 +10,20 @@ #include "Driver.h" +spi_device_handle_t spi; //SPI + +uint16_t *lines[2]; +int16_t sending_line=-1; +int16_t calc_line=0; + +uint32_t vDriver_GetId(void); +static esp_err_t iDriver_sendLineFinish(void); +void vDriver_spiPreTransferCallback(spi_transaction_t *t); +esp_err_t iDriver_sendCmd(const uint8_t u8Cmd); +static esp_err_t iDriver_sendLines(uint16_t u16Ypos, uint16_t *pu16Linedata); +esp_err_t iDriver_SendData(const uint8_t *pu8Data, uint16_t u16Len); +void vDriver_getFramenufferPerLine(uint16_t *pu16Dest, uint16_t u16Line, uint16_t u16Linect, uint16_t ***pu16Framebuffer); + //Place data into DRAM. Constant data gets placed into DROM by default, which is not accessible by DMA. DRAM_ATTR static const lcd_init_cmd_t st_init_cmds[]= { /* Memory Data Access Control, MX=MV=1, MY=ML=MH=0, RGB=0 */ @@ -105,75 +119,46 @@ DRAM_ATTR static const lcd_init_cmd_t ili_init_cmds[]= { {0, {0}, 0xff}, }; - - -/* Send a command to the LCD. Uses spi_device_polling_transmit, which waits - * until the transfer is complete. - * - * Since command transactions are usually small, they are handled in polling - * mode for higher speed. The overhead of interrupt transactions is more than - * just waiting for the transaction to complete. +/** + * @fn esp_err_t vDriver_init(void) + * @brief Initialize the driver + * @param void + * @return esp error code + * @author Hendrik Schutter + * @date 3.11.2020 */ -void vDriver_cmd(spi_device_handle_t spi, const uint8_t cmd) +esp_err_t vDriver_init(void) { - esp_err_t ret; - spi_transaction_t t; - memset(&t, 0, sizeof(t)); //Zero out the transaction - t.length=8; //Command is 8 bits - t.tx_buffer=&cmd; //The data is the cmd itself - t.user=(void*)0; //D/C needs to be set to 0 - ret=spi_device_polling_transmit(spi, &t); //Transmit! - assert(ret==ESP_OK); //Should have had no issues. -} + esp_err_t ret; //store esp error code -/* Send data to the LCD. Uses spi_device_polling_transmit, which waits until the - * transfer is complete. - * - * Since data transactions are usually small, they are handled in polling - * mode for higher speed. The overhead of interrupt transactions is more than - * just waiting for the transaction to complete. - */ -void vDriver_data(spi_device_handle_t spi, const uint8_t *data, int len) -{ - esp_err_t ret; - spi_transaction_t t; - if (len==0) return; //no need to send anything - memset(&t, 0, sizeof(t)); //Zero out the transaction - t.length=len*8; //Len is in bytes, transaction length is in bits. - t.tx_buffer=data; //Data - t.user=(void*)1; //D/C needs to be set to 1 - ret=spi_device_polling_transmit(spi, &t); //Transmit! - assert(ret==ESP_OK); //Should have had no issues. -} + spi_bus_config_t buscfg= { + .miso_io_num=PIN_NUM_MISO, + .mosi_io_num=PIN_NUM_MOSI, + .sclk_io_num=PIN_NUM_CLK, + .quadwp_io_num=-1, + .quadhd_io_num=-1, + .max_transfer_sz=PARALLEL_LINES*320*2+8 + }; -//This function is called (in irq context!) just before a transmission starts. It will -//set the D/C line to the value indicated in the user field. -void vDriver_spi_pre_transfer_callback(spi_transaction_t *t) -{ - int dc=(int)t->user; - gpio_set_level(PIN_NUM_DC, dc); -} + spi_device_interface_config_t devcfg= { +#ifdef CONFIG_LCD_OVERCLOCK + .clock_speed_hz=26*1000*1000, //Clock out at 26 MHz +#else + .clock_speed_hz=10*1000*1000, //Clock out at 10 MHz +#endif + .mode=0, //SPI mode 0 + .spics_io_num=PIN_NUM_CS, //CS pin + .queue_size=7, //We want to be able to queue 7 transactions at a time + .pre_cb=vDriver_spiPreTransferCallback, //Specify pre-transfer callback to handle D/C line + }; -uint32_t vDriver_get_id(spi_device_handle_t spi) -{ - //get_id cmd - vDriver_cmd(spi, 0x04); + //Initialize the SPI bus + ret=spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN); + ESP_ERROR_CHECK(ret); + //Attach the LCD to the SPI bus + ret=spi_bus_add_device(LCD_HOST, &devcfg, &spi); + ESP_ERROR_CHECK(ret); - spi_transaction_t t; - memset(&t, 0, sizeof(t)); - t.length=8*3; - t.flags = SPI_TRANS_USE_RXDATA; - t.user = (void*)1; - - esp_err_t ret = spi_device_polling_transmit(spi, &t); - assert( ret == ESP_OK ); - - return *(uint32_t*)t.rx_data; -} - -//Initialize the display -void vDriver_init(spi_device_handle_t spi) -{ int cmd=0; const lcd_init_cmd_t* lcd_init_cmds; @@ -189,7 +174,7 @@ void vDriver_init(spi_device_handle_t spi) vTaskDelay(100 / portTICK_RATE_MS); //detect LCD type - uint32_t lcd_id = vDriver_get_id(spi); + uint32_t lcd_id = vDriver_GetId(); int lcd_detected_type = 0; int lcd_type; @@ -223,14 +208,261 @@ void vDriver_init(spi_device_handle_t spi) //Send all the commands while (lcd_init_cmds[cmd].databytes!=0xff) { - vDriver_cmd(spi, lcd_init_cmds[cmd].cmd); - vDriver_data(spi, lcd_init_cmds[cmd].data, lcd_init_cmds[cmd].databytes&0x1F); + ret = iDriver_sendCmd(lcd_init_cmds[cmd].cmd); + assert(ret==ESP_OK); + ret = iDriver_SendData(lcd_init_cmds[cmd].data, lcd_init_cmds[cmd].databytes&0x1F); if (lcd_init_cmds[cmd].databytes&0x80) { vTaskDelay(100 / portTICK_RATE_MS); } cmd++; } + //Allocate memory for the line buffers + for (int i=0; i<2; i++) { + lines[i]=heap_caps_malloc(320*PARALLEL_LINES*sizeof(uint16_t), MALLOC_CAP_DMA); + assert(lines[i]!=NULL); + } + ///Enable backlight gpio_set_level(PIN_NUM_BCKL, 0); + + return ret; } + +/** + * @fn void iDriver_sendCmd(const uint8_t u8Cmd) + * @brief Send a command to the LCD. + * @param const uint8_t u8Cmd + * @return esp error code + * @author Hendrik Schutter + * @date 3.11.2020 + * + * Send a command to the LCD. Uses spi_device_polling_transmit, which waits + * until the transfer is complete. + * + * Since command transactions are usually small, they are handled in polling + * mode for higher speed. The overhead of interrupt transactions is more than + * just waiting for the transaction to complete. + */ +esp_err_t iDriver_sendCmd(const uint8_t u8Cmd) +{ + esp_err_t ret; + spi_transaction_t t; + memset(&t, 0, sizeof(t)); //Zero out the transaction + t.length=8; //Command is 8 bits + t.tx_buffer=&u8Cmd; //The data is the cmd itself + t.user=(void*)0; //D/C needs to be set to 0 + ret=spi_device_polling_transmit(spi, &t); //Transmit! + assert(ret==ESP_OK); //Should have had no issues. + return ret; +} + +/** + * @fn esp_err_t iDriver_SendData(const uint8_t *pu8Data, uint16_t u16Len) + * @brief Send data to the LCD. + * @param const uint8_t *pu8Data + * @param uint16_t u16Len + * @return esp error code + * @author Hendrik Schutter + * @date 3.11.2020 + * + * Send data to the LCD. Uses spi_device_polling_transmit, which waits until the + * transfer is complete. + * + * Since data transactions are usually small, they are handled in polling + * mode for higher speed. The overhead of interrupt transactions is more than + * just waiting for the transaction to complete. + */ +esp_err_t iDriver_SendData(const uint8_t *pu8Data, uint16_t u16Len) +{ + esp_err_t ret; + spi_transaction_t t; + if (u16Len==0) return ESP_FAIL; //no need to send anything + memset(&t, 0, sizeof(t)); //Zero out the transaction + t.length=u16Len*8; //Len is in bytes, transaction length is in bits. + t.tx_buffer=pu8Data; //Data + t.user=(void*)1; //D/C needs to be set to 1 + ret=spi_device_polling_transmit(spi, &t); //Transmit! + return ret; +} + +/** + * @fn void vDriver_spiPreTransferCallback(spi_transaction_t *t) + * @brief Pre Transfer Callback + * @param spi_transaction_t *t + * @return void + * @author Hendrik Schutter + * @date 3.11.2020 + * + * This function is called (in irq context!) just before a transmission starts. It will + * set the D/C line to the value indicated in the user field. + */ +void vDriver_spiPreTransferCallback(spi_transaction_t *t) +{ + int dc=(int)t->user; + gpio_set_level(PIN_NUM_DC, dc); +} + +/** + * @fn uint32_t vDriver_GetId(void) + * @brief get LCD driver chip id + * @param void + * @return uint32_t + * @author Hendrik Schutter + * @date 3.11.2020 + */ +uint32_t vDriver_GetId(void) +{ + esp_err_t ret; + //get_id cmd + ret = iDriver_sendCmd(0x04); + assert(ret==ESP_OK); + + spi_transaction_t t; + memset(&t, 0, sizeof(t)); + t.length=8*3; + t.flags = SPI_TRANS_USE_RXDATA; + t.user = (void*)1; + + ret = spi_device_polling_transmit(spi, &t); + assert( ret == ESP_OK ); + + return *(uint32_t*)t.rx_data; +} + +/** + * @fn esp_err_t iDriver_writeFramebuffer(uint16_t ***pu16Framebuffer) + * @brief write framebuffer to LCD via SPI + * @param uint16_t ***pu16Framebuffer + * @return esp error code + * @author Hendrik Schutter + * @date 3.11.2020 + */ +esp_err_t iDriver_writeFramebuffer(uint16_t ***pu16Framebuffer) +{ + esp_err_t ret; + for (int y=0; y<240; y+=PARALLEL_LINES) { + vDriver_getFramenufferPerLine(lines[calc_line], y, PARALLEL_LINES, pu16Framebuffer); + //Finish up the sending process of the previous line, if any + if (sending_line!=-1) + { + ret = iDriver_sendLineFinish(); + } + //Swap sending_line and calc_line + sending_line=calc_line; + calc_line=(calc_line==1)?0:1; + //Send the line we currently calculated. + iDriver_sendLines(y, lines[sending_line]); + //The line set is queued up for sending now; the actual sending happens in the + //background. We can go on to calculate the next line set as long as we do not + //touch line[sending_line]; the SPI sending process is still reading from that. + } + return ret; +} + +/** + * @fn void vDriver_getFramenufferPerLine(uint16_t *pu16Dest, uint16_t u16Line, uint16_t u16Linect, uint16_t ***pu16Framebuffer) + * @brief Get the pixel data for a set of lines (with implied line size of 320) + * @param uint16_t *pu16Dest + * @param uint16_t u16Line + * @param uint16_t u16Linect + * @param uint16_t ***pu16Framebuffer + * @return void + * @author Hendrik Schutter + * @date 3.11.2020 + */ +void vDriver_getFramenufferPerLine(uint16_t *pu16Dest, uint16_t u16Line, uint16_t u16Linect, uint16_t ***pu16Framebuffer) +{ + for (uint16_t y=u16Line; y>8; //End Col High + trans[1].tx_data[3]=(320)&0xff; //End Col Low + trans[2].tx_data[0]=0x2B; //Page address set + trans[3].tx_data[0]=u16Ypos>>8; //Start page high + trans[3].tx_data[1]=u16Ypos&0xff; //start page low + trans[3].tx_data[2]=(u16Ypos+PARALLEL_LINES)>>8; //end page high + trans[3].tx_data[3]=(u16Ypos+PARALLEL_LINES)&0xff; //end page low + trans[4].tx_data[0]=0x2C; //memory write + trans[5].tx_buffer=pu16Linedata; //finally send the line data + trans[5].length=320*2*8*PARALLEL_LINES; //Data length, in bits + trans[5].flags=0; //undo SPI_TRANS_USE_TXDATA flag + + //Queue all transactions. + for (uint8_t x=0; x<6; x++) { + ret=spi_device_queue_trans(spi, &trans[x], portMAX_DELAY); + assert(ret==ESP_OK); + } + + //When we are here, the SPI driver is busy (in the background) getting the transactions sent. That happens + //mostly using DMA, so the CPU doesn't have much to do here. We're not going to wait for the transaction to + //finish because we may as well spend the time calculating the next line. When that is done, we can call + //send_line_finish, which will wait for the transfers to be done and check their status. + return ret; +} + +/** + * @fn static esp_err_t iDriver_sendLineFinish(void) + * @brief send finish after line + * @param void + * @return esp error code + * @author Hendrik Schutter + * @date 3.11.2020 + */ +static esp_err_t iDriver_sendLineFinish(void) +{ + spi_transaction_t *rtrans; + esp_err_t ret; + //Wait for all 6 transactions to be done and get back the results. + for (uint8_t x=0; x<6; x++) { + ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); + assert(ret==ESP_OK); + //We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though. + } + return ret; +} \ No newline at end of file diff --git a/main/Driver.h b/main/Driver.h index 4259f6a..a5cbd33 100644 --- a/main/Driver.h +++ b/main/Driver.h @@ -21,7 +21,6 @@ #include "freertos/task.h" -#ifdef CONFIG_IDF_TARGET_ESP32 #define LCD_HOST HSPI_HOST #define DMA_CHAN 2 @@ -33,7 +32,10 @@ #define PIN_NUM_DC 21 #define PIN_NUM_RST 18 #define PIN_NUM_BCKL 5 -#endif + +//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use, +//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this. +#define PARALLEL_LINES 16 /* The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct. @@ -51,7 +53,7 @@ typedef enum { } type_lcd_t; -void vDriver_init(spi_device_handle_t spi); +esp_err_t vDriver_init(void); +esp_err_t iDriver_writeFramebuffer(uint16_t ***pu16Framebuffer); -void vDriver_spi_pre_transfer_callback(spi_transaction_t *t); #endif /* __DRIVER_H */ diff --git a/main/Example_Main.c b/main/Example_Main.c index b5420c7..e0b0ae0 100644 --- a/main/Example_Main.c +++ b/main/Example_Main.c @@ -13,35 +13,38 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" - #include "LCD.h" +/** + * @fn void app_main(void) + * @brief main task + * @param void + * @return void + * @author Hendrik Schutter + * @date 3.11.2020 + */ void app_main(void) { printf("Hello World!\n"); - vLCD_init(); + iLCD_init(); - - while(1){ - - clear_framebuffer(COLOR_RED); - vTaskDelay(1000 / portTICK_RATE_MS); - - clear_framebuffer(COLOR_GREEN); - vTaskDelay(1000 / portTICK_RATE_MS); - - - clear_framebuffer(COLOR_BLUE); - vTaskDelay(1000 / portTICK_RATE_MS); - - clear_framebuffer(COLOR_WHITE); - vTaskDelay(1000 / portTICK_RATE_MS); - - clear_framebuffer(COLOR_BLACK); - vTaskDelay(1000 / portTICK_RATE_MS); - + while(1) { + iLCD_clearFramebuffer(COLOR_RED); + vTaskDelay(1000 / portTICK_RATE_MS); + + iLCD_clearFramebuffer(COLOR_GREEN); + vTaskDelay(1000 / portTICK_RATE_MS); + + iLCD_clearFramebuffer(COLOR_BLUE); + vTaskDelay(1000 / portTICK_RATE_MS); + + iLCD_clearFramebuffer(COLOR_WHITE); + vTaskDelay(1000 / portTICK_RATE_MS); + + iLCD_clearFramebuffer(COLOR_BLACK); + vTaskDelay(1000 / portTICK_RATE_MS); } - + printf("end\n"); } diff --git a/main/LCD.c b/main/LCD.c index 35cd14c..169b74e 100644 --- a/main/LCD.c +++ b/main/LCD.c @@ -1,161 +1,59 @@ /*! @file LCD.c - @brief + @brief sets and writes framebuffer @author Hendrik Schutter @version V1.0 @date 03.11.2020 -*/ - - -#include "LCD.h" -#include "Driver.h" - -/* - This code displays some fancy graphics on the 320x240 LCD on an ESP-WROVER_KIT board. - This example demonstrates the use of both spi_device_transmit as well as - spi_device_queue_trans/spi_device_get_trans_result and pre-transmit callbacks. + This code displays graphics on the 320x240 LCD on an ESP-WROVER_KIT board. Some info about the ILI9341/ST7789V: It has an C/D line, which is connected to a GPIO here. It expects this line to be low for a command and high for data. We use a pre-transmit callback here to control that line: every transaction has as the user-definable argument the needed state of the D/C line and just before the transaction is sent, the callback will set this line to the correct state. + */ -esp_err_t allocate_frame_buffer(uint16_t ***pPixels); -void write_framebuffer(spi_device_handle_t* spi); +#include "LCD.h" +#include "Driver.h" -uint16_t **pixels; //framebuffer -spi_device_handle_t spi; +esp_err_t iLCD_allocateFramebuffer(uint16_t ***pPixels); - uint16_t *lines[2]; - - - //Indexes of the line currently being sent to the LCD and the line we're calculating. - int sending_line=-1; - int calc_line=0; - -void vLCD_init(void) { +uint16_t **pu16Framebuffer; //framebuffer +/** + * @fn esp_err_t iLCD_init(void) + * @brief init + * @param void + * @return int + * @author Hendrik Schutter + * @date 3.11.2020 + */ +esp_err_t iLCD_init(void) { esp_err_t ret; - - spi_bus_config_t buscfg= { - .miso_io_num=PIN_NUM_MISO, - .mosi_io_num=PIN_NUM_MOSI, - .sclk_io_num=PIN_NUM_CLK, - .quadwp_io_num=-1, - .quadhd_io_num=-1, - .max_transfer_sz=PARALLEL_LINES*320*2+8 - }; - spi_device_interface_config_t devcfg= { -#ifdef CONFIG_LCD_OVERCLOCK - .clock_speed_hz=26*1000*1000, //Clock out at 26 MHz -#else - .clock_speed_hz=10*1000*1000, //Clock out at 10 MHz -#endif - .mode=0, //SPI mode 0 - .spics_io_num=PIN_NUM_CS, //CS pin - .queue_size=7, //We want to be able to queue 7 transactions at a time - .pre_cb=vDriver_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line - }; - //Initialize the SPI bus - ret=spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN); - ESP_ERROR_CHECK(ret); - //Attach the LCD to the SPI bus - ret=spi_bus_add_device(LCD_HOST, &devcfg, &spi); - ESP_ERROR_CHECK(ret); - //Initialize the LCD - vDriver_init(spi); + + //Initialize the Driver + vDriver_init(); //Initialize the framebuffer - ret=allocate_frame_buffer(&pixels); + ret= iLCD_allocateFramebuffer(&pu16Framebuffer); ESP_ERROR_CHECK(ret); - - - //Allocate memory for the pixel buffers - for (int i=0; i<2; i++) { - lines[i]=heap_caps_malloc(320*PARALLEL_LINES*sizeof(uint16_t), MALLOC_CAP_DMA); - assert(lines[i]!=NULL); - } + return ret; } -/* To send a set of lines we have to send a command, 2 data bytes, another command, 2 more data bytes and another command - * before sending the line data itself; a total of 6 transactions. (We can't put all of this in just one transaction - * because the D/C line needs to be toggled in the middle.) - * This routine queues these commands up as interrupt transactions so they get - * sent faster (compared to calling spi_device_transmit several times), and at - * the mean while the lines for next transactions can get calculated. +/** + * @fn esp_err_t iLCD_allocateFramebuffer(uint16_t ***pPixels) + * @brief allocate framebuffer + * @param pointer of framebuffer two dimensional array + * @return esp error code + * @author Hendrik Schutter + * @date 3.11.2020 */ -static void send_lines(spi_device_handle_t spi, int ypos, uint16_t *linedata) -{ - esp_err_t ret; - int x; - //Transaction descriptors. Declared static so they're not allocated on the stack; we need this memory even when this - //function is finished because the SPI driver needs access to it even while we're already calculating the next line. - static spi_transaction_t trans[6]; - - //In theory, it's better to initialize trans and data only once and hang on to the initialized - //variables. We allocate them on the stack, so we need to re-init them each call. - for (x=0; x<6; x++) { - memset(&trans[x], 0, sizeof(spi_transaction_t)); - if ((x&1)==0) { - //Even transfers are commands - trans[x].length=8; - trans[x].user=(void*)0; - } else { - //Odd transfers are data - trans[x].length=8*4; - trans[x].user=(void*)1; - } - trans[x].flags=SPI_TRANS_USE_TXDATA; - } - trans[0].tx_data[0]=0x2A; //Column Address Set - trans[1].tx_data[0]=0; //Start Col High - trans[1].tx_data[1]=0; //Start Col Low - trans[1].tx_data[2]=(320)>>8; //End Col High - trans[1].tx_data[3]=(320)&0xff; //End Col Low - trans[2].tx_data[0]=0x2B; //Page address set - trans[3].tx_data[0]=ypos>>8; //Start page high - trans[3].tx_data[1]=ypos&0xff; //start page low - trans[3].tx_data[2]=(ypos+PARALLEL_LINES)>>8; //end page high - trans[3].tx_data[3]=(ypos+PARALLEL_LINES)&0xff; //end page low - trans[4].tx_data[0]=0x2C; //memory write - trans[5].tx_buffer=linedata; //finally send the line data - trans[5].length=320*2*8*PARALLEL_LINES; //Data length, in bits - trans[5].flags=0; //undo SPI_TRANS_USE_TXDATA flag - - //Queue all transactions. - for (x=0; x<6; x++) { - ret=spi_device_queue_trans(spi, &trans[x], portMAX_DELAY); - assert(ret==ESP_OK); - } - - //When we are here, the SPI driver is busy (in the background) getting the transactions sent. That happens - //mostly using DMA, so the CPU doesn't have much to do here. We're not going to wait for the transaction to - //finish because we may as well spend the time calculating the next line. When that is done, we can call - //send_line_finish, which will wait for the transfers to be done and check their status. -} - - -static void send_line_finish(spi_device_handle_t spi) -{ - spi_transaction_t *rtrans; - esp_err_t ret; - //Wait for all 6 transactions to be done and get back the results. - for (int x=0; x<6; x++) { - ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); - assert(ret==ESP_OK); - //We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though. - } -} - - -esp_err_t allocate_frame_buffer(uint16_t ***pPixels) +esp_err_t iLCD_allocateFramebuffer(uint16_t ***pPixels) { *pPixels = NULL; esp_err_t ret = ESP_OK; - //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines. *pPixels = calloc(240, sizeof(uint16_t *)); if (*pPixels == NULL) { @@ -170,53 +68,24 @@ esp_err_t allocate_frame_buffer(uint16_t ***pPixels) } } return ret; -} //end fun - -//Calculate the pixel data for a set of lines (with implied line size of 320). Pixels go in dest, line is the Y-coordinate of the -//first line to be calculated, linect is the amount of lines to calculate. Frame increases by one every time the entire image -//is displayed; this is used to go to the next frame of animation. -void get_framenuffer_per_line(uint16_t *dest, int line, int linect) -{ - for (int y=line; y> 8) | (u16Color << 8); - pixels[y][x] = u16Color; + pu16Framebuffer[y][x] = u16Color; } } - - write_framebuffer(&spi); - -} - -void write_framebuffer(spi_device_handle_t* spi) { - - - for (int y=0; y<240; y+=PARALLEL_LINES) { - //Calculate a line. - get_framenuffer_per_line(lines[calc_line], y, PARALLEL_LINES); - //Finish up the sending process of the previous line, if any - if (sending_line!=-1) - { - send_line_finish(*spi); - } - //Swap sending_line and calc_line - sending_line=calc_line; - calc_line=(calc_line==1)?0:1; - //Send the line we currently calculated. - send_lines(*spi, y, lines[sending_line]); - //The line set is queued up for sending now; the actual sending happens in the - //background. We can go on to calculate the next line set as long as we do not - //touch line[sending_line]; the SPI sending process is still reading from that. - } + return iDriver_writeFramebuffer(&pu16Framebuffer); } diff --git a/main/LCD.h b/main/LCD.h index 4c670f5..822fa96 100644 --- a/main/LCD.h +++ b/main/LCD.h @@ -18,22 +18,13 @@ #include #include "esp_system.h" -#define COLOR_RED 0xF800 +#define COLOR_RED 0xF800 #define COLOR_GREEN 0x07E0 #define COLOR_BLUE 0x001F -#define COLOR_WHITE 0xFFFF +#define COLOR_WHITE 0xFFFF #define COLOR_BLACK 0x0000 - -//To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use, -//but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this. -#define PARALLEL_LINES 16 - - -void vLCD_init(void); -void clear_framebuffer(uint16_t u16Color); - - - +esp_err_t iLCD_init(void); +esp_err_t iLCD_clearFramebuffer(uint16_t u16Color); #endif /* __LCD_H */ diff --git a/workspace.code-workspace b/workspace.code-workspace new file mode 100644 index 0000000..d60dc64 --- /dev/null +++ b/workspace.code-workspace @@ -0,0 +1,3 @@ +{ + "folders": [] +} \ No newline at end of file