3
votes

I'm using the DMA to manage some SPI transfers with an external flash. The first and last data bytes retrieved are invalid. I can live with the last byte being invalid (but would still like to know why) but not the first one.

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 a SPI transfer to have something in the SPIx->DR before DMA transfer starts but without success

while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPIx, (Uint16)0x00);

Why is this happening and how would you recommend fixing it?

EDIT: here is the defines 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 byte read 0 instead of 0xff. Here is the start and end of the transfer.

Start

End

To clarify, I'm using normal SPI instructions to send the read command and then I configure the DMA for the specific data length and start the transfer (the section where the SCLK is continuous). The Flash is empty (verified) which means everything is at 0xFF. The data buffer just gets 0 in the first and last bytes...

1
It would be much easier (to see what you are doing) if you just set up the hardware directly without this STLib crap in-between. However, I suspect, you disable SS too early, while the last or last two transfers are still underway. Wait for !BUSY. - too honest for this site
CS is enabled just before the DMA initialization and the DMA irqHandler disables it after checking the transferComplete flag. No idea what you mean by STLib crap though... - Tiwi13
The libraries provided by ST. There is no gain in not setting up the hardware directly. That stuff just adds bloat, possibly resulting in strange behaviour. If not that, it at least obfuscates the actualy code by having some setting here, some there, etc. - too honest for this site
However, if SS is not the point, you have to provide more info; e.g. use a debugger or MSO to see what's going on on the line actually. - too honest for this site
Added images of what's going on with the logic analyzer. - Tiwi13

1 Answers

2
votes

I suspect, you enable SS too late for the start while the SPI already starts transfering. And disable it too early for the end of the frame, while there are still bits being shifted.

For the start, first enable SPI, then start the DMA. For the end, wait until DMA complete (SPI !BUSY will not work, if the DMA is too slow to continously feed the SPI).