Invalid data when using DMA for SPI with STM32
I am using DMA to manage some SPI transmissions with external flash. The selected first and last data are invalid. I can live with the last invalid byte (but would still like to know why), but not the first.
Here's the DMA initialization
// Deinitialize DMA Streams
DMA_DeInit(DMA_TX_STREAM);
DMA_DeInit(DMA_RX_STREAM);
// Initialize buffer size
DMA_InitStructure.DMA_BufferSize = *nbData;
// Rest of Init
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_PeripheralBaseAddr = (Uint32)&(SPIx->DR);
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// Configure Tx DMA
DMA_InitStructure.DMA_Channel = DMA_TX_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
DMA_InitStructure.DMA_Memory0BaseAddr = (Uint32) data;
DMA_Init(DMA_TX_STREAM, &DMA_InitStructure);
// Configure Rx DMA
DMA_InitStructure.DMA_Channel = DMA_RX_CHANNEL;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) data;
DMA_Init(DMA_RX_STREAM, &DMA_InitStructure);
DMA_ITConfig(DMA_RX_STREAM, DMA_IT_TC, ENABLE);
// Enable the DMA Stream IRQ Channel
NVIC_InitStructure.NVIC_IRQChannel = DMA_RX_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable DMA Streams
DMA_Cmd(DMA_RX_STREAM, ENABLE);
DMA_Cmd(DMA_TX_STREAM, ENABLE);
// Enable DMA SPI request
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_DMACmd(SPIx, SPI_I2S_DMAReq_Tx, ENABLE);
I tried pushing SPI transfer to something in SPIx-> DR before starting DMA transfer but with no success
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPIx, (Uint16)0x00);
Why is this happening and how could you fix it?
EDIT: used here are used
#define SPIx SPI2
#define DMA_RX_STREAM DMA1_Stream3
#define DMA_RX_CHANNEL DMA_Channel_0
#define DMA_RX_IRQ DMA1_Stream3_IRQn
#define DMA_IT_TCIF_RX DMA_IT_TCIF3
#define DMA_TX_STREAM DMA1_Stream4
#define DMA_TX_CHANNEL DMA_Channel_0
#define DMA_TX_IRQ DMA1_Stream4_IRQn
#define DMA_IT_TCIF_TX DMA_IT_TCIF4
EDIT 2: The first and last bytes are counted as 0 instead of 0xff. Here's the beginning and end of the show.
To clarify, I use normal SPI instructions to send the read command, and then I configure the DMA for a specific data length and start transfer (the section where SCLK is continuous). The flash is empty (tested) which means everything is at 0xFF. The data buffer just gets 0 in the first and last bytes ...
source to share
I suspect you turned on SS too late to start while SPI is already starting to transmit. And turn it off too early for the end of the frame while still the bit is shifted.
First, enable SPI, then start DMA. Wait until DMA is complete to complete (SPI !BUSY
will not work if DMA is too slow to support SPI continuously).
source to share