2014-09-17 05:05 PM
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.2014-09-17 09:35 PM
What is the state of respective DMA status bits?
You could also post the respective DMA channel's registers' content. JW2014-09-18 06:44 AM
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 0SxNDT(number of data) 0 However, TEIF2 which is for RX shows 1 means transfer error.Here are the registers in DMA stream2.EN bit 0SxNDT 00000077For the data amount, I set DMA_BufferSize 120 which is 0x78Apparently, something wrong for the DMA.2014-09-18 07:02 AM
I meant, post content of *all* registers of the stream.
JW2014-09-18 07:22 AM
2014-09-18 07:34 AM
You never said which derivative do you use, but if it's STM32F4, SxM0A points into CCM, which is not accessible from DMA.
JW2014-09-18 07:35 AM
Suggest you using internal SRAM, not CCMRAM (DMA not supported) or SDRAM
Use the DMA Status NOT the IT Status Use symmetrical transfers2014-09-18 07:46 AM
Thank you for JW and clive1 's response.
I am using internal SRAM.Clive, could you explain more about what you said?2014-09-18 07:57 AM
> 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? JW2014-09-18 08:01 AM
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.