AnsweredAssumed Answered

STM32F4 SPI DMA Double Buffer issue

Question asked by steinert.lukas.001 on Feb 17, 2014
Latest reply on Mar 30, 2014 by pal_l.szabolcs
Hi, 

I'm using the F407 (Discovery) as a SPI-Slave with DMA enabled and a "data ready" signaling line. I'm currently trying to transfer data in dual buffer mode (the host cpu might also send configuration data at random times), because the slave has to respond very quickly when a CS-Edge arrives, so there is no time to service a regular CS-EXTI-IRQ in order to set up the DMA in single buffer mode with the correct data pointer (which might be an empty message or data/status frames). So I choose dual buffer mode with a half-transfer completion interrupt to setup the next memory location to handle continous transfers. 

Everything runs smooth, as long as the host requests data and only receives empty messages which means that I do not modify the dma. But when I start a transfer by stopping the DMA, selecting the proper memory region for buffer 0, choosing buffer 0 as next to transfer and re-enabling the DMA stream, the SPI frames are shifted by one byte. The first byte is always either "0" or equal to the last byte of the previous frame which was transmitted by the DMA. I'm using direct-mode, so no FIFO involved here... The receive is in standard circular mode nd works nicely...

Any clue/solution on this problem? 

Init for the Tx Transfer:
01.DMA_DeInit(DMA1_Stream4);
02.DMA_InitStructure.DMA_Channel               = DMA_Channel_0;
03.DMA_InitStructure.DMA_DIR                   = DMA_DIR_MemoryToPeripheral;
04.DMA_InitStructure.DMA_Memory0BaseAddr       = (uint32_t)SPI_EmtpyBuffer;
05.DMA_InitStructure.DMA_BufferSize            = (uint16_t)SPI_BUFFER_SLOTLENGTH;
06.DMA_InitStructure.DMA_PeripheralBaseAddr    = (uint32_t)&SPI2->DR;
07.DMA_InitStructure.DMA_PeripheralInc         = DMA_PeripheralInc_Disable;
08.DMA_InitStructure.DMA_MemoryInc             = DMA_MemoryInc_Enable;
09.DMA_InitStructure.DMA_PeripheralDataSize    = DMA_PeripheralDataSize_Byte;
10.DMA_InitStructure.DMA_MemoryDataSize        = DMA_MemoryDataSize_Byte;
11.DMA_InitStructure.DMA_Mode                  = DMA_Mode_Normal;
12.DMA_InitStructure.DMA_Priority              = DMA_Priority_VeryHigh;
13.DMA_InitStructure.DMA_FIFOMode              = DMA_FIFOMode_Disable;
14.DMA_InitStructure.DMA_FIFOThreshold         = DMA_FIFOThreshold_1QuarterFull;
15.DMA_InitStructure.DMA_MemoryBurst           = DMA_MemoryBurst_Single;
16.DMA_InitStructure.DMA_PeripheralBurst       = DMA_PeripheralBurst_Single;
17. 
18.//Setup the Dual Buffer mode for the Tx DMA
19.DMA_DoubleBufferModeConfig(DMA1_Stream4, (uint32_t)SPI_EmtpyBuffer, DMA_Memory_0);
20.DMA_DoubleBufferModeCmd(DMA1_Stream4, ENABLE);
21.DMA_Init(DMA1_Stream4, &DMA_InitStructure);

My routine if my slave wants to send new data the host:
01.void SPI_Tx_Start(volatile uint8_t *pBuf)
02.{
03.    //Check if there is no ongoing transfer. No need to do anything if still transfering since HT-IRQ will check if data left to send
04.    if(SPI_CheckTxInProgress() == 0)
05.    {
06.        DMA_Cmd(DMA1_Stream4, DISABLE);
07.        //Setup the current DMA memory to the desired buffer
08.        if(DMA_GetCurrentMemoryTarget(DMA1_Stream4)== 0)
09.        {
10.            DMA_MemoryTargetConfig(DMA1_Stream4,(uint32_t)pBuf,DMA_Memory_0);
11.        }
12.        else
13.        {
14.            DMA_MemoryTargetConfig(DMA1_Stream4,(uint32_t)pBuf,DMA_Memory_1);
15.        }
16.        //Set the current data pointer to the entered buffer
17.        ptr_SPI_Tx_Current = pBuf;
18.        DMA_Cmd(DMA1_Stream4, ENABLE);
19. 
20.        //Increment current open pointer to storage
21.        SPI_Increment_TxOpen();
22. 
23.        //Signal that data is available
24.        SPI_Raise_IRQ();
25.    }
26.}


Outcomes