HX8347 240*320 TFT屏 3线SPI(CS,SCL,SDI)用ESP32 S3驱动
一、源码
/* SPI Master exampleThis example code is in the Public Domain (or CC0 licensed, at your option.)Unless required by applicable law or agreed to in writing, thissoftware is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES ORCONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.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 asspi_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 thisline to be low for a command and high for data. We use a pre-transmit callback here to control thatline: every transaction has as the user-definable argument the needed state of the D/C line and justbefore the transaction is sent, the callback will set this line to the correct state.
*/#define LCD_HOST SPI2_HOST#define PIN_NUM_MISO 4
#define PIN_NUM_MOSI 5
#define PIN_NUM_CLK 3
#define PIN_NUM_CS 6#define PIN_NUM_DC -1
#define PIN_NUM_RST 2
#define PIN_NUM_BCKL -1#define PIN_NUM_LED 45static spi_device_handle_t g_screen_spi;static int lcd_cs_port(int status)
{if (status) {gpio_set_level(PIN_NUM_CS, 1);} else {gpio_set_level(PIN_NUM_CS, 0);}return 0;
}static void spi_writeData(spi_device_handle_t spi,uint8_t data)
{esp_err_t ret;spi_transaction_t t;memset(&t, 0, sizeof(t));t.length = 8;t.tx_buffer = &data;ret = spi_device_polling_transmit(spi, &t); //Transmit!assert(ret==ESP_OK);
}static void lcd_cmd(spi_device_handle_t spi, const uint8_t data) {lcd_cs_port(0);spi_writeData(spi,0x70);spi_writeData(spi,data);lcd_cs_port(1);
}static void lcd_data(spi_device_handle_t spi, const uint8_t data) {lcd_cs_port(0);spi_writeData(spi,0x72);spi_writeData(spi,data);lcd_cs_port(1);
}static void LCD_WriteComm(uint8_t cmd) {lcd_cmd(g_screen_spi, cmd);
}static void LCD_WriteData(uint8_t data) {lcd_data(g_screen_spi, data);
}void LCD_WriteData_16Bit(uint16_t Data)
{lcd_cs_port(0);spi_writeData(g_screen_spi,0x72);spi_writeData(g_screen_spi,Data>>8);spi_writeData(g_screen_spi,Data);lcd_cs_port(1);
}
void Lcd_Write_REG(uint8_t Index,uint8_t Data)
{LCD_WriteComm(Index);LCD_WriteData(Data);
}void LCD_SetWindow(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{//SCLcd_Write_REG(0x02,x1>>8); // Column address start2Lcd_Write_REG(0x03,(unsigned char)x1); // Column address start1//ECLcd_Write_REG(0x04,x2>>8); // Column address end2Lcd_Write_REG(0x05,(unsigned char)x2); // Column address end1//SPLcd_Write_REG(0x06,y1>>8); // Row address start2Lcd_Write_REG(0x07,(unsigned char)y1); // Row address start1//EPLcd_Write_REG(0x08,y2>>8); // Row address end2Lcd_Write_REG(0x09,(unsigned char)y2); // Row address end1//写0x22到index register,那么下次send data就会直接被写到graphic ramLCD_WriteComm(0x22);
}void FillRect(unsigned short x1, unsigned short y1, unsigned short x2, unsigned short y2, unsigned short color)
{LCD_SetWindow(x1, y1,x2,y2);x2 = x2 - x1 + 1;y2 = y2 - y1 + 1;for(x1 = x2; x1 != 0 ; x1--){for (y1 = y2;y1 != 0 ;y1--){LCD_WriteData_16Bit(color);}}}void LCD_Init(void)
{gpio_set_level(PIN_NUM_RST, 0);vTaskDelay(100/portTICK_PERIOD_MS);gpio_set_level(PIN_NUM_RST, 1);vTaskDelay(100/portTICK_PERIOD_MS);Lcd_Write_REG(0x18,0x88); //UADJ 75HzLcd_Write_REG(0x19,0x01); //OSC_EN='1', start Osc//Power Voltage SettingLcd_Write_REG(0x1B,0x1E); //VRH=4.60VLcd_Write_REG(0x1C,0x07); //AP Crosstalk 04Lcd_Write_REG(0x1A,0x01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)Lcd_Write_REG(0x24,0x38); //VMH 27Lcd_Write_REG(0x25,0x5F); //VML//VCOM offsetLcd_Write_REG(0x23,0x8C); //for Flicker adjustLcd_Write_REG(0x1F,0x88);// GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0vTaskDelay(5/portTICK_PERIOD_MS);Lcd_Write_REG(0x1F,0x80);// GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0vTaskDelay(5/portTICK_PERIOD_MS);Lcd_Write_REG(0x1F,0x90);// GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0vTaskDelay(5/portTICK_PERIOD_MS);Lcd_Write_REG(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0vTaskDelay(5/portTICK_PERIOD_MS);//Display ON SettingLcd_Write_REG(0x28,0x38); //GON=1, DTE=1, D=1000vTaskDelay(40/portTICK_PERIOD_MS);Lcd_Write_REG(0x28,0x3C); //GON=1, DTE=1, D=1100Lcd_Write_REG(0x36,0x09); //REV, BGRLcd_Write_REG(0x17,0x05); //16BIT/PIXEL//Gamma 2.2 SettingLcd_Write_REG(0x40,0x00); //Lcd_Write_REG(0x41,0x00); //Lcd_Write_REG(0x42,0x00); //Lcd_Write_REG(0x43,0x11); //Lcd_Write_REG(0x44,0x0e); //Lcd_Write_REG(0x45,0x23); //Lcd_Write_REG(0x46,0x08); //Lcd_Write_REG(0x47,0x53); //Lcd_Write_REG(0x48,0x03); //Lcd_Write_REG(0x49,0x11); //Lcd_Write_REG(0x4A,0x18); //Lcd_Write_REG(0x4B,0x1a); //Lcd_Write_REG(0x4C,0x16); //Lcd_Write_REG(0x50,0x1c); //Lcd_Write_REG(0x51,0x31); //Lcd_Write_REG(0x52,0x2e); //Lcd_Write_REG(0x53,0x3f); //Lcd_Write_REG(0x54,0x3f); //Lcd_Write_REG(0x55,0x3f); //Lcd_Write_REG(0x56,0x2c); //Lcd_Write_REG(0x57,0x77); //Lcd_Write_REG(0x58,0x09); //Lcd_Write_REG(0x59,0x05); //Lcd_Write_REG(0x5A,0x07); //Lcd_Write_REG(0x5B,0x0e); //Lcd_Write_REG(0x5C,0x1c); //Lcd_Write_REG(0x5D,0x88); //vTaskDelay(100/portTICK_PERIOD_MS);FillRect(0, 0, 239, 319, 0xf800 );
}void app_main(void)
{esp_err_t ret;gpio_config_t io_conf = {};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=16*320};spi_device_interface_config_t devcfg={.clock_speed_hz=40*1000*1000, //Clock out at 10 MHz.mode=0, //SPI mode 0//.spics_io_num=PIN_NUM_CS, //CS pin.queue_size=1, //We want to be able to queue 7 transactions at a time};//Initialize the lcd gpioio_conf.pin_bit_mask = ( (1ULL<<PIN_NUM_RST) |(1ULL<<PIN_NUM_CS));io_conf.mode = GPIO_MODE_OUTPUT;io_conf.pull_up_en = true;gpio_config(&io_conf);//Initialize the SPI busret=spi_bus_initialize(LCD_HOST, &buscfg, SPI_DMA_CH_AUTO);ESP_ERROR_CHECK(ret);// //Attach the LCD to the SPI busret=spi_bus_add_device(LCD_HOST, &devcfg, &g_screen_spi);ESP_ERROR_CHECK(ret);//Initialize the LCDLCD_Init();FillRect(0, 0, 239, 319, 0xf800 );vTaskDelay(500/portTICK_PERIOD_MS);FillRect(0, 0, 239, 319, 0x07e0 );vTaskDelay(500/portTICK_PERIOD_MS);FillRect(0, 0, 239, 319, 0x001f );vTaskDelay(500/portTICK_PERIOD_MS);FillRect(0, 0, 239, 319, 0xFFE0 );vTaskDelay(500/portTICK_PERIOD_MS);FillRect(0, 0, 239, 319, 0xEF7D );vTaskDelay(500/portTICK_PERIOD_MS);}
二、总结
1、驱动成功了,但刷新很慢,感觉比模拟SPI都慢。SPI频率设到40M了,也没什么改进。
2、开始让SPI自己控制CS,不知道什么原因,无论用中断方式还是轮询方式,屏幕都无显示。CS只有通过GPIO控制才有效。
SPI轮询方式
ret = spi_device_polling_transmit(spi, &t); //Transmit!
SPI中断方式
ret = spi_device_transmit(spi,(spi_transaction_t *)&trans);
自己控制CS
static int lcd_cs_port(int status)
{
if (status) {
gpio_set_level(PIN_NUM_CS, 1);
} else {
gpio_set_level(PIN_NUM_CS, 0);
}
return 0;
}
所以.spics_io_num=PIN_NUM_CS被注释掉了。
spi_device_interface_config_t devcfg={
.clock_speed_hz=40*1000*1000, //Clock out at 10 MHz
.mode=0, //SPI mode 0
//.spics_io_num=PIN_NUM_CS, //CS pin
.queue_size=1, //We want to be able to queue 7 transactions at a time
};