2025-01-13 05:44 AM - last edited on 2025-01-13 07:11 AM by SofLit
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
2025-01-13 07:08 AM
> it will not work
Elaborate.
JW
2025-01-13 07:11 AM
@HansPLJ please use </> button to paste a code. See this post. I've edited your post
2025-01-13 11:33 PM
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:
Live watch of the rxBuffer
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:
In the live watch the buffer is only receiving the first 4 words:
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
2025-01-14 04:02 AM
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