AnsweredAssumed Answered

STM32F10x SPI DMA sync problem

Question asked by van_der_putten.bob on Oct 28, 2014
Latest reply on Dec 11, 2014 by van_der_putten.bob

I use two STM32F103R8 controllers that will communicate full duplex SPI with DMA, transmitting 50 integers from master to slave and vice verse.
I can't get the data synchronized properly. It seems that the slave is transmitting the data one int shifted (first byte is always 0000, and should contain a package counter).

A second problem is that I seems to receive only 50% (first 24 integers) of the databuffer.

 

I initiated SPI:

SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;

PI_InitStructure.SPI_DataSize = SPI_DataSize_16b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 7;

SPI_Init(SPI1, &SPI_InitStructure);

 

Then added DMA transfer:

DMA_InitTypeDef DMA_InitStructure;

//    Configure the DMA controller

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

//init DMA1 Channel 3 for Transmission.

DMA_DeInit(DMA_SPI_TX_CHANNEL);

DMA_StructInit(&DMA_InitStructure); //Fills each DMA_InitStruct member with its default value.

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

DMA_InitStructure.DMA_MemoryBaseAddr  = (uint32_t) &SPI_Slave_MISO_TX_Buffer;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

DMA_InitStructure.DMA_BufferSize  = SPI_BUFFER_SIZE;

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_Init(DMA_SPI_TX_CHANNEL, &DMA_InitStructure);//Initializes the DMAy Channelx according to the specified parameters in the DMA_InitStruct.

 

//init DMA1 Channel 2 for Reception.

DMA_DeInit(DMA_SPI_RX_CHANNEL);

DMA_StructInit(&DMA_InitStructure);

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

DMA_InitStructure.DMA_MemoryBaseAddr  = (uint32_t) &SPI_Slave_MOSI_RX_Buffer;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_BufferSize  = SPI_BUFFER_SIZE;

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_Init(DMA_SPI_RX_CHANNEL, &DMA_InitStructure);

 

 

DMA_NVIC_Configuration();

 

DMA_ITConfig(DMA_SPI_RX_CHANNEL, DMA_IT_TC, ENABLE);

DMA_ITConfig(DMA_SPI_TX_CHANNEL, DMA_IT_TC, ENABLE);  //Enable DMA1_Channel3 Transmit interrupt

 

Whan the master finished the transmission, I use a hardware interrupt on the slave to stoop the transmission and prepare the next transmission.:

Interrupt:

if (DMA_GetITStatus(DMA1_IT_TC3) == SET)

{

      DMA_ClearITPendingBit(DMA1_IT_TC3);

      while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY) == SET){

            }

      SPI_Cmd(SPI_PORT, DISABLE);

      DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, DISABLE);

      SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, DISABLE);

      DMA_Cmd(DMA1_Channel3, DISABLE);

 

      while (DMA1_Channel3->CCR & DMA_CCR2_EN); // wait until DMA is actually off

 

      DMA_SetCurrDataCounter(DMA_SPI_RX_CHANNEL, SPI_BUFFER_SIZE);      // Set the number of transfers

 

      DMA_ClearITPendingBit(DMA1_IT_GL3);       // clear again

            DMA_ClearFlag(DMA1_FLAG_GL3);       // Clear the global flag

}

 

Outside the interrupt I re-init the SPI and DMA again for the next transmission:

InitSPI_DMA_Transfer();

 

SPI_Cmd(SPI_PORT, ENABLE);

 

SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Tx,ENABLE);

SPI_I2S_DMACmd(SPI1,SPI_I2S_DMAReq_Rx,ENABLE);

DMA_Cmd(DMA_SPI_TX_CHANNEL,ENABLE);

DMA_Cmd(DMA_SPI_RX_CHANNEL,ENABLE);

 Is there anyone who can help?

 

Outcomes