SPI master driver time between transactions

technomage
Posts: 7
Joined: Fri Dec 03, 2021 12:28 pm

SPI master driver time between transactions

Postby technomage » Fri Dec 03, 2021 1:48 pm

Hello,
I am writing a test program to read from an ADC through the IDF SPI Master driver. I am using polling transmissions without DMA. This is the code I am using:

Code: Select all

uint16_t val;
spi_transaction_t trans = {}:

trans.flags = SPI_TRANS_USE_TXDATA;
trans.length = 16;
trans.rx_buffer = &val;

ESP_ERROR_CHECK( spi_device_acquire_bus(spi, portMAX_DELAY) );

for (i=0; i < 16; i++) {
    ESP_ERROR_CHECK( spi_device_polling_transmit(spi, &trans) );

    val = SPI_SWAP_DATA_RX(val, 16);

    reads[i] = val;
}

spi_device_release_bus(spi);

This code works well, the thing is that between transmissions there is a gap of about 8 us, not allowing the code to read faster enough to cover my requirements.

After some manual profiling in the driver code, i found that the function where the code spends more time is initiating the transmission in spi_device_polling_start() called by spi_device_polling_transmit().

My question is, how could I shrink the times between transactions to achieve a higher sample rate?

Thanks.

malaugh
Posts: 4
Joined: Mon Aug 20, 2018 8:17 pm

Re: SPI master driver time between transactions

Postby malaugh » Wed Dec 15, 2021 8:07 pm

Did anyone find a solution for this. I am having the same problem. I am implementing an LCD driver

Below is a section of the code.

When I use the functions Lcd_Cmd or Lcd_Data, the SPI transaction is fast, but there is a 15mS delay before the function completes and returns. Any ideas on how to speed up the time between transactions?

Code: Select all

/******************************************************************************  
 * FUNCTION:    Lcd_InitSpi
 * 
 * DESCRIPTION:	Initialize the SPI connection to the LCD
 *
 * PARAMETERS:  
 *
 * RETURN: 		None
 ******************************************************************************/
void Lcd_InitSpi(void)
{
    esp_err_t ret;
    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 = 
    {
        .clock_speed_hz=10*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_SpiPreTransferCallback,     //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, &Lcd_Spi);
    ESP_ERROR_CHECK(ret);
}    

/******************************************************************************  
 * FUNCTION:    Lcd_InitDriver
 * 
 * DESCRIPTION:	Initialize the LCD Driver
 *
 * PARAMETERS:  
 *
 * RETURN: 		None
 ******************************************************************************/
void Lcd_InitDriver(void)
{
    int cmd = 0;
    const lcd_init_cmd_t* lcd_init_cmds;
    
    /* Set IM pins to SPI Interface */
    gpio_set_direction(PIN_NUM_IM1, GPIO_MODE_OUTPUT);
    gpio_set_direction(PIN_NUM_IM2, GPIO_MODE_OUTPUT);
    gpio_set_direction(PIN_NUM_IM3, GPIO_MODE_OUTPUT);
    gpio_set_level(PIN_NUM_IM1, 1);
    gpio_set_level(PIN_NUM_IM2, 1);
    gpio_set_level(PIN_NUM_IM3, 1);

    /* 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 */
    if ( Lcd_GetId() == 0 )
    {
        /* ID zero = ILI9341 graphics chip */
        lcd_init_cmds = ili_init_cmds;
    }
    else
    {
        /* ID non-zero = ST7789V graphics chip */
        lcd_init_cmds = st_init_cmds;
    }

    /* Send all initialization commands */
    while (lcd_init_cmds[cmd].databytes != 0xff)
    {
        Lcd_Cmd(lcd_init_cmds[cmd].cmd);
        Lcd_Data(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);
}

/******************************************************************************
 * FUNCTION:    Lcd_Cmd
 * 
 * DESCRIPTION:	Send a command byte through the SPI to the LCD
 *
 * PARAMETERS:  spi - Pointer to SPI instance
 *              cmd - CommandByte to be sent
 *
 * RETURN: 		None
 ******************************************************************************/
void Lcd_Cmd(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(Lcd_Spi, &t);  // Transmit!
    assert(ret == ESP_OK);                            // Should have had no issues.
}

/******************************************************************************
 * FUNCTION:    Lcd_Data
 * 
 * DESCRIPTION:	Send data bytes to the LCD over the SPI interface
 *
 * PARAMETERS:  spi - Pointer to SPI instance
 *              data - pointer to data buffer
 *              len - number of data bytes to send
 *
 * RETURN: 		None
 ******************************************************************************/
void Lcd_Data(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(Lcd_Spi, &t); // Transmit!
    assert(ret == ESP_OK);                           // Should have had no issues.
}

lukecam95
Posts: 14
Joined: Thu Sep 23, 2021 9:37 am

Re: SPI master driver time between transactions

Postby lukecam95 » Sat Jan 21, 2023 5:51 pm

Did anyone find a solution to this issue?

Who is online

Users browsing this forum: Google [Bot] and 104 guests