cancel
Showing results for 
Search instead for 
Did you mean: 

SPI RX Buffer via DMA Too Big

jvavra
Associate III
Posted on February 13, 2014 at 14:07

I've set up my DMA to transfer 106 half-words via the SPI to a memory buffer. I am quite confident that my buffer size is correct. However, when the transfer actually occurs, it is twice the size I expect (and is consequently stepping on some global variables). Because the transfer is all 0xFFs, I can't tell if I'm getting 212 half-words, 106 full-words, or two 106 half-word ''packets'' back-to-back and somehow the destination pointer is getting scrambled. If I look at the NDTR register for that stream in my IDE just before it transfers, it says I have 106 data items, leading me to believe the case is 106 full-words, but then again it also says the memory and peripheral data sizes are set to half-words so I don't know which to believe.

Any thoughts are appreciated. Sample DMA/SPI setup:

void SPI_Configuration()

{

   StopSPI();                                                                   //Stop DMA, SPI

   /***************************

   //     SPI1               //

   ***************************/

   SPI1_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

   SPI1_InitStructure.SPI_Mode = SPI_Mode_Master;

   SPI1_InitStructure.SPI_DataSize = SPI_DataSize_16b;

   SPI1_InitStructure.SPI_CPOL = SPI_CPOL_Low;

   SPI1_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

   SPI1_InitStructure.SPI_NSS = SPI_NSS_Soft;

   SPI1_InitStructure.SPI_BaudRatePrescaler = SPI1SCALER;

   SPI1_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

   SPI1_InitStructure.SPI_CRCPolynomial = 7;

   SPI_Init(SPI1, &SPI1_InitStructure);

  

   // Rx Channel

   DMA_DeInit(DMA2_Stream2);

   DMA_StructInit(&SPI1RX_DMA_InitStructure);

   SPI1RX_DMA_InitStructure.DMA_Channel = DMA_Channel_3;

   SPI1RX_DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR);

   SPI1RX_DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&g_spi1_adc_data;

   SPI1RX_DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

   SPI1RX_DMA_InitStructure.DMA_BufferSize = g_chain1_buffer_size;

   SPI1RX_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

   SPI1RX_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

   SPI1RX_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

   SPI1RX_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

   SPI1RX_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

   SPI1RX_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

   DMA_Init(DMA2_Stream2, &SPI1RX_DMA_InitStructure);

   // Enable DMA Stream Transfer Complete interrupt

   DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);

  

   // Tx Channel

   DMA_DeInit(DMA2_Stream3);

   DMA_StructInit(&SPI1TX_DMA_InitStructure);

   SPI1TX_DMA_InitStructure.DMA_Channel = DMA_Channel_3;

   SPI1TX_DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR);

   SPI1TX_DMA_InitStructure.DMA_Memory0BaseAddr = g_spi1_config_buf_base_ptr;

   SPI1TX_DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

   SPI1TX_DMA_InitStructure.DMA_BufferSize = g_chain1_buffer_size;

   SPI1TX_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

   SPI1TX_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

   SPI1TX_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

   SPI1TX_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

   SPI1TX_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

   SPI1TX_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  

   DMA_Init(DMA2_Stream3, &SPI1TX_DMA_InitStructure);

   // Enable SPI1

   SPI_Cmd(SPI1, ENABLE);

 

   // Enable DMA request

   SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);

}

#dma #stm32 #spi
15 REPLIES 15
Posted on February 13, 2014 at 14:20

g_chain1_buffer_size = number of 16-bit words to transfer

The DMA shouldn't overflow it's described buffer. You could make yourself a large buffer, put a fill character in it, and then observe how much gets over written. Avoid DMA to auto/local variables.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jvavra
Associate III
Posted on February 13, 2014 at 14:24

Clive,

Thanks for the reply. I have confirmed that g_chain1_buffer_size is the number that I want (106). And without creating a larger buffer, I can tell pretty easily what size it's actually writing by viewing the memory starting at the destination pointer in my IDE. It's actually sending exactly twice what I expect (212 16-bit integers, instead of 106).

bpacan
Associate II
Posted on February 13, 2014 at 14:59

Please try enable only DMA TX request - last line. Configured as full-duplex should also trigger a DMA RX, I hope.

jvavra
Associate III
Posted on February 13, 2014 at 15:24

Thank you for the reply. So I changed the last line to:

   // Enable DMA request

   SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);

However, now I get NO data transferred at all. I think you may be on to something here: I just noticed that before I made this change, when I see this ''too large'' DMA transfer, both the RX stream and TX stream (which each have the same size buffer) have their NDTR registers cleared. Can you elaborate on why you say ''Configured as full-duplex should also trigger a DMA RX, I hope.''? I would not expect to receive anything when only the TX DMA transfer is enabled, but I may be missing something important.

Thanks!

 

francescatodiego
Associate II
Posted on February 13, 2014 at 16:01

DMA TX transfer is enabled ?

DMA_Cmd (DMA2_stream3,  ENABLE);

You can post also the DMA handler procedure called when transfer is complete

jvavra
Associate III
Posted on February 13, 2014 at 16:29

Yes, it's when I actually enable the DMA that I see this overrun transfer:

DMA2_Stream3->CR |= (u32)DMA_SxCR_EN;

I also notice that I get a FIFO error for this TX stream; in searching it appears that getting one of these error flags is normal since I enable the SPI before enabling the DMA. Can anyone confirm?

jvavra
Associate III
Posted on February 13, 2014 at 16:59

I am thoroughly cinfused now: I changed the buffer size on the TX side of the config, trying to verify if it was indeed the TX stream contributing to the ovverun. Changed like this:

   // Tx Channel

   DMA_DeInit(DMA2_Stream3);

   DMA_StructInit(&SPI1TX_DMA_InitStructure);

   SPI1TX_DMA_InitStructure.DMA_Channel = DMA_Channel_3;

   SPI1TX_DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(SPI1->DR);

   SPI1TX_DMA_InitStructure.DMA_Memory0BaseAddr = g_spi1_config_buf_base_ptr;

   SPI1TX_DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;

   SPI1TX_DMA_InitStructure.DMA_BufferSize = (g_chain1_buffer_size - 20);

 

   SPI1TX_DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

   SPI1TX_DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

   SPI1TX_DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

   SPI1TX_DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

   SPI1TX_DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

   SPI1TX_DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;  

   DMA_Init(DMA2_Stream3, &SPI1TX_DMA_InitStructure);

I expected I might see the total transfer to decrease by 20. Instead, it decreased by 40. It's as if the TX stream ONLY is writing to memory, instead of sending from memory to my peripheral. 

Does this make sense to anyone? 

Posted on February 13, 2014 at 18:42

Does this make sense to anyone? 

I'm confused too, present a complete test case that illustrates the problem. There are other things going on here, and I lack context.
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
jvavra
Associate III
Posted on February 13, 2014 at 20:09

The original post was too long to process during our migration. Please click on the provided URL to read the original post. https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I6e2&d=%2Fa%2F0X0000000bsN%2FH2zZCIvrAbIGNqJ8Sui91UDnnMSRjyty5o2TglYZpO0&asPdf=false