cancel
Showing results for 
Search instead for 
Did you mean: 

SPI DMA Rx transfer error

intcd31
Associate II
Posted on September 18, 2014 at 02:05

I want to change polling SPI to DMA SPI. Now I get stuck and have looked up lots of material. None of them is working for me. 

The original polling SPI code works fine. I implemented the following code for the DMA. Something weird happened here. It seems there is no problem for TX  but the RX DMA gets transfer error. SxNDT register still 0x78. I don't know the reason.

1. Should the amount of RX data be the same as TX? But Rx doesn't receive anything.

2. The TX source is from external memory by FMC. Does it matter?

void SPI1_DMA_Configuration()

{

    DMA_InitTypeDef DMA_InitStructure;

    DMA_Cmd(DMA2_Stream3, DISABLE);

    DMA_Cmd(DMA2_Stream2, DISABLE);

    DMA_ClearITPendingBit(DMA2_Stream3,DMA_IT_TCIF3);

    DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);

    DMA_DeInit(DMA2_Stream3);

    while (DMA_GetCmdStatus (DMA2_Stream3) != DISABLE);

    DMA_StructInit(&DMA_InitStructure);

    // TX

    DMA_InitStructure.DMA_Channel = DMA_Channel_3;

    DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)(&SPI1->DR));

    DMA_InitStructure.DMA_BufferSize = 10000;

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) HEADER_ADDR;

    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//DMA_PeripheralDataSize_HalfWord;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//DMA_MemoryDataSize_HalfWord;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA2_Stream3, &DMA_InitStructure);

    // RX

    DMA_DeInit(DMA2_Stream2);

    while (DMA_GetCmdStatus (DMA2_Stream2) != DISABLE);

    DMA_StructInit(&DMA_InitStructure);

    DMA_InitStructure.DMA_Channel = DMA_Channel_3;

    DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)(&SPI1->DR));

    DMA_InitStructure.DMA_BufferSize = 120;

    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) &SPIReceiveBuffer[0];

    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//DMA_PeripheralDataSize_HalfWord;

    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//DMA_MemoryDataSize_HalfWord;

    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

    DMA_Init(DMA2_Stream2, &DMA_InitStructure);

    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx, ENABLE);

    SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx, ENABLE);

    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));                // wait for empty TX buffer

    DMA_Cmd(DMA2_Stream2, ENABLE);

    DMA_Cmd(DMA2_Stream3, ENABLE);

    

    while ( DMA_GetCmdStatus(DMA2_Stream3) != ENABLE );

    while ( DMA_GetCmdStatus(DMA2_Stream2) != ENABLE ); 

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, DISABLE);

}

This is my first time to ask questions. Thank you for your help.
11 REPLIES 11
Posted on September 18, 2014 at 06:35

What is the state of respective DMA status bits?

You could also post the respective DMA channel's registers' content.

JW
intcd31
Associate II
Posted on September 18, 2014 at 15:44

I set a break point at SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, DISABLE);

TCIF3 which is for TX shows 1 means transfer complete.

The registers in DMA stream3 have no problems.

EN bit 0

SxNDT(number of data) 0 

However, TEIF2 which is for RX shows 1 means transfer error.

Here are the registers in DMA stream2.

EN bit 0

SxNDT 00000077

For the data amount, I set DMA_BufferSize 120 which is 0x78

Apparently, something wrong for the DMA.

Posted on September 18, 2014 at 16:02

I meant, post content of *all* registers of the stream.

JW

intcd31
Associate II
Posted on September 18, 2014 at 16:22

0690X00000605AAQAY.png

Posted on September 18, 2014 at 16:34

You never said which derivative do you use, but if it's STM32F4, SxM0A points into CCM, which is not accessible from DMA.

JW
Posted on September 18, 2014 at 16:35

Suggest you using internal SRAM, not CCMRAM (DMA not supported) or SDRAM

Use the DMA Status NOT the IT Status

Use symmetrical transfers
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
intcd31
Associate II
Posted on September 18, 2014 at 16:46

Thank you for JW and clive1 's response.

I am using internal SRAM.

Clive, could you explain more about what you said?

Posted on September 18, 2014 at 16:57

> I am using internal SRAM.

The content of SxM0A register indicates, that you are using the CCM RAM as the target for the Rx DMA, and the DMA controller can't access it. Read the manual to learn what is CCM RAM - there are several internal RAMs in your device (which you still failed to identify).

I guess you placed the Rx buffer onto the stack or dynamically allocated into heap, and you have set stack and heap into the CCM RAM in your toolchain. Read the manual of your toolchain to learn how to place a buffer into an explicit memory area.

---

Clive, what do you mean by symmetrical transfers?

JW

intcd31
Associate II
Posted on September 18, 2014 at 17:01

I set the RX DMA_Memory0BaseAddr to 0xC0000000 which is the starting address for external SDRAM. There is no transfer error anymore.

But it seems like the bit I got is wrong. At least, there is a progress.