From e3ac4d806edc060902949b666c66ad3825614a58 Mon Sep 17 00:00:00 2001 From: SalimTerryLi Date: Wed, 8 Sep 2021 11:32:26 +0800 Subject: [PATCH] example/spi_master: bring back lcd example and clean up partially revert ac069bfca112b44ac0019743a37acc22fdc85ff9 --- .../peripherals/spi_master/lcd/CMakeLists.txt | 6 + examples/peripherals/spi_master/lcd/Makefile | 8 + examples/peripherals/spi_master/lcd/README.md | 41 ++ .../spi_master/lcd/main/CMakeLists.txt | 8 + .../spi_master/lcd/main/Kconfig.projbuild | 26 + .../spi_master/lcd/main/component.mk | 8 + .../spi_master/lcd/main/decode_image.c | 149 ++++++ .../spi_master/lcd/main/decode_image.h | 30 ++ .../peripherals/spi_master/lcd/main/image.jpg | Bin 0 -> 67106 bytes .../spi_master/lcd/main/pretty_effect.c | 60 +++ .../spi_master/lcd/main/pretty_effect.h | 38 ++ .../lcd/main/spi_master_example_main.c | 452 ++++++++++++++++++ 12 files changed, 826 insertions(+) create mode 100644 examples/peripherals/spi_master/lcd/CMakeLists.txt create mode 100644 examples/peripherals/spi_master/lcd/Makefile create mode 100644 examples/peripherals/spi_master/lcd/README.md create mode 100644 examples/peripherals/spi_master/lcd/main/CMakeLists.txt create mode 100644 examples/peripherals/spi_master/lcd/main/Kconfig.projbuild create mode 100644 examples/peripherals/spi_master/lcd/main/component.mk create mode 100644 examples/peripherals/spi_master/lcd/main/decode_image.c create mode 100644 examples/peripherals/spi_master/lcd/main/decode_image.h create mode 100644 examples/peripherals/spi_master/lcd/main/image.jpg create mode 100644 examples/peripherals/spi_master/lcd/main/pretty_effect.c create mode 100644 examples/peripherals/spi_master/lcd/main/pretty_effect.h create mode 100644 examples/peripherals/spi_master/lcd/main/spi_master_example_main.c diff --git a/examples/peripherals/spi_master/lcd/CMakeLists.txt b/examples/peripherals/spi_master/lcd/CMakeLists.txt new file mode 100644 index 0000000000..6494ac1fda --- /dev/null +++ b/examples/peripherals/spi_master/lcd/CMakeLists.txt @@ -0,0 +1,6 @@ +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(spi_master) diff --git a/examples/peripherals/spi_master/lcd/Makefile b/examples/peripherals/spi_master/lcd/Makefile new file mode 100644 index 0000000000..bb969cd5d3 --- /dev/null +++ b/examples/peripherals/spi_master/lcd/Makefile @@ -0,0 +1,8 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := spi_master + +include $(IDF_PATH)/make/project.mk diff --git a/examples/peripherals/spi_master/lcd/README.md b/examples/peripherals/spi_master/lcd/README.md new file mode 100644 index 0000000000..e848e1938c --- /dev/null +++ b/examples/peripherals/spi_master/lcd/README.md @@ -0,0 +1,41 @@ +# SPI Host Driver Example + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example aims to show how to use SPI Host driver API, like `spi_transaction_t` and spi_device_queue. + +If you are looking for code to drive LCDs in general, rather than code that uses the SPI master, that may be a better example to look at as it uses ESP-IDFs built-in LCD support rather than doing all the low-level work itself, which can be found at `examples/peripherals/lcd/tjpgd/` + +## How to Use Example + +### Hardware Required + +* An ESP development board, with SPI LCD + +Connection : + +Depends on boards. Refer to `spi_master_example_main.c` No wiring is required on ESP-WROVER-KIT + +### Build and Flash + +Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +On ESP-WROVER-KIT there will be: + +``` +LCD ID: 00000000 +ILI9341 detected. +LCD ILI9341 initialization. +``` + +At the meantime `ESP32` will be displayed on the connected LCD screen. + +## Troubleshooting + +For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. diff --git a/examples/peripherals/spi_master/lcd/main/CMakeLists.txt b/examples/peripherals/spi_master/lcd/main/CMakeLists.txt new file mode 100644 index 0000000000..0d34bee60e --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/CMakeLists.txt @@ -0,0 +1,8 @@ +set(srcs "pretty_effect.c" + "spi_master_example_main.c" + "decode_image.c" + ) + +idf_component_register(SRCS ${srcs} + INCLUDE_DIRS "." + EMBED_FILES image.jpg) diff --git a/examples/peripherals/spi_master/lcd/main/Kconfig.projbuild b/examples/peripherals/spi_master/lcd/main/Kconfig.projbuild new file mode 100644 index 0000000000..bab78fc6bf --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/Kconfig.projbuild @@ -0,0 +1,26 @@ +menu "Example Configuration" + + choice LCD_TYPE + prompt "LCD module type" + default LCD_TYPE_AUTO + help + The type of LCD on the evaluation board. + + config LCD_TYPE_AUTO + bool "Auto detect" + config LCD_TYPE_ST7789V + bool "ST7789V (WROVER Kit v2 or v3)" + config LCD_TYPE_ILI9341 + bool "ILI9341 (WROVER Kit v1 or DevKitJ v1)" + endchoice + + config LCD_OVERCLOCK + bool + prompt "Run LCD at higher clock speed than allowed" + default "n" + help + The ILI9341 and ST7789 specify that the maximum clock speed for the SPI interface is 10MHz. However, + in practice the driver chips work fine with a higher clock rate, and using that gives a better framerate. + Select this to try using the out-of-spec clock rate. + +endmenu diff --git a/examples/peripherals/spi_master/lcd/main/component.mk b/examples/peripherals/spi_master/lcd/main/component.mk new file mode 100644 index 0000000000..4ffe9e8ca2 --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/component.mk @@ -0,0 +1,8 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + + +#Compile image file into the resulting firmware binary +COMPONENT_EMBED_FILES := image.jpg diff --git a/examples/peripherals/spi_master/lcd/main/decode_image.c b/examples/peripherals/spi_master/lcd/main/decode_image.c new file mode 100644 index 0000000000..a9a460bc39 --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/decode_image.c @@ -0,0 +1,149 @@ +/* SPI Master example: jpeg decoder. + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +/* +The image used for the effect on the LCD in the SPI master example is stored in flash +as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG +decoder library to decode this JPEG into a format that can be sent to the display. + +Keep in mind that the decoder library cannot handle progressive files (will give +``Image decoder: jd_prepare failed (8)`` as an error) so make sure to save in the correct +format if you want to use a different image file. +*/ + +#include "decode_image.h" +#include "esp_rom_tjpgd.h" +#include "esp_log.h" +#include + +//Reference the binary-included jpeg file +extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); +extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); +//Define the height and width of the jpeg file. Make sure this matches the actual jpeg +//dimensions. +#define IMAGE_W 336 +#define IMAGE_H 256 + +const char *TAG = "ImageDec"; + +//Data that is passed from the decoder function to the infunc/outfunc functions. +typedef struct { + const unsigned char *inData; //Pointer to jpeg data + uint16_t inPos; //Current position in jpeg data + uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values + int outW; //Width of the resulting file + int outH; //Height of the resulting file +} JpegDev; + +//Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure. +static uint32_t infunc(esp_rom_tjpgd_dec_t *decoder, uint8_t *buf, uint32_t len) +{ + //Read bytes from input file + JpegDev *jd = (JpegDev *)decoder->device; + if (buf != NULL) { + memcpy(buf, jd->inData + jd->inPos, len); + } + jd->inPos += len; + return len; +} + +//Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and +//stores it in the outData array of the JpegDev structure. +static uint32_t outfunc(esp_rom_tjpgd_dec_t *decoder, void *bitmap, esp_rom_tjpgd_rect_t *rect) +{ + JpegDev *jd = (JpegDev *)decoder->device; + uint8_t *in = (uint8_t *)bitmap; + for (int y = rect->top; y <= rect->bottom; y++) { + for (int x = rect->left; x <= rect->right; x++) { + //We need to convert the 3 bytes in `in` to a rgb565 value. + uint16_t v = 0; + v |= ((in[0] >> 3) << 11); + v |= ((in[1] >> 2) << 5); + v |= ((in[2] >> 3) << 0); + //The LCD wants the 16-bit value in big-endian, so swap bytes + v = (v >> 8) | (v << 8); + jd->outData[y][x] = v; + in += 3; + } + } + return 1; +} + +//Size of the work space for the jpeg decoder. +#define WORKSZ 3100 + +//Decode the embedded image into pixel lines that can be used with the rest of the logic. +esp_err_t decode_image(uint16_t ***pixels) +{ + char *work = NULL; + int r; + esp_rom_tjpgd_dec_t decoder; + JpegDev jd; + *pixels = 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. + *pixels = calloc(IMAGE_H, sizeof(uint16_t *)); + if (*pixels == NULL) { + ESP_LOGE(TAG, "Error allocating memory for lines"); + ret = ESP_ERR_NO_MEM; + goto err; + } + for (int i = 0; i < IMAGE_H; i++) { + (*pixels)[i] = malloc(IMAGE_W * sizeof(uint16_t)); + if ((*pixels)[i] == NULL) { + ESP_LOGE(TAG, "Error allocating memory for line %d", i); + ret = ESP_ERR_NO_MEM; + goto err; + } + } + + //Allocate the work space for the jpeg decoder. + work = calloc(WORKSZ, 1); + if (work == NULL) { + ESP_LOGE(TAG, "Cannot allocate workspace"); + ret = ESP_ERR_NO_MEM; + goto err; + } + + //Populate fields of the JpegDev struct. + jd.inData = image_jpg_start; + jd.inPos = 0; + jd.outData = *pixels; + jd.outW = IMAGE_W; + jd.outH = IMAGE_H; + + //Prepare and decode the jpeg. + r = esp_rom_tjpgd_prepare(&decoder, infunc, work, WORKSZ, (void *)&jd); + if (r != JDR_OK) { + ESP_LOGE(TAG, "Image decoder: jd_prepare failed (%d)", r); + ret = ESP_ERR_NOT_SUPPORTED; + goto err; + } + r = esp_rom_tjpgd_decomp(&decoder, outfunc, 0); + if (r != JDR_OK && r != JDR_FMT1) { + ESP_LOGE(TAG, "Image decoder: jd_decode failed (%d)", r); + ret = ESP_ERR_NOT_SUPPORTED; + goto err; + } + + //All done! Free the work area (as we don't need it anymore) and return victoriously. + free(work); + return ret; +err: + //Something went wrong! Exit cleanly, de-allocating everything we allocated. + if (*pixels != NULL) { + for (int i = 0; i < IMAGE_H; i++) { + free((*pixels)[i]); + } + free(*pixels); + } + free(work); + return ret; +} diff --git a/examples/peripherals/spi_master/lcd/main/decode_image.h b/examples/peripherals/spi_master/lcd/main/decode_image.h new file mode 100644 index 0000000000..1e31e3d1cd --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/decode_image.h @@ -0,0 +1,30 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#pragma once +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Decode the jpeg ``image.jpg`` embedded into the program file into pixel data. + * + * @param pixels A pointer to a pointer for an array of rows, which themselves are an array of pixels. + * Effectively, you can get the pixel data by doing ``decode_image(&myPixels); pixelval=myPixels[ypos][xpos];`` + * @return - ESP_ERR_NOT_SUPPORTED if image is malformed or a progressive jpeg file + * - ESP_ERR_NO_MEM if out of memory + * - ESP_OK on succesful decode + */ +esp_err_t decode_image(uint16_t ***pixels); + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/spi_master/lcd/main/image.jpg b/examples/peripherals/spi_master/lcd/main/image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..803ca2cdca464f387a97af7042f9f4ed040a7f18 GIT binary patch literal 67106 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 literal 0 HcmV?d00001 diff --git a/examples/peripherals/spi_master/lcd/main/pretty_effect.c b/examples/peripherals/spi_master/lcd/main/pretty_effect.c new file mode 100644 index 0000000000..2923b7cf6f --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/pretty_effect.c @@ -0,0 +1,60 @@ +/* + This code generates an effect that should pass the 'fancy graphics' qualification + as set in the comment in the spi_master code. + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include "pretty_effect.h" +#include "sdkconfig.h" +#include "decode_image.h" + +uint16_t **pixels; + +//Grab a rgb16 pixel from the esp32_tiles image +static inline uint16_t get_bgnd_pixel(int x, int y) +{ + //Image has an 8x8 pixel margin, so we can also resolve e.g. [-3, 243] + x+=8; + y+=8; + return pixels[y][x]; +} +//This variable is used to detect the next frame. +static int prev_frame=-1; + +//Instead of calculating the offsets for each pixel we grab, we pre-calculate the valueswhenever a frame changes, then re-use +//these as we go through all the pixels in the frame. This is much, much faster. +static int8_t xofs[320], yofs[240]; +static int8_t xcomp[320], ycomp[240]; + +//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 pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect) +{ + if (frame!=prev_frame) { + //We need to calculate a new set of offset coefficients. Take some random sines as offsets to make everything + //look pretty and fluid-y. + for (int x=0; x<320; x++) xofs[x]=sin(frame*0.15+x*0.06)*4; + for (int y=0; y<240; y++) yofs[y]=sin(frame*0.1+y*0.05)*4; + for (int x=0; x<320; x++) xcomp[x]=sin(frame*0.11+x*0.12)*4; + for (int y=0; y<240; y++) ycomp[y]=sin(frame*0.07+y*0.15)*4; + prev_frame=frame; + } + for (int y=line; y +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @brief Calculate the effect for a bunch of lines. + * + * @param dest Destination for the pixels. Assumed to be LINECT * 320 16-bit pixel values. + * @param line Starting line of the chunk of lines. + * @param frame Current frame, used for animation + * @param linect Amount of lines to calculate + */ +void pretty_effect_calc_lines(uint16_t *dest, int line, int frame, int linect); + + +/** + * @brief Initialize the effect + * + * @return ESP_OK on success, an error from the jpeg decoder otherwise. + */ +esp_err_t pretty_effect_init(void); + +#ifdef __cplusplus +} +#endif diff --git a/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c b/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c new file mode 100644 index 0000000000..f25d0787f8 --- /dev/null +++ b/examples/peripherals/spi_master/lcd/main/spi_master_example_main.c @@ -0,0 +1,452 @@ +/* SPI Master example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_system.h" +#include "driver/spi_master.h" +#include "driver/gpio.h" + +#include "pretty_effect.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. + + 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. +*/ + +#ifdef CONFIG_IDF_TARGET_ESP32 +#define LCD_HOST HSPI_HOST + +#define PIN_NUM_MISO 25 +#define PIN_NUM_MOSI 23 +#define PIN_NUM_CLK 19 +#define PIN_NUM_CS 22 + +#define PIN_NUM_DC 21 +#define PIN_NUM_RST 18 +#define PIN_NUM_BCKL 5 +#elif defined CONFIG_IDF_TARGET_ESP32S2 +#define LCD_HOST SPI2_HOST + +#define PIN_NUM_MISO 37 +#define PIN_NUM_MOSI 35 +#define PIN_NUM_CLK 36 +#define PIN_NUM_CS 34 + +#define PIN_NUM_DC 4 +#define PIN_NUM_RST 5 +#define PIN_NUM_BCKL 6 +#elif defined CONFIG_IDF_TARGET_ESP32C3 +#define LCD_HOST SPI2_HOST + +#define PIN_NUM_MISO 2 +#define PIN_NUM_MOSI 7 +#define PIN_NUM_CLK 6 +#define PIN_NUM_CS 10 + +#define PIN_NUM_DC 9 +#define PIN_NUM_RST 4 +#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. +*/ +typedef struct { + uint8_t cmd; + uint8_t data[16]; + uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds. +} lcd_init_cmd_t; + +typedef enum { + LCD_TYPE_ILI = 1, + LCD_TYPE_ST, + LCD_TYPE_MAX, +} type_lcd_t; + +//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 */ + {0x36, {(1<<5)|(1<<6)}, 1}, + /* Interface Pixel Format, 16bits/pixel for RGB/MCU interface */ + {0x3A, {0x55}, 1}, + /* Porch Setting */ + {0xB2, {0x0c, 0x0c, 0x00, 0x33, 0x33}, 5}, + /* Gate Control, Vgh=13.65V, Vgl=-10.43V */ + {0xB7, {0x45}, 1}, + /* VCOM Setting, VCOM=1.175V */ + {0xBB, {0x2B}, 1}, + /* LCM Control, XOR: BGR, MX, MH */ + {0xC0, {0x2C}, 1}, + /* VDV and VRH Command Enable, enable=1 */ + {0xC2, {0x01, 0xff}, 2}, + /* VRH Set, Vap=4.4+... */ + {0xC3, {0x11}, 1}, + /* VDV Set, VDV=0 */ + {0xC4, {0x20}, 1}, + /* Frame Rate Control, 60Hz, inversion=0 */ + {0xC6, {0x0f}, 1}, + /* Power Control 1, AVDD=6.8V, AVCL=-4.8V, VDDS=2.3V */ + {0xD0, {0xA4, 0xA1}, 1}, + /* Positive Voltage Gamma Control */ + {0xE0, {0xD0, 0x00, 0x05, 0x0E, 0x15, 0x0D, 0x37, 0x43, 0x47, 0x09, 0x15, 0x12, 0x16, 0x19}, 14}, + /* Negative Voltage Gamma Control */ + {0xE1, {0xD0, 0x00, 0x05, 0x0D, 0x0C, 0x06, 0x2D, 0x44, 0x40, 0x0E, 0x1C, 0x18, 0x16, 0x19}, 14}, + /* Sleep Out */ + {0x11, {0}, 0x80}, + /* Display On */ + {0x29, {0}, 0x80}, + {0, {0}, 0xff} +}; + +DRAM_ATTR static const lcd_init_cmd_t ili_init_cmds[]={ + /* Power contorl B, power control = 0, DC_ENA = 1 */ + {0xCF, {0x00, 0x83, 0X30}, 3}, + /* Power on sequence control, + * cp1 keeps 1 frame, 1st frame enable + * vcl = 0, ddvdh=3, vgh=1, vgl=2 + * DDVDH_ENH=1 + */ + {0xED, {0x64, 0x03, 0X12, 0X81}, 4}, + /* Driver timing control A, + * non-overlap=default +1 + * EQ=default - 1, CR=default + * pre-charge=default - 1 + */ + {0xE8, {0x85, 0x01, 0x79}, 3}, + /* Power control A, Vcore=1.6V, DDVDH=5.6V */ + {0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5}, + /* Pump ratio control, DDVDH=2xVCl */ + {0xF7, {0x20}, 1}, + /* Driver timing control, all=0 unit */ + {0xEA, {0x00, 0x00}, 2}, + /* Power control 1, GVDD=4.75V */ + {0xC0, {0x26}, 1}, + /* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */ + {0xC1, {0x11}, 1}, + /* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */ + {0xC5, {0x35, 0x3E}, 2}, + /* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */ + {0xC7, {0xBE}, 1}, + /* Memory access contorl, MX=MY=0, MV=1, ML=0, BGR=1, MH=0 */ + {0x36, {0x28}, 1}, + /* Pixel format, 16bits/pixel for RGB/MCU interface */ + {0x3A, {0x55}, 1}, + /* Frame rate control, f=fosc, 70Hz fps */ + {0xB1, {0x00, 0x1B}, 2}, + /* Enable 3G, disabled */ + {0xF2, {0x08}, 1}, + /* Gamma set, curve 1 */ + {0x26, {0x01}, 1}, + /* Positive gamma correction */ + {0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0X87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15}, + /* Negative gamma correction */ + {0XE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15}, + /* Column address set, SC=0, EC=0xEF */ + {0x2A, {0x00, 0x00, 0x00, 0xEF}, 4}, + /* Page address set, SP=0, EP=0x013F */ + {0x2B, {0x00, 0x00, 0x01, 0x3f}, 4}, + /* Memory write */ + {0x2C, {0}, 0}, + /* Entry mode set, Low vol detect disabled, normal display */ + {0xB7, {0x07}, 1}, + /* Display function control */ + {0xB6, {0x0A, 0x82, 0x27, 0x00}, 4}, + /* Sleep out */ + {0x11, {0}, 0x80}, + /* Display on */ + {0x29, {0}, 0x80}, + {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. + */ +void lcd_cmd(spi_device_handle_t spi, const uint8_t cmd) +{ + 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. +} + +/* 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 lcd_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. +} + +//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 lcd_spi_pre_transfer_callback(spi_transaction_t *t) +{ + int dc=(int)t->user; + gpio_set_level(PIN_NUM_DC, dc); +} + +uint32_t lcd_get_id(spi_device_handle_t spi) +{ + //get_id cmd + lcd_cmd(spi, 0x04); + + 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 lcd_init(spi_device_handle_t spi) +{ + int cmd=0; + const lcd_init_cmd_t* lcd_init_cmds; + + //Initialize non-SPI GPIOs + gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT); + gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT); + + //Reset the display + gpio_set_level(PIN_NUM_RST, 0); + vTaskDelay(100 / portTICK_RATE_MS); + gpio_set_level(PIN_NUM_RST, 1); + vTaskDelay(100 / portTICK_RATE_MS); + + //detect LCD type + uint32_t lcd_id = lcd_get_id(spi); + int lcd_detected_type = 0; + int lcd_type; + + printf("LCD ID: %08X\n", lcd_id); + if ( lcd_id == 0 ) { + //zero, ili + lcd_detected_type = LCD_TYPE_ILI; + printf("ILI9341 detected.\n"); + } else { + // none-zero, ST + lcd_detected_type = LCD_TYPE_ST; + printf("ST7789V detected.\n"); + } + +#ifdef CONFIG_LCD_TYPE_AUTO + lcd_type = lcd_detected_type; +#elif defined( CONFIG_LCD_TYPE_ST7789V ) + printf("kconfig: force CONFIG_LCD_TYPE_ST7789V.\n"); + lcd_type = LCD_TYPE_ST; +#elif defined( CONFIG_LCD_TYPE_ILI9341 ) + printf("kconfig: force CONFIG_LCD_TYPE_ILI9341.\n"); + lcd_type = LCD_TYPE_ILI; +#endif + if ( lcd_type == LCD_TYPE_ST ) { + printf("LCD ST7789V initialization.\n"); + lcd_init_cmds = st_init_cmds; + } else { + printf("LCD ILI9341 initialization.\n"); + lcd_init_cmds = ili_init_cmds; + } + + //Send all the commands + while (lcd_init_cmds[cmd].databytes!=0xff) { + lcd_cmd(spi, lcd_init_cmds[cmd].cmd); + lcd_data(spi, lcd_init_cmds[cmd].data, lcd_init_cmds[cmd].databytes&0x1F); + if (lcd_init_cmds[cmd].databytes&0x80) { + vTaskDelay(100 / portTICK_RATE_MS); + } + cmd++; + } + + ///Enable backlight + gpio_set_level(PIN_NUM_BCKL, 0); +} + + +/* 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. + */ +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. + } +} + + +//Simple routine to generate some patterns and send them to the LCD. Don't expect anything too +//impressive. Because the SPI driver handles transactions in the background, we can calculate the next line +//while the previous one is being sent. +static void display_pretty_colors(spi_device_handle_t spi) +{ + uint16_t *lines[2]; + //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); + } + int frame=0; + //Indexes of the line currently being sent to the LCD and the line we're calculating. + int sending_line=-1; + int calc_line=0; + + while(1) { + frame++; + for (int y=0; y<240; y+=PARALLEL_LINES) { + //Calculate a line. + pretty_effect_calc_lines(lines[calc_line], y, frame, 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. + } + } +} + +void app_main(void) +{ + esp_err_t ret; + spi_device_handle_t spi; + 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=lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line + }; + //Initialize the SPI bus + ret=spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO); + 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 + lcd_init(spi); + //Initialize the effect displayed + ret=pretty_effect_init(); + ESP_ERROR_CHECK(ret); + + //Go do nice stuff. + display_pretty_colors(spi); +}