ESP32 S3 Segmented SPI Transfer -SEG_TRANS_DONE interrupt never triggers!

faptastic
Posts: 15
Joined: Mon Nov 14, 2022 10:38 pm

ESP32 S3 Segmented SPI Transfer -SEG_TRANS_DONE interrupt never triggers!

Postby faptastic » 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!

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;
}

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.

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;
}

Any ideas?

faptastic
Posts: 15
Joined: Mon Nov 14, 2022 10:38 pm

Re: ESP32 S3 Segmented SPI Transfer -SEG_TRANS_DONE interrupt never triggers!

Postby faptastic » Wed Jul 03, 2024 9:30 pm

Figured out the problem.

Ending the DMA transfer does not trigger an interrupt by the SPI device. It just sits there in silence. You need to zero out SPI_USR_CONF_NXT to trigger an interrupt.

Solution here: https://github.com/mrcodetastic/esp32s3 ... x_seg_loop

Who is online

Users browsing this forum: No registered users and 113 guests