cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 Workaround for DMA data transfer > SPI fifo-buffer

HansPLJ
Associate III

Hi! 

I am working on a project where we are using DMA driven SPI-transmissions. I am using LPTIM1 to synchronize readouts of multiple SPI busses.

The setup works when the transmissions is equal or below 128 bits (for SPI1-SPI3). 

When HAL_DMA_MuxSyncConfigTypeDef.RequestNumber is above 4 (at DMA_PDATAALIGN_WORD and DMA_MDATAALIGN_WORD) it will not work. 

From what I can understand this is due to the size of the fifo registers of the SPI-peripheral. 

Is there a workaround for this? 

This is my current setup:

DMA_InitTypeDef txDMAinit;
DMA_InitTypeDef rxDMAinit;

spiHandle.Init.Mode = SPI_MODE_MASTER;
spiHandle.Init.Direction = SPI_DIRECTION_2LINES;
spiHandle.Init.DataSize = SPI_DATASIZE_32BIT;
spiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
spiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
spiHandle.Init.NSS = SPI_NSS_HARD_OUTPUT;
spiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
spiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
spiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
spiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
spiHandle.Init.CRCPolynomial = 0x0;
spiHandle.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
spiHandle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
spiHandle.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
spiHandle.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
spiHandle.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
spiHandle.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_04CYCLE;
spiHandle.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
spiHandle.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
spiHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
spiHandle.Init.IOSwap = SPI_IO_SWAP_DISABLE;

if(HAL_SPI_Init(&m_spiHandle)!= HAL_OK)
{
return StatusCode::STATUS_ERROR;
}

txDMAinit.Direction = DMA_MEMORY_TO_PERIPH;
txDMAinit.PeriphInc = DMA_PINC_DISABLE;
txDMAinit.MemInc = DMA_MINC_ENABLE;
txDMAinit.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
txDMAinit.MemDataAlignment = DMA_MDATAALIGN_WORD;
txDMAinit.Mode = DMA_CIRCULAR;
txDMAinit.Priority = DMA_PRIORITY_MEDIUM;
txDMAinit.FIFOMode = DMA_FIFOMODE_ENABLE;
txDMAinit.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;

rxDMAinit.Direction = DMA_PERIPH_TO_MEMORY;
rxDMAinit.PeriphInc = DMA_PINC_DISABLE;
rxDMAinit.MemInc = DMA_MINC_ENABLE;
rxDMAinit.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
rxDMAinit.MemDataAlignment = DMA_MDATAALIGN_WORD;
rxDMAinit.Mode = DMA_CIRCULAR;
rxDMAinit.Priority = DMA_PRIORITY_MEDIUM;
rxDMAinit.FIFOMode = DMA_FIFOMODE_ENABLE;
rxDMAinit.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;

pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_LPTIM1_OUT;
pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_FALLING;
pSyncConfig.SyncEnable = ENABLE;
pSyncConfig.EventEnable = DISABLE;
pSyncConfig.RequestNumber = 8;

hdma_spi1_tx.Instance = DMA1_Stream4;
hdma_spi1_tx.Init = txDMAinit;
hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX;

HAL_DMA_Init(&hdma_spi1_tx);

if((HAL_DMAEx_ConfigMuxSync(&hdma_spi1_tx, &pSyncConfig)) != HAL_OK)
{
return StatusCode::STATUS_ERROR;
}

__HAL_LINKDMA(&m_spiHandle,hdmatx,hdma_spi1_tx);

hdma_spi1_rx.Instance = DMA1_Stream1;
hdma_spi1_rx.Init = rxDMAinit;
hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX;

HAL_DMA_Init(&hdma_spi1_rx);

if((HAL_DMAEx_ConfigMuxSync(&hdma_spi1_rx, &pSyncConfig)) != HAL_OK)
{
return StatusCode::STATUS_ERROR;
}

__HAL_LINKDMA(&m_spiHandle,hdmarx,hdma_spi1_rx);

It only works for pSyncConfig.RequestNumber <= 4. 

Any suggestions for a workaround would be appreciated!

Best regards, 

Hans-Petter 

 

4 REPLIES 4

> it will not work

Elaborate.

JW

SofLit
ST Employee

@HansPLJ please use </> button to paste a code. See this post. I've edited your post

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
PS: Be polite in your reply. Otherwise, it will be reported as inappropriate and you will be permanently blacklisted from my help/support.
HansPLJ
Associate III

Thanks for your reply! I will try to elaborate

When Im using pSyncConfig.RequestNumber = 4, I am getting the expected behavior. At the current stage I am looping back MOSI to MISO and I am reading what I am sending. This is happening at the rate of LPTIM sync event at 16 kHz. 

After setting up the SPI, DMA and LPTIM I am using this function: 

#define SIZE_BUFFER       96
uint32_t __attribute__((section (".axi_sram1"))) RxBuff[SIZE_BUFFER];
uint32_t __attribute__((section (".axi_sram1"))) TxBuff[SIZE_BUFFER];

HAL_SPI_TransmitReceive_DMA(&hal.spi1.getHandle(), (uint8_t*)TxBuff, (uint8_t*)RxBuff, (uint16_t)SIZE_BUFFER);
HAL_LPTIM_PWM_Start(&hal.lptim1.getHandle(), LPTIM1_PERIODS, LPTIM1_PULSE_PERIODS);

From oscilloscope:

HansPLJ_1-1736837959208.png

Live watch of the rxBuffer

HansPLJ_0-1736837925174.png

My aim is to be able to do read more than 4 words at each LPTIM event without using interrupts.

When I adjust the pSyncConfig.RequestNumber = 6. 

I see in the oscilloscope that the readout is occuring at HW level: 

HansPLJ_2-1736839533353.png

In the live watch the buffer is only receiving the first 4 words:

HansPLJ_3-1736839629212.png

In the SPI SR the peripheral is flagging overrun (OVR). There are no error flags in the ISR register of the DMA peripheral. 

Is there a way I can change the settings in the DMA or SPI to have the DMA handle the data before overrun?

If you need more information, let me know. 

Best regards, 

Hans-Petter 

I don't see anything suspicious, but I am not familiar with the 'H7.

Does the SPI work in expected way if you don't use the DMAMUX synchronization?

(Btw. I don't think you'd need synchronization at the Rx path).

JW