cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F407 Discovery board SPI, DMA

40802528
Associate II
Posted on December 08, 2011 at 20:04

Hi all,

I am getting some problems with using SPI peripheral.

In the sample code, I see that we have to wait until receiving the ''response'' data after each data transfer.  Why we must do that? I mean when we write data to slave LIS302, we do not need receive the ''response'' data.

And another question is why we must write a ''dummy'' byte before receiving data from slave ? Does it need to keep clock in CLK line ? It is not mentioned in the datasheet.

Does anyone use the DMA with SPI ? Would you help me show steps (transaction) to transmit & receive data from LIS302.

Thank all !

#spi-dma-receive-rx-tx-stm32f4
18 REPLIES 18
lumley
Associate II
Posted on December 09, 2011 at 21:20

I have done my best to digest those examples. My current program can successfully read the SPI via polling. I loop through that polling test 10 times, and then go into DMA Mode. Here is my code for DMA.

I am trying to use SPI1. Rx = DMA2, Stream0, Channel3. Tx = DMA2, Stream5, Channel3 on an STM32F4. I am unsure about my PeripheralBaseAddress, but I have tried a few options. This code loops at while(!DMA_GetFlagStatus(DMA2_Stream5, DMA_FLAG_TCIF5));

//program initiates SPI1 and confirms that polling works.
#define tstBufferSize 5
GPIO_SetBits(GPIOA, GPIO_Pin_4); //Set CS Off
SPI_Cmd(SPI1, DISABLE);
uint16_t SPI_MASTER_Buffer_Rx[tstBufferSize] = {99,99,99,99,99};
uint16_t SPI_MASTER_Buffer_Tx[tstBufferSize] = {0x8000, 0, 0x7E00, 0x8003, 0};

RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_DMA2, ENABLE);

DMA_Cmd(DMA2_Stream0, DISABLE);
DMA_Cmd(DMA2_Stream5, DISABLE);
/* SPI_MASTER_Rx_DMA_Channel configuration ---------------------------------*/
DMA_DeInit(DMA2_Stream0);
DMA_InitTypeDef DMA_InitStructure;
DMA_StructInit(&DMA_InitStructure);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(SPI1_BASE + 0xC); //not sure about this
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI_MASTER_Buffer_Rx;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = tstBufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_Channel = DMA_Channel_3;
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
// DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA2_Stream0, &DMA_InitStructure);
/* SPI_MASTER_Tx_DMA_Channel configuration ---------------------------------*/
DMA_DeInit(DMA2_Stream5);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(SPI1_BASE + 0xC); //not sure about this
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)SPI_MASTER_Buffer_Tx;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_Init(DMA2_Stream5, &DMA_InitStructure);
/* Enable SPI_MASTER DMA Tx request */
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
/* Enable SPI_MASTER DMA Rx request */
SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_ClearFlag(SPI1, SPI_I2S_FLAG_TXE);
SPI_I2S_ClearFlag(SPI1, SPI_I2S_FLAG_RXNE);
GPIO_ResetBits(GPIOA, GPIO_Pin_4); //Set CS On
/* Enable SPI_MASTER */
SPI_Cmd(SPI1, ENABLE);
/* Enable DMA channels */
DMA_Cmd(DMA2_Stream0, ENABLE);
DMA_Cmd(DMA2_Stream5, ENABLE);
//while(!DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0));
while(!DMA_GetFlagStatus(DMA2_Stream5, DMA_FLAG_TCIF5));
GPIO_SetBits(GPIOA, GPIO_Pin_4); //Set CS Off
while (1)
{
}

From: clive1 Posted: Friday, December 09, 2011 1:23 PM Subject: STM32F407 Discovery board SPI, DMA

Is there a full duplex DMA SPI example that you can point me to?

Within Keil, and presumably IAR, you have V2.0.1 of the firmware library You have DMA for both Rx, Tx, SPI1 and SPI2 \Keil\ARM\Examples\ST\STM32F10xFWLib\Examples\DMA\SPI_RAM And a Tx example \Keil\ARM\Examples\ST\STM32F10xFWLib\Examples\SPI\DMA
lumley
Associate II
Posted on December 12, 2011 at 00:50

FYI, I believe my problem is that I should have had

SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx , ENABLE);

Instead of:

/* Enable SPI_MASTER DMA Tx request */

SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

/* Enable SPI_MASTER DMA Rx request */

SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx, ENABLE);

 

pawel_popiolek
Associate II
Posted on February 03, 2012 at 08:55

I have strange SPI DMA receive problem. Transmitting via SPI DMA works OK, receiving is written same to Tx. The problem is that DMA can't change data indicating by ''DMA_InitStructure.DMA_Memory0BaseAddr''. By hardware I connected MISO to VDD or GND. Result is the same - data after DMA doesn't change. Initialization is OK - both interrupt from DMA SPI RX works and ''while(!DMA_GetFlagStatus(FRAMDMARX, DMA_FLAG_TCIF3));'' works fine. I have no idea what's matter. I hope that somebody can help me. I'm using Atollic True Studio.

Code:

DMA_InitStructure.DMA_Channel = FRAMDMACHANNEL;

DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t) dane5;

DMA_InitStructure.DMA_PeripheralBaseAddr = FRAMDMASPIREG;

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_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_Init(FRAMDMARX, &DMA_InitStructure);

DMA_InitStructure.DMA_Channel = FRAMDMACHANNEL;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dane5;

DMA_InitStructure.DMA_PeripheralBaseAddr = FRAMDMASPIREG;

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_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

DMA_Init(FRAMDMATX, &DMA_InitStructure);

DMA_ITConfig(FRAMDMARX, DMA_IT_TC, ENABLE);

DMA_ITConfig(FRAMDMATX, DMA_IT_TC, ENABLE);

ilosc_danych=9;

danebuff.danebuforowane=(uint8_t*)malloc(ilosc_danych); //nie zapomniec zrobic free(dane) w programie glownym

DMA_InitStructure.DMA_BufferSize = ilosc_danych;

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dane5;

DMA_Init(FRAMDMARX, &DMA_InitStructure);

DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;

DMA_InitStructure.DMA_Memory0BaseAddr = 0;

DMA_Init(FRAMDMATX, &DMA_InitStructure);

SPI_I2S_SendData(FRAMSPI, 0x03); //wyslanie komendy startu odczytu

while (SPI_I2S_GetFlagStatus(FRAMSPI, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(FRAMSPI, dane_odczytywane>>16);//dwa najmlodsze bity to dwa najstarsze bity adresu

while (SPI_I2S_GetFlagStatus(FRAMSPI, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(FRAMSPI, dane_odczytywane>>8);//

while (SPI_I2S_GetFlagStatus(FRAMSPI, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(FRAMSPI, dane_odczytywane);//najmlodszy bajt adresu

 while (SPI_I2S_GetFlagStatus(FRAMSPI, SPI_I2S_FLAG_TXE) == RESET);

DMA_Cmd(FRAMDMARX, ENABLE);

DMA_Cmd(FRAMDMATX, ENABLE);

while(!DMA_GetFlagStatus(FRAMDMARX, DMA_FLAG_TCIF3));

for(i=0;i<10;i++)

{

USART_SendData(USART3, dane5[i]);

while (USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET);

}

In this code dane5 is uint8_t dane5[10];

but I tried with structure with pointer and malloc function.

I have DMA FIFO problem. I think, that's probably because parallel using TX and RX.

Any solutions??

Posted on February 03, 2012 at 13:35

Unfortunately there is a lot of initialization code missing, and defines for which we do not see values for. Try to present a clear and complete example.

Does it work in polled mode?

You should probably make sure RXNE is clear before lighting off the DMA.

Also be aware that some of the RAM is not accessible via DMA (64KB CCM).

Adding some diagnostics to print out addresses might help there.

Check that clocks are initialized properly.

Check that pins are configured properly.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
pawel_popiolek
Associate II
Posted on February 03, 2012 at 14:45

Posted on February 03, 2012 at 16:33

Aren't you missing :

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

or

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx,, ENABLE);

 

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
pawel_popiolek
Associate II
Posted on February 04, 2012 at 22:25

 

Aren't you missing :

 

 

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

 

 SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);

 

 or

 

SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx,, ENABLE);

 

 

No, I tried both - result was the same. TX had been working, so probably settings are OK (when RX settings are the same as TX settings). I'm suspecting DMA mode or SPI mode, maybe parallel RX and TX (on this forum I found, that's good way).

 

On Monday I'll try on different SPI port (SPI1 instead SPI2).

Added on Monday:

The problem was in initialization. I was using one initStructure for TX and RX. The TX settings rewrite my RX settings. 

Thank You for help.

gordon239955_st
Associate III
Posted on June 18, 2012 at 17:02

My apologies for hijacking the thread here, but I have a related problem.

STM32F205, SPI3.

I appear able to get the SPI to send & receive the first transaction, but subsequent transactions don't go. I've tracked this down to an apparent anomly, but can't presently see why the anomaly occurs. I'm hoping someone else can give advice.

I set up SPI3 and the DMA, then to Tx/Rx, I do the following:

    // Set up ready to receive

    DMA1_Stream0->NDTR = SPI_TxRx_length; // How much to receive

    DMA1_Stream0->M0AR = (uint32_t)pRxBuffer;

    DMA1_Stream0->CR |= (uint32_t)DMA_SxCR_EN;

    // Set up ready to transmit

    DMA1_Stream5->NDTR = SPI_TxRx_length; // How much to send

    DMA1_Stream5->M0AR = (uint32_t)SPI_TxBuffer;

    DMA1_Stream5->CR |= (uint32_t)DMA_SxCR_EN;

    // let her go!

    SPI_I2S_DMACmd(SPI3, SPI_I2S_DMAReq_Tx|SPI_I2S_DMAReq_Rx, ENABLE );

The first time through this ode, the DMA+SPI appear to work, in that I see clock and data and get data back, though as it's an unwritten EEPROM, the data is all 0xFFs, which doesn't prove that much.

The second time through this code, the DMA enable for transmit line:

    DMA1_Stream5->CR |= (uint32_t)DMA_SxCR_EN;

Does not set the Enable bit, so the DMA does not run.

So far I've failed to find why the Enable bit will not set, or possibly is cleared again before I see it.

gordon239955_st
Associate III
Posted on June 18, 2012 at 17:37

Asking the question is so often the key to answering it.

I've just learned I have to clear the TCIF flag before I can set Enable.