ESP32 S3+3线SPI+HX8347

 HX8347 240*320 TFT屏 3线SPI(CS,SCL,SDI)用ESP32 S3驱动

一、源码

/* 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 <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 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.
*/

#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  45


static 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)
{

    //SC
    Lcd_Write_REG(0x02,x1>>8);       // Column address start2
    Lcd_Write_REG(0x03,(unsigned char)x1);          // Column address start1
    //EC
    Lcd_Write_REG(0x04,x2>>8);       // Column address end2
    Lcd_Write_REG(0x05,(unsigned char)x2);          // Column address end1
    //SP
    Lcd_Write_REG(0x06,y1>>8);       // Row address start2
    Lcd_Write_REG(0x07,(unsigned char)y1);          // Row address start1
    //EP
    Lcd_Write_REG(0x08,y2>>8);       // Row address end2
    Lcd_Write_REG(0x09,(unsigned char)y2);          // Row address end1
    //写0x22到index register,那么下次send data就会直接被写到graphic ram
    LCD_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 75Hz
    Lcd_Write_REG(0x19,0x01);        //OSC_EN='1', start Osc
    //Power Voltage Setting
    Lcd_Write_REG(0x1B,0x1E); //VRH=4.60V
    Lcd_Write_REG(0x1C,0x07); //AP Crosstalk    04
    Lcd_Write_REG(0x1A,0x01); //BT (VGH~15V,VGL~-10V,DDVDH~5V)
    Lcd_Write_REG(0x24,0x38); //VMH 27
    Lcd_Write_REG(0x25,0x5F); //VML
    //VCOM offset
    Lcd_Write_REG(0x23,0x8C); //for Flicker adjust
    Lcd_Write_REG(0x1F,0x88);// GAS=1, VOMG=00, PON=0, DK=1, XDK=0, DVDH_TRI=0, STB=0
    vTaskDelay(5/portTICK_PERIOD_MS);
    Lcd_Write_REG(0x1F,0x80);// GAS=1, VOMG=00, PON=0, DK=0, XDK=0, DVDH_TRI=0, STB=0
    vTaskDelay(5/portTICK_PERIOD_MS);
    Lcd_Write_REG(0x1F,0x90);// GAS=1, VOMG=00, PON=1, DK=0, XDK=0, DVDH_TRI=0, STB=0
    vTaskDelay(5/portTICK_PERIOD_MS);
    Lcd_Write_REG(0x1F,0xD0);// GAS=1, VOMG=10, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
    vTaskDelay(5/portTICK_PERIOD_MS);
    //Display ON Setting
    Lcd_Write_REG(0x28,0x38);   //GON=1, DTE=1, D=1000
    vTaskDelay(40/portTICK_PERIOD_MS);
    Lcd_Write_REG(0x28,0x3C);   //GON=1, DTE=1, D=1100
    Lcd_Write_REG(0x36,0x09);   //REV, BGR
    Lcd_Write_REG(0x17,0x05);  //16BIT/PIXEL

    //Gamma 2.2 Setting
    Lcd_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 gpio

    io_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 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, &g_screen_spi);
    ESP_ERROR_CHECK(ret);

    //Initialize the LCD
    LCD_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

    };

3、LCD_WriteData_16Bit 函数中,改成tx_buffer传输就快了。应该是用CMD方式每次传的太少,而SPI+DMA最好是一次多传一些数据,减少启动spi传输次数,增加每次传输的数据量。

void LCD_WriteData_16Bit(uint8_t* Data)
{

    esp_err_t ret;

    spi_transaction_ext_t trans = {0};
    trans.base.flags=SPI_DEVICE_CLK_AS_CS|SPI_DEVICE_NO_DUMMY;
    trans.base.length=320*2*8;
    trans.base.tx_buffer=Data;

    disp_wait_for_pending_transactions();	/* before polling, all previous pending transactions need to be serviced */
    spi_device_polling_transmit(g_screen_spi, (spi_transaction_t *) &trans);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值