Skip to main content
TTaie.1
Associate
January 12, 2023
Question

In STM32G474RE, How to properly re-configure SPI peripheral during run-time (using DMA for both Rx/Tx channels) ? I need to increase data to be received & transmitted with SPI after some time of running. Thanks, Tal.T

  • January 12, 2023
  • 4 replies
  • 1967 views

Here's my code for re-configuring the SPI1 peripheral, but after that the data being corrupted (even if I re-configure the same size of the previous configuration):

void AppSpiReconfig(void * ulRxBuffAddr, void * ulTxBuffAddr, unsigned long ulSize)

{

LL_SPI_InitTypeDef SPI_InitStruct = {0};

/* Disable DMA channels to reset their configurations */

LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);

LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);

while((LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) && (LL_SPI_IsActiveFlag_BSY(SPI1) != 0))

{

};

LL_SPI_Disable(SPI1);

do {

LL_SPI_ReceiveData16(SPI1);

} while(LL_SPI_GetRxFIFOLevel(SPI1) != LL_SPI_RX_FIFO_EMPTY);

LL_SPI_DisableDMAReq_TX(SPI1);

LL_SPI_DisableDMAReq_RX(SPI1);

SET_BIT(RCC->APB2RSTR, RCC_APB2RSTR_SPI1RST);

CLEAR_BIT(RCC->APB2RSTR, RCC_APB2RSTR_SPI1RST);

while((LL_SPI_IsActiveFlag_BSY(SPI1) != 0))

{

};

/* SPI1 parameter configuration*/

SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;

SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;

SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_16BIT;

SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;

SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;

SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;

SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV4;

SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;

SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;

SPI_InitStruct.CRCPoly = 7;

LL_SPI_Init(SPI1, &SPI_InitStruct);

LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);

LL_SPI_EnableNSSPulseMgt(SPI1);

/* ------------------------------------------------------------------------------- */

/* Configure the DMA1_Channel2 functional parameters */

/* Prepare DMA data and length - RX */

LL_DMA_ConfigAddresses(DMA1,

LL_DMA_CHANNEL_1,

LL_SPI_DMA_GetRegAddr(SPI1), (unsigned long)ulRxBuffAddr,

LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));

LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, ulSize);

/* Enable DMA SPI RX request */

LL_SPI_EnableDMAReq_RX(SPI1);

/* Prepare DMA data and length - TX */

LL_DMA_ConfigAddresses( DMA1,

LL_DMA_CHANNEL_2,

(unsigned long)ulTxBuffAddr, LL_SPI_DMA_GetRegAddr(SPI1),

LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));

LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, ulSize);

/* Enable DMA SPI TX request */

LL_SPI_EnableDMAReq_TX(SPI1);

/* Enable DMA SPI TX/RX channels */

SpiDmaActivate();

/* Enabel SPI peripheral requests */

LL_SPI_Enable(SPI1);

}

This topic has been closed for replies.

4 replies

gbm
Lead III
January 13, 2023

You cannot continue to receive data after you disable SPI - these two actions should be reversed (if they are needed at all). Actually you don't need to do anything with SPI. It's enough to stop TX DMA, then complete and stop RX DMA, then program new RX DMA, then new TX DMA settings.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
TTaie.1
TTaie.1Author
Associate
January 13, 2023

Hi, thanks for your reply !

So you mean something like this :

  • disable DMA TX channel and wait for FTLVL & BSY to be cleared.
  • disable DMA RX channel and read all remain data in buffer until its empty
  • reconfigure the source/dest buffer and the length of each DMA channel
  • Enable the DMA channels

BTW, which API is preferred to stop DMA,

LL_DMA_DisableChannel or

LL_SPI_DisableDMAReq ?

Thanks,

Tal.T

Piranha
Principal III
January 14, 2023

The name LL_DMA_***() says that it configures the DMA peripheral. The other one configures the SPI peripheral - disables the DMA request generation.

S.Ma
Principal
January 14, 2023

I usually rely on dma rx completed transaction interrupt in master mode before preparing the next block size. Now some newer STM32 have an automated blocks linked list support to minimize the pause time between blocks. Remains NSS hw handling to make SPI HW bandwidth efficient.

TTaie.1
TTaie.1Author
Associate
January 15, 2023

Ok, thanks for the replies, I've changed my code according to what people said here to this:

void AppSpiReconfig(void * ulRxBuffAddr, void * ulTxBuffAddr, unsigned long ulSize)

{

/* Disable DMA channels to reset their configurations */

while(!(LL_DMA_IsActiveFlag_TC2(DMA1))) {};

LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);

while((LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) && (LL_SPI_IsActiveFlag_BSY(SPI1) != 0))

{

};

while(!(LL_DMA_IsActiveFlag_TC1(DMA1))) {};

LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);

do {

LL_SPI_ReceiveData16(SPI1);

} while(LL_SPI_GetRxFIFOLevel(SPI1) != LL_SPI_RX_FIFO_EMPTY);

/* ------------------------------------------------------------------------------- */

/* Configure the DMA1_Channel2 functional parameters */

/* Prepare DMA data and length - RX */

LL_DMA_ConfigAddresses(DMA1,

LL_DMA_CHANNEL_1,

LL_SPI_DMA_GetRegAddr(SPI1), (unsigned long)ulRxBuffAddr,

LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));

LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, ulSize);

LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);

/* Prepare DMA data and length - TX */

LL_DMA_ConfigAddresses( DMA1,

LL_DMA_CHANNEL_2,

(unsigned long)ulTxBuffAddr, LL_SPI_DMA_GetRegAddr(SPI1),

LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_2));

LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, ulSize);

LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);

}

Still the data keep arrive corrupted to the slave...

Any advice ?

S.Ma
Principal
January 15, 2023

When using DMA, avoid manual data push without it. Reprogram the DMA for your 2 bytes, even if less efficient.

I would not use fifo flags. Get the dma receive block complete info to prepare the next block. Damn.

Unless I couldn't dig it, Refman examples from Cube are like making a Frankeinstein prototype from molecules instead of stitching organs....

Pavel A.
Super User
January 15, 2023

> Refman examples from Cube are like making a Frankeinstein prototype from molecules instead of stitching organs.

ChatGPT, yeah ; )