I am using I MX RT1060 conducted experiments on SPI slave data transmission using EDMA, but recently encountered a problem that caused the system to crash for an unknown reason.
My background is as follows: my code uses RTOS and has two SPI slave threads, with SPI1 thread 1 having a higher priority and SPI2 thread 2 having a lower priority. Both threads act as slaves to put data into the buf bound to the SPI controller and wait for the host to retrieve it. Each packet of data is 512 bytes in size and has a communication frequency of 250Hz. There is a low probability of system crashes, where SPI2 thread 2 (with lower priority) crashes when calling a underlying DMA function,code is in file fsl_edma.c:
void EDMA_SetTransferConfig(DMA_Type *base, uint32_t channel, const edma_transfer_config_t *config, edma_tcd_t *nextTcd)
{
assert(channel < FSL_FEATURE_EDMA_MODULE_CHANNEL);
assert(config != NULL);
assert(((uint32_t)nextTcd & 0x1FU) == 0);
EDMA_TcdSetTransferConfig((edma_tcd_t *)&base->TCD[channel], config, nextTcd);
}
The place where the code is called is :
file:fsl_lpspi_edma.c
status_t LPSPI_SlaveTransferEDMA(LPSPI_Type *base, lpspi_slave_edma_handle_t *handle, lpspi_transfer_t *transfer)
{
......
if (isThereExtraTxBytes)
{
EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
&transferConfigTx, softwareTCD_extraBytes);
}
else
{
EDMA_SetTransferConfig(handle->edmaTxDataToTxRegHandle->base, handle->edmaTxDataToTxRegHandle->channel,
&transferConfigTx, NULL);
}
EDMA_StartTransfer(handle->edmaTxDataToTxRegHandle);
EDMA_StartTransfer(handle->edmaRxRegToRxDataHandle);
LPSPI_EnableDMA(base, kLPSPI_RxDmaEnable | kLPSPI_TxDmaEnable);
LPSPI_Enable(base, true);
return kStatus_Success;
}
The line of code that caused the system to crash is:
assert(((uint32_t)nextTcd & 0x1FU) == 0);
The kernel register address I captured through the backtrace tool is:
R0 : 400e8000 R1 : 00000014 R2 : 20022d70 R3 : 00000000
R0 is DMA0 adrress, R1 is DMA channel, R2 is config, R3 is nextTcd, These register addresses are all as expected.
So, I don't know what exactly caused the system crash, is it related to DMA access? SPI1 and SPI2 use different DMA channels.
Hi @769985518 ,
Thank you so much for your interest in our products and for using our community.
The line of code that caused the system to crash is:
assert(((uint32_t)nextTcd & 0x1FU) == 0); causes the system to crash, it means that the address pointed to by nextTcd is not 32-byte aligned.
1: So please check Peripherals LPSPI Register status when system crash, whether something abnormal.
2: As you said that you have 2 SPI slave threads, Please double check handle of SPI1 and SPI2 (lpspi_slave_edma_handle_t,edma_handle_t, lpspi_slave_edma_transfer_callback_t )have been defined separately?
3: Please check whether your project the stack space is sufficient.
Wish it helps you.
If you still have question about it, please kindly let me know.
BR
mayliu
Hi @769985518 ,
Thanks for your reply and patience.
I think when the address of ((uint32_t)nextTcd & 0x1FU) is not 0, It crashes immediately when executing
assert(((uint32_t)nextTcd & 0x1FU) == 0U); Under normal circumstances, this situation will not occur.
Please answer my two question.
1:I want to know how you know the current SPI1/2 slave transfer is finished (by LPSPI_SlaveUs
erCallback )?Also I want to know when you will trigger the next SPI1/2 transfer?
2: Did you deal with the errors when SPI1/2 transmission fail. I suggest that if SPI1/2 have error, please abort the current SPI1/2 transfer or perform a reset operation, and then start a new SPI1/2 transfer.
Your Question:
1. Do two SPI operations on DMA registers exhibit race behavior?
Answer: Yes, in MIMXRT1160RM, chapter 6.4.3 Arbitration mode considerations described more detail.
Question:
2. Is it related to memory barriers?such as __DSB, __ ISB, etc.
Answer: Usually, we use SDK_ISR_EXIT_BARRIER (#define SDK_ISR_EXIT_BARRIER __DSB()) in interrupt functions to ensure the execution order of instructions.
It is hard to say "it is related to memory barriers?such as __DSB, __ ISB, etc."
If you consider this impact, I suggest you can use __DSB when call SPI1/2 LPSPI_SlaveTransferEDMA function.
Wish it helps you.
If you still have question about it, please kindly let me know.
BR
mayliu