cancel
Showing results for 
Search instead for 
Did you mean: 

SPI with DMA on STM32F437

alexpes59
Associate II
Posted on June 23, 2015 at 15:39

Hi,

I'm having troubles setting up the DMA with SPI2 on a STM32F4 I am using the streams 3 and 4 on channel 0 as said in the datasheet. Here is my init code :

void
MX_SPI2_Init(
void
)
{
DMA_InitTypeDef DMA_InitStructure; 
//Variable used to setup the DMA
hspi2.Instance = SPI2;
hspi2.Init.Mode = SPI_MODE_MASTER;
hspi2.Init.Direction = SPI_DIRECTION_2LINES;
hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi2.Init.NSS = SPI_NSS_SOFT;
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi2.Init.TIMode = SPI_TIMODE_DISABLED;
hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
hspi2.hdmarx =&dmarx;
hspi2.hdmatx =&dmatx;
HAL_SPI_Init(&hspi2);
}

Then the MSP init :


__DMA1_CLK_ENABLE();


dmatx.Init.Channel = DMA_CHANNEL_0;

dmatx.Init.Direction = DMA_MEMORY_TO_PERIPH;

dmatx.Init.PeriphInc = DMA_PINC_DISABLE; 

dmatx.Init.MemInc = DMA_MINC_DISABLE; 

dmatx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

dmatx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; 

dmatx.Init.Mode = DMA_NORMAL; 

dmatx.Init.Priority = DMA_PRIORITY_HIGH; 

dmatx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 

dmatx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

dmatx.Init.MemBurst = DMA_MBURST_SINGLE; 

dmatx.Init.PeriphBurst = DMA_PBURST_SINGLE; 


dmatx.Instance = DMA1_Stream4;



HAL_DMA_Init(&dmatx);

__HAL_LINKDMA(&hspi2, hdmatx, dmatx);

HAL_NVIC_SetPriority(DMA1_Stream4_IRQn,8,0);

HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);



dmarx.Init.Channel = DMA_CHANNEL_0;

dmarx.Init.Direction = DMA_PERIPH_TO_MEMORY;

dmarx.Init.PeriphInc = DMA_PINC_DISABLE; 

dmarx.Init.MemInc = DMA_MINC_DISABLE; 

dmarx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

dmarx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; 

dmarx.Init.Mode = DMA_NORMAL; 

dmarx.Init.Priority = DMA_PRIORITY_MEDIUM; 

dmarx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; 

dmarx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;

dmarx.Init.MemBurst = DMA_MBURST_SINGLE; 

dmarx.Init.PeriphBurst = DMA_PBURST_SINGLE; 


dmarx.Instance = DMA1_Stream3;



HAL_DMA_Init(&dmarx);

__HAL_LINKDMA(&hspi2, hdmarx, dmarx);

HAL_NVIC_SetPriority(DMA1_Stream3_IRQn,8,0);

HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);

Then I callHAL_SPI_Transmit_DMA from my code which prepares the DMA transmission and registers the interrupt. The TX interrupt is then fired with no error flags, but the code hangs in the SPI transmit callback function because the TXE flags never resets in the SPI. My DMA seems to be correctly configured, the target address is the address of the SPI DR register, the byte count is correct, so is the source address. If I check with a scope, nothing comes out of the µC (it works without the DMA). So I guess there's something missing in my initialization, but I can't figure out what... Any ideas ? Thanks ! #spi-dma #dma-spi-stm32
3 REPLIES 3
jpeacock
Associate II
Posted on June 23, 2015 at 22:45

I don't use the HAL but you might be seeing an error because of RX overrun.  SPI is always bi-directional, where transmitting also generates the clock for receiving.  After a transmit you have to clear the receiver or you get an overrun.

With the Std Library I set up both TX and RX DMA streams, RX with higher priority, but when sending the RX DMA points to a dummy location and address increment is disabled, effectively throwing away whatever is clocked in.  RX DMA should be a higher priority to ensure it always clears RX buffer before the next transmit.

Check the DMA errors to see if the DMA is stopping.  If so, check the SPI status to see if you have an RX overrun.

Same procedure for receiving with DMA, but set the TX to a dummy location with no address increment so it only generates a clock.

  Jack Peacock

alexpes59
Associate II
Posted on June 24, 2015 at 09:24

Hi Jack, thanks for the reply.

The HAL actually does all of what you are suggesting in the TX/RX sequence, and what bugs me is that the registers don't show any sign of error (and RXNE stays at 0 in the SPI2)

The TXDMAEN in SPI2 stays at 1 and the TXE /DR stay at 0 after the DMA transmission. It's like the DMA wrote something in DR but the SPI buffer is never sent, so TXE never goes back to 1.

The DMA registers are also indicating that the transfer went fine, the PAR is set to the address of the SPI DR register (0x4000380C), the source address is my buffer's address, the TCIF interrupt is fired.

The weird thing in the SPI SR is that BSY is not set. It's like the SPI is not initiating a transfer.

jpeacock
Associate II
Posted on June 29, 2015 at 14:24

Is your SPI peripheral clock enabled in RCC?

  Jack Peacock