2023-01-12 09:44 AM
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);
}
2023-01-13 01:08 AM
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.
2023-01-13 02:08 AM
Hi, thanks for your reply !
So you mean something like this :
BTW, which API is preferred to stop DMA,
LL_DMA_DisableChannel or
LL_SPI_DisableDMAReq ?
Thanks,
Tal.T
2023-01-13 04:48 PM
The name LL_DMA_***() says that it configures the DMA peripheral. The other one configures the SPI peripheral - disables the DMA request generation.
2023-01-13 09:42 PM
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.
2023-01-15 12:50 AM
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 ?
2023-01-15 01:30 AM
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....
2023-01-15 03:26 AM
> Refman examples from Cube are like making a Frankeinstein prototype from molecules instead of stitching organs.
ChatGPT, yeah ; )