2014-10-28 04:16 AM
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-sync2014-10-28 12:10 PM
> A second problem is that I seems to receive only 50% (first 24 integers) of the databuffer.
What isSPI_BUFFER_SIZE?
JW2014-10-29 01:01 AM
SPI_BUFFER_SIZE = 50
50 elements of integer type2014-10-29 01:33 AM
By ''integer'' you mean ''int'', i.e. ''int32_t'', presumably.
Then, asDMA_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. JW2014-10-29 01:55 AM
Hi Jan,
I don't understand.tellingDMA_InitStructure.
DMA_PeripheralDataSize
= DMA_PeripheralDataSize_HalfWord;
should mean I wantDMA_InitStructure.
DMA_PeripheralDataSize_HalfWord (16bits) to be transmitted, right? If not, what should it be?
DMA_InitStructure.
DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Word;?
2014-10-29 02:46 AM
> 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 xHalfWord
, which is exactly the 25 words you experience. JW2014-10-30 02:32 AM
> 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 xHalfWord
, which is exactly the 25 words you experience. JW2014-12-11 12:40 AM