cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F10x SPI DMA sync problem

bob
Associate II
Posted on October 28, 2014 at 12:16

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?

#stm32f10x-spi-dma-sync
7 REPLIES 7
Posted on October 28, 2014 at 20:10

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

What is

SPI_BUFFER_SIZE?

JW

bob
Associate II
Posted on October 29, 2014 at 09:01

Hi Jan, 

SPI_BUFFER_SIZE = 50

50 elements of integer type

Posted on October 29, 2014 at 09:33

By ''integer'' you mean ''int'', i.e. ''int32_t'', presumably.

Then, as

DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_HalfWord;

you transfer 50x16 bits, which is 25x32 bits.

These damn' computers do what you tell them to do, not what you think you told them to do.

JW

bob
Associate II
Posted on October 29, 2014 at 09:55

Hi Jan,

I don't understand.

telling 

DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_HalfWord;

should mean I want 

DMA_InitStructure.

 DMA_PeripheralDataSize_HalfWord (16bits) to be transmitted, right? If not, what should it be?

DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_Word;?

Posted on October 29, 2014 at 10:46

> DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_Word;?

No. You want the DMA to transfer one halfword (16-bit) at a time

, as that's the width of the SPI data register, into which/from which the data is going.

But if you write:

DMA_InitStructure.

DMA_BufferSize

  = SPI_BUFFER_SIZE;

DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_HalfWord;

you transfer SPI_BUFFER_SIZE x

HalfWord

, which is exactly the 25 words you experience.

JW

bob
Associate II
Posted on October 30, 2014 at 10:32

From: waclawek.jan

Posted: Wednesday, October 29, 2014 10:46 AM

Subject: STM32F10x SPI DMA sync problem

> DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_Word;?

No. You want the DMA to transfer one halfword (16-bit) at a time

, as that's the width of the SPI data register, into which/from which the data is going.

But if you write:

DMA_InitStructure.

DMA_BufferSize

  = SPI_BUFFER_SIZE;

DMA_InitStructure.

DMA_PeripheralDataSize

  = DMA_PeripheralDataSize_HalfWord;

you transfer SPI_BUFFER_SIZE x

HalfWord

, which is exactly the 25 words you experience.

JW

bob
Associate II
Posted on December 11, 2014 at 09:40

Finally found the problem. As most of the time, solution is very simple.

I used to write code for 8 and 16 bits micro. There an integer is always 16 bit.

In a 32bit system, integer is 32 bits if not specified. After changing 'integer' to int16_t, the problem was solved.

Thanks for the support Jan!