Hello,
I am currently testing an external ADC (ADS131E08) functionality using the i.MX93 EVK. I have already confirmed that the LPSPI3 interface works fine in Polling/Interrupt mode. Now, I am trying to implement LPSPI3 combined with eDMA4 to optimize performance.
Environment:
Target Board: MCIMX93-EVK (Cortex-M33)
SDK Version: MCUXpresso SDK 25.12.0
IDE: VSCode with MCUXpresso Extension
Since there is no specific "LPSPI-EDMA" example for i.MX93 in the SDK, I implemented the following based on other peripheral examples:
1. Memory Allocation (OCRAM - NonCacheable)
I placed all DMA-related buffers and handles in the OCRAM section and configured the MPU as Non-Cacheable to avoid coherency issues.
============================ code ===============================
/* Linker Script */ MEMORY { m_data (RW) : ORIGIN = 0x20003000, LENGTH = 0x0001B000 m_ocram (RW) : ORIGIN = 0x20480000, LENGTH = 0x00040000 } .noncacheable_section : { . = ALIGN(32); __noncacheable_start__ = .; *(NonCacheable) __noncacheable_end__ = .; } > m_ocram
/* Variable Definitions */ __attribute__((section("NonCacheable"), aligned(32))) static lpspi_master_edma_handle_t g_lpspi_master_edma_handle; AT_NONCACHEABLE_SECTION_INIT(static edma_handle_t g_lpspi_tx_dma_handle); AT_NONCACHEABLE_SECTION_INIT(static edma_handle_t g_lpspi_rx_dma_handle); __attribute__((section("NonCacheable"), aligned(32))) static uint8_t dummy_tx_data[ADC_SAMPLE_BYTES] = { ... }; __attribute__((section("NonCacheable"), aligned(32))) static uint8_t sample_buf_ping[INTERPOLATION_L][ADC_SAMPLE_BYTES];
============================ code ===============================
2. Initialization Process
I configured eDMA4, created handles, and linked them to LPSPI3.
============================ code ===============================
static void LPSPI_Master_DMA_Init(void) { edma_config_t userConfig; EDMA_GetDefaultConfig(&userConfig); EDMA_Init(DMA4, &userConfig); EDMA_CreateHandle(&g_lpspi_tx_dma_handle, DMA4, LPSPI3_TX_DMA_CHANNEL); // CH 12 EDMA_CreateHandle(&g_lpspi_rx_dma_handle, DMA4, LPSPI3_RX_DMA_CHANNEL); // CH 13 EDMA_SetChannelMux(DMA4, LPSPI3_TX_DMA_CHANNEL, kDma4RequestMuxLPSPI3Tx); EDMA_SetChannelMux(DMA4, LPSPI3_RX_DMA_CHANNEL, kDma4RequestMuxLPSPI3Rx); LPSPI_MasterTransferCreateHandleEDMA( LPSPI3, &g_lpspi_master_edma_handle, LPSPI_MasterUserCallback, NULL, &g_lpspi_rx_dma_handle, &g_lpspi_tx_dma_handle); }
============================ code ===============================
3. SPI Transaction with Address Conversion
I used MEMORY_ConvertMemoryMapAddress to provide the System Address (Local2DMA) to the eDMA engine.
============================ code ===============================
xfer.txData = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)dummy_tx_data, kMEMORY_Local2DMA); xfer.rxData = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)sample_buf_ping, kMEMORY_Local2DMA); xfer.dataSize = ADC_SAMPLE_BYTES; xfer.configFlags = kLPSPI_MasterPcs0; status_t ret = LPSPI_MasterTransferEDMA(LPSPI3, &g_lpspi_master_edma_handle, &xfer);
============================ code ===============================
Current Symptoms:
The first call to LPSPI_MasterTransferEDMA returns kStatus_Success, but no SPI clock or data is observed on the oscilloscope.
From the second call onwards, it consistently returns kStatus_LPSPI_Busy. This suggests that the driver's internal state is stuck in 'Busy' because the first transfer never completed or triggered the 'Transfer Done' interrupt.
Checking the eDMA4 registers:
TCD[12].CH_CSR (ERQ bit) is 0 (or not being set properly).
CH_ES (Error Status) sometimes shows DBE (Destination Bus Error).
The LPSPI3 DER register has TDDE and RDDE bits set to 1 after the first call, meaning the SPI peripheral is requesting DMA, but the eDMA engine is not responding.