SPI驱动问题,ST7789,spi_device_polling_transmit和spi_device_queue_trans差异?

geokai
Posts: 6
Joined: Sat Mar 27, 2021 1:33 pm

SPI驱动问题,ST7789,spi_device_polling_transmit和spi_device_queue_trans差异?

Postby geokai » Sat Mar 27, 2021 2:25 pm

在做ST7789 240×240的驱动,修改自官方SPI_MASTER下的LCD例子,附上主要的修改

Code: Select all

引脚部分
#ifdef CONFIG_IDF_TARGET_ESP32
#define LCD_HOST    HSPI_HOST
#define DMA_CHAN    2

#define PIN_NUM_MISO -1
#define PIN_NUM_MOSI 25
#define PIN_NUM_CLK  12
#define PIN_NUM_CS   27

#define PIN_NUM_DC   33
#define PIN_NUM_RST  14
#define PIN_NUM_BCKL -1

一次刷新120行
#define PARALLEL_LINES 120

主函数

Code: Select all

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*240*2+8
    };
    spi_device_interface_config_t devcfg={
        .clock_speed_hz=25*1000*1000,           //Clock out at 10 MHz
        .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, 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
    lcd_init(spi);
    //Go do nice stuff.
    display_pretty_colors(spi);
}

Code: Select all

static void display_pretty_colors(spi_device_handle_t spi)
{
    uint16_t *lines[2];
    uint8_t pix[240];
    //Allocate memory for the pixel buffers
    ESP_LOGI(TAG,"start heap caps malloc");
    for (int i=0; i<2; i++) {
        lines[i]=heap_caps_malloc(240*PARALLEL_LINES*sizeof(uint16_t), MALLOC_CAP_DMA);
        assert(lines[i]!=NULL);
    }
    uint16_t frame=0xFFFF;
    //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--;
        if (frame==0) frame = 0xFFFF;
        for (int y=0; y<240; y+=PARALLEL_LINES) {
            //Calculate a line.
            // pretty_effect_calc_lines(lines[calc_line], y, frame, PARALLEL_LINES);

            for (int j=0; j<240*PARALLEL_LINES; j++) lines[0][j] = (frame<<8) + (frame>>8);
            //Finish up the sending process of the previous line, if any
            ESP_LOGI(TAG,"fill color %2x", frame);
            if (sending_line!=-1) send_line_finish(spi);
            ESP_LOGI(TAG,"send line");

            send_lines(spi, y, lines[0]);
            ESP_LOGI(TAG,"finish send line");
        }
    }


}

Code: Select all

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.
    DRAM_ATTR static spi_transaction_t trans[6];
    DRAM_ATTR static uint8_t data_command=0x2c;
    static uint8_t ydata_pos_command[5];

    //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]=((uint16_t)239)>>8;       //End Col High
    trans[1].tx_data[3]=((uint16_t)239)&0xff;     //End Col Low
    
    trans[2].tx_data[0]=0x2B;           //Page address set

    ydata_pos_command[0] = ypos>>8;
    ydata_pos_command[1] = ypos&0xff; 
    ydata_pos_command[2] = (ypos+PARALLEL_LINES)>>8; 
    ydata_pos_command[3] = (ypos+PARALLEL_LINES)&0xff;
    trans[3].tx_buffer = ydata_pos_command;
    trans[3].length=4*8;          //Data length, in bits
    trans[3].flags=0; //undo SPI_TRANS_USE_TXDATA flag


    trans[4].tx_buffer=&data_command;        //finally send the line data
    trans[4].length = 8;
    trans[4].flags=0;

    trans[5].tx_buffer = linedata;
    trans[5].length=240*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);
        // ret=spi_device_polling_transmit(spi, &trans[x]);
        
        assert(ret==ESP_OK);
    }

}

我获得了如下的波形
整体
Image

第一帧的两次写数据
Image

第一帧第二次写数据前的写命令部分
Image

其中
1)ST7789初始化部分
2a)第一帧的前120行:设置写入坐标的5个指令,240×2×120 字节的像素数据
2b)第一帧的后120行:设置写入坐标的5个指令,240×2×120 字节的像素数据
3)第二帧
4)第三帧
。。。。。。下同

1.为什么ST7789初始化阶段两个命令间会延时这么久
2.为什么第一帧的前120行写入时写命令间隔为4ms,而到了第二个120行写命令间隔为间隔变成了20us
3.为什么只有第一帧的前120写入时写命令间隔为4ms,而后所有帧的写命令间隔为20us

geokai
Posts: 6
Joined: Sat Mar 27, 2021 1:33 pm

Re: SPI驱动问题,ST7789,spi_device_polling_transmit和spi_device_queue_trans差异?

Postby geokai » Mon Mar 29, 2021 2:47 pm

图挂了,重新上传了
Image
Image
Image

geokai
Posts: 6
Joined: Sat Mar 27, 2021 1:33 pm

Re: SPI驱动问题,ST7789,spi_device_polling_transmit和spi_device_queue_trans差异?

Postby geokai » Mon Mar 29, 2021 3:07 pm

新的进展,
将每次写入120行修改成为每次写入<80行后,每一次写入数据前的写命令阶段的阶段都变成4ms了,而不是20us。

然后修改本例子中的传输显示数据部分send_lines(),使用了lvgl官方的esp32版本中的st7789驱动的传输显示数据部分(核心代码如下)。此时所有命令间隔均变成了20us,无论是单次写入多少行。
spi_transaction_ext_t *pTransaction = NULL;
xQueueReceive(TransactionPool, &pTransaction, portMAX_DELAY);
memcpy(pTransaction, &t, sizeof(t));
if (spi_device_queue_trans(spi, (spi_transaction_t *) pTransaction, portMAX_DELAY) != ESP_OK) {
xQueueSend(TransactionPool, &pTransaction, portMAX_DELAY); /* send failed transaction back to the pool to be reused */
}

目前时序比较满意了,指令与指令之间的间隔均在几十us,显示的流畅程度明显增加。
问题算是解决了。但是这究竟是怎么运行起来的?由于本人资历较浅,代码底层确实研究不明白。希望有大佬能解答。

Mars.CN
Posts: 45
Joined: Tue Jan 11, 2022 1:36 am

Re: SPI驱动问题,ST7789,spi_device_polling_transmit和spi_device_queue_trans差异?

Postby Mars.CN » Tue Oct 04, 2022 3:57 am

我怀疑是不是S3的SPI就不能用?
看到的都是S2的,S3就没成功过,用官方的例程都不成功!
示波器测试初始化指令发送阶段就没有波形
使用spi_device_polling_transmit 发送数据完全没反应,示波器没有任何信号

Who is online

Users browsing this forum: No registered users and 90 guests