ESP32 S3 Segmented SPI Transfer -SEG_TRANS_DONE interrupt never triggers!
Posted: Tue Jul 02, 2024 1:21 am
Hi,
I have created a 'simple' example of using ESP32S3's Segmented Transfer mode for SPI in order to create a continuous loop.
However, I can NEVER get it to trigger a SPI_DMA_SEG_TRANS_DONE_INT interrupt never seems to trigger, no matter what I do.
https://github.com/mrcodetastic/esp32s3 ... x_seg_loop
I have this function that ends the transfer by setting the linked list to end, but even that won't cause an interrupt to be generated!
Two functions are run in sequential order to start things off, the first one to use the esp-idf driver framework to set the registers of the GPSPI2 peripheral, then a second function to interact with it again to set segmented transfer and kick off a loop of output.
Any ideas?
I have created a 'simple' example of using ESP32S3's Segmented Transfer mode for SPI in order to create a continuous loop.
However, I can NEVER get it to trigger a SPI_DMA_SEG_TRANS_DONE_INT interrupt never seems to trigger, no matter what I do.
https://github.com/mrcodetastic/esp32s3 ... x_seg_loop
I have this function that ends the transfer by setting the linked list to end, but even that won't cause an interrupt to be generated!
Code: Select all
// Doesn't quite clean up cleanly.
esp_err_t spi_transfer_loop_stop(void) {
const spi_bus_attr_t* bus_attr = spi_bus_get_attr(SPI2_HOST);
// Disconnect the looping DMA transfer to cause the transfer to finish
ESP_LOGD(TAG, "Calling spi_transfer_loop_stop()");
dma_data_lldesc[dma_lldesc_required-1].eof = 1;
dma_data_lldesc[dma_lldesc_required-1].qe.stqe_next = NULL;
return ESP_OK;
}
Code: Select all
esp_err_t spi_transfer_loop_start()
{
// Setup interrupt
static intr_handle_t intr;
esp_intr_alloc (ETS_SPI2_DMA_INTR_SOURCE, ESP_INTR_FLAG_SHARED, dma_isr3, NULL, &intr);
esp_intr_alloc (ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, dma_isr3, NULL, &intr);
esp_intr_enable (intr);
dma_isr3(0); // increase count to 1
esp_err_t err;
// Dispatch transaction; link_trans will finish it off
ESP_LOGD(TAG, "Initial Transfer");
static spi_transaction_t trans;
trans.flags = SPI_TRANS_MODE_OCT;
// What do we do here? TO DO, send null packet just to kick off transfer?
// https://www.esp32.com/viewtopic.php?p=123221#p123211
trans.tx_buffer = spi_tx_payload_testchunk2;
trans.length = (sizeof(spi_tx_payload_testchunk2)) * 8;
trans.rx_buffer = NULL;
trans.rxlength = 0;
CHECK_CALLE(spi_device_polling_start(spi_device, &trans, portMAX_DELAY), "Could not start SPI transfer");
//esp_register_shutdown_handler(vga_deinit);
ESP_LOGD(TAG, "spi_transfer_loop_start() complete");
return ESP_OK;
}
esp_err_t spi_transfer_loop_start_2()
{
// Need to do first start first to set registers.
ESP_LOGD(TAG, "Part 2");
// TODO; Figure out a way to get interrupts working, and when the GCLK segement has completed and about to restert - then allow a DCLK / Greyscale transfer
// AT THE SAME TIME
// esp_intr_alloc_intrstatus(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, (uint32_t)&GPSPI2.dma_int_st.val, SPI_DMA_SEG_TRANS_DONE_INT_ENA_M, dma_isr2, NULL, &intr);
GPSPI2.slave.dma_seg_magic_value = 0xA;
const spi_bus_attr_t* bus_attr = spi_bus_get_attr(SPI2_HOST);
// hal->dmadesc_tx = &dma_data_lldesc[0]; // START OFF A DESCRIPTOR 0
spi_dma_ll_tx_reset(&GDMA, bus_attr->tx_dma_chan);
spi_ll_dma_tx_fifo_reset(&GPSPI2);
spi_ll_outfifo_empty_clr(&GPSPI2);
spi_ll_dma_tx_enable(&GPSPI2, 1);
spi_dma_ll_tx_start(&GDMA, bus_attr->tx_dma_chan, &dma_data_lldesc[0]);
GPSPI2.slave.usr_conf = 1; // Enable user conf for segmented transfers
GPSPI2.user.usr_conf_nxt = 1;
GPSPI2.misc.cs0_dis = 1; // turn off client select pin
// 13. Set SPI_DMA_SEG_TRANS_DONE_INT_ENA to enable the SPI_DMA_SEG_TRANS_DONE_INT interrupt.
// Configure other interrupts if needed according to Section 30.10.
//esp_intr_free(spi_device->host->intr);
spi_ll_clear_intr(&GPSPI2, SPI_LL_INTR_TRANS_DONE); // need this for the transacion to start
spi_ll_clear_intr(&GPSPI2, SPI_LL_INTR_SEG_DONE); // need this for the transacion to start
GPSPI2.dma_int_ena.dma_seg_trans_done = 1; // Doesn't work, so can't use it. :-(
GPSPI2.dma_int_ena.trans_done = 1; // Doesn't work, so can't use it. :-(
GPSPI2.cmd.conf_bitlen = 0;
// Configure interrupt
// TODO; Figure out a way to get interrupts working, and when the GCLK segement has completed and about to restert - then allow a DCLK / Greyscale transfer
// AT THE SAME TIME
// esp_intr_alloc_intrstatus(ETS_SPI2_INTR_SOURCE, ESP_INTR_FLAG_SHARED, (uint32_t)&GPSPI2.dma_int_st.val, SPI_DMA_SEG_TRANS_DONE_INT_ENA_M, dma_isr2, NULL, &intr);
//esp_intr_free(spi_device->host->intr);
//spi_ll_clear_int_stat (spi_device->host->hal.hw);
GPSPI2.cmd.update = 1;
while (GPSPI2.cmd.update); //waiting config applied
// start trans
GPSPI2.cmd.usr = 1;
//esp_register_shutdown_handler(vga_deinit);
ESP_LOGD(TAG, "spi_transfer_loop_start_2() complete");
return ESP_OK;
}