i.MX RT 1060 use spi slave and EDMA transfer data

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX RT 1060 use spi slave and EDMA transfer data

756 Views
769985518
Contributor I

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.

Labels (1)
Tags (1)
0 Kudos
Reply
3 Replies

727 Views
mayliu1
NXP Employee
NXP Employee

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. 

mayliu1_0-1734426213074.png

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?

mayliu1_1-1734426784251.png

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

0 Kudos
Reply

713 Views
769985518
Contributor I
Executing this line of code(assert(((uint32_t)nextTcd & 0x1FU) == 0)) is just a facade, Because the address of [NextTcd] is 0, It crashes immediately when executing [((uint32_t)nextTcd & 0x1FU) == 0].

This is a very low probability problem, it may only occur for several consecutive days, and it always crashes in the same place.

Regarding the questions you answered above:
1. The register of SPI is normal
2.handle of SPI1 and SPI2 defined separately
3. The stack space is large enough

Additionally, my main focus is on whether a few points are related:
1. Do two SPI operations on DMA registers exhibit race behavior?
2. Is it related to memory barriers?such as __DSB, __ ISB, etc.

The assembly code for the system crash fault function is:

600b6dfc <EDMA_SetTransferConfig>:
600b6dfc: 291f cmp r1, #31 # r1 and 31 compare
600b6dfe: b5f8 push {r3, r4, r5, r6, r7, lr}
600b6e00: d82d bhi.n 600b6e5e <EDMA_SetTransferConfig+0x62> # if r1 > 31 jump 600b6e5e
600b6e02: 2a00 cmp r2, #0 # r2 and 0 compare
600b6e04: d03e beq.n 600b6e84 <EDMA_SetTransferConfig+0x88> # if r2 == 0 jump 600b6e84
600b6e06: 06de lsls r6, r3, #27 # r6 = r3 << 27
600b6e08: d136 bne.n 600b6e78 <EDMA_SetTransferConfig+0x7c> # crash pc

600b6e0a: 3180 adds r1, #128 ; 0x80
600b6e0c: 06c5 lsls r5, r0, #27
600b6e0e: ea4f 1441 mov.w r4, r1, lsl #5
600b6e12: eb00 1141 add.w r1, r0, r1, lsl #5
600b6e16: d128 bne.n 600b6e6a <EDMA_SetTransferConfig+0x6e>
_________________________________________________________________

Thank you very much for your answer
0 Kudos
Reply

674 Views
mayliu1
NXP Employee
NXP Employee

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.

mayliu1_0-1734685271058.png

If you consider this impact, I suggest you can use this SDK function "EDMA_SetChannelPreemptionConfig".
 

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

 

0 Kudos
Reply