SPI master problem when driving ST7789,get puzzled between spi_device_polling_transmit and spi_device_queue_trans差异?
Posted: Sat Mar 27, 2021 2:55 pm
I was doing ST7789 240*240 LCD driver, which is modified from official example in "SPI_MASTER/LCD" . And the main modification is below. The LCD is working well, but the Timing Diagram puzzled me.
主函数
I get the Timing Diagram below
1) ST7789 init part,
2a) the first 120 line of the first frame. Represent function send_lines()
including 1cmd+4data+1cmd+4data+1cmd+240*120*2data
2b) the rest 120 line of the first frame. Represent function send_lines()
including 1cmd+4data+1cmd+4data+1cmd+240*120*2data
my question is
why cmd or data transfer interval between stage 1) 2a) and 3) are different , from 8ms ->4ms->20us. as there is no delay() function between cmd or data transfer.
is it cause by spi_device_polling_transmit() and spi_device_queue_trans(), or something else?
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);
}
}
I get the Timing Diagram below
1) ST7789 init part,
2a) the first 120 line of the first frame. Represent function send_lines()
including 1cmd+4data+1cmd+4data+1cmd+240*120*2data
2b) the rest 120 line of the first frame. Represent function send_lines()
including 1cmd+4data+1cmd+4data+1cmd+240*120*2data
my question is
why cmd or data transfer interval between stage 1) 2a) and 3) are different , from 8ms ->4ms->20us. as there is no delay() function between cmd or data transfer.
is it cause by spi_device_polling_transmit() and spi_device_queue_trans(), or something else?