Skip to main content
aliMesut
Associate III
December 1, 2021
Question

Stm32mp157c Spi Dma Transfer Stuck Problem

  • December 1, 2021
  • 7 replies
  • 2555 views

Hello,

I am working stm32mp157c. I want to send the data coming from ipcc to m4 to another chip with spi.

My code is;

void MX_SPI4_Init(void)
{
 hspi4.Instance = SPI4;
 
 hspi4.Init.Mode = SPI_MODE_MASTER;
 
 hspi4.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
 
 hspi4.Init.DataSize = SPI_DATASIZE_8BIT;
 
 hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
 
 hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;
 
 hspi4.Init.NSS = SPI_NSS_HARD_OUTPUT;
 
 hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
 
 hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
 
 hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
 
 hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 
 hspi4.Init.CRCPolynomial = 0x0;
 
 hspi4.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
 
 hspi4.Init.NSSPolarity = SPI_NSS_POLARITY_HIGH;
 
 hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
 
 hspi4.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
 
 hspi4.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
 
 hspi4.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
 
 hspi4.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
 
 hspi4.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
 
 hspi4.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
 
 hspi4.Init.IOSwap = SPI_IO_SWAP_DISABLE;
 
 if (HAL_SPI_Init(&hspi4) != HAL_OK)
 {
 Error_Handler();
 }
 
}
 
 
 
void MX_DMA_Init(void)
 
{
 /* DMA controller clock enable */
 
 __HAL_RCC_DMAMUX_CLK_ENABLE();
 
 __HAL_RCC_DMA2_CLK_ENABLE();
 
 
 
 /* DMA interrupt init */
 
 /* DMA2_Stream0_IRQn interrupt configuration */
 
 HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0);
 
 HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
 
 /* DMA2_Stream1_IRQn interrupt configuration */
 
 HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 1, 0);
 
 HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
 
}
 
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
 
{
...
 
/* SPI4 DMA Init */
 
 /* SPI4_TX Init */
 
 hdma_spi4_tx.Instance = DMA2_Stream1;
 
 hdma_spi4_tx.Init.Request = DMA_REQUEST_SPI4_TX;
 
 hdma_spi4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
 
 hdma_spi4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
 
 hdma_spi4_tx.Init.MemInc = DMA_MINC_ENABLE;
 
 hdma_spi4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
 
 hdma_spi4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
 
 hdma_spi4_tx.Init.Mode = DMA_NORMAL;
 
 hdma_spi4_tx.Init.Priority = DMA_PRIORITY_LOW;
 
 hdma_spi4_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
...
 
}
 
int main()
{
 
MX_SPI4_Init();
MX_DMA_Init();
 
VIRT_UART_Init(&huart0);
VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID, data_receive)
 
while (1)
{
...
}
 
}
 
void data_receive(VIRT_UART_HandleTypeDef *huart)
 
{
uint8_t buffer[1000] = { 0 };
 
 uint16_t recSize = huart->RxXferSize < MAX_BUFFER_SIZE ? huart->RxXferSize : MAX_BUFFER_SIZE-1;
 
memcpy(buffer, huart->pRxBuffPtr, recSize);
 
if (GL.spi[SPI_MOD]->State == HAL_SPI_STATE_READY)
{
 
HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);
 
}
 
}
 

As the data size from ipcc(data_receive) increases, hal_spi_transmit_dma stucks. But when i use hal_spi_transmit instead of hal_spi_transmit_dma stuck does not occur.

Why do you think hal_spi_transmit_dma could cause such a thing?

Best Regards,

Mesut Ince

This topic has been closed for replies.

7 replies

aliMesut
aliMesutAuthor
Associate III
December 1, 2021

Note: some time after using hal_spi_transmit_dma Spi state never turn in ready. Even when I reset the m4, the situation does not change. until i reset the a7. (i guess this problem occur spi clock. Because a7 side in chip sets peripheral clocks.)

PatrickF
Technical Moderator
December 1, 2021

Hi,

did you ensure the DMA is finished when your restart it ?

Might be better to have a clean 'flag' set by SPI call back interrupt instead of polling the SPI state.

e.g. something like:

bool volatile DMA_Finished = true;
.......
if (DMA_Finished == true)
{
DMA_Finished = false;
HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);
}
......
 
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
DMA_Finished = true;
}

For the mis-restart of M4 application, rhis is a know behavior as peripherals are not reset when M4 is restarted (and HAL could fail to init then a second time).

Could be easily overcome by using some 'manual' reset before your inits.

e.g. something like:

// ensure clear any pending peripherals settings, interrupt or dmas
 hspi4.Instance = SPI4;
 HAL_SPI_DeInit(&hspi4);
 HAL_SPI_MspDeInit(&hspi4);
 HAL_NVIC_DisableIRQ(SPI4_IRQn);
 __HAL_RCC_SPI4_FORCE_RESET();
 __HAL_RCC_SPI4_RELEASE_RESET();
 HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
 __HAL_RCC_DMA2_FORCE_RESET();
 __HAL_RCC_DMA2_RELEASE_RESET();
 
// then regular init could be done
 
MX_SPI4_Init();
MX_DMA_Init();
 
VIRT_UART_Init(&huart0);

Regards.

In order to give better visibility on the answered topics, please click on 'Best Answer' on the reply which solved your issue or answered your question.Tip of the day: Try Sidekick STM32 AI agent
aliMesut
aliMesutAuthor
Associate III
December 2, 2021

Hi @PatrickF​ ,

Thank you for your supporting.

M4 reboot problem solved.

But when I added DMA_Finished control, there was no improvement.

Best Regards

Mesut Ince

PatrickF
Technical Moderator
December 2, 2021

Hi,

I'm puzzle with this line

HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);

which should be in the form

HAL_SPI_Transmit_DMA(&hspi4, buffer, MPEGTS_PACKET_SIZE);

Maybe 'buffer' should be better declared as a global variable to avoid potential memory reallocation and corruption during the DMA background execution.

Furthermore, sound strange to have the 'memcpy' before the check than previous 'buffer' transfer is finished.

Need to debug step by step on your side, but I think one of the usual cause of hal_spi_transmit_dma() stuck is the issue of a new DMA transfer command while the previous is not finished. This is why I recommended to use the HAL_SPI_TxCpltCallback.

It is also recommended to check any HAL_*** return value with != HAL_OK to check for returned errors.

Any chances to debug using GPIOs set/clr around HAL_SPI_Transmit_DMA() and an oscilloscope to see real time SPI transfer timings ?

Regards.

In order to give better visibility on the answered topics, please click on 'Best Answer' on the reply which solved your issue or answered your question.Tip of the day: Try Sidekick STM32 AI agent
aliMesut
aliMesutAuthor
Associate III
December 2, 2021

Hi @PatrickF​ ,

I'm sorry, I mistyped while copy-pasting.  In fact, the code is

HAL_SPI_Transmit_DMA(&hspi4, buffer, MPEGTS_PACKET_SIZE);

When I measure spi_clock with an oscilloscope, It stays drawn to gnd while in the stuck state.

Best Regards

Mesut Ince

aliMesut
aliMesutAuthor
Associate III
December 2, 2021

Note: i'm checking hspi4->state in code.

if (&hspi4>State == HAL_SPI_STATE_READY)
{
HAL_SPI_Transmit_DMA(&hspi4, buffer, MPEGTS_PACKET_SIZE);
}

hspi->State is HAL_SPI_STATE_BUSY_TX while in the stuck state. Never get into if state.

aliMesut
aliMesutAuthor
Associate III
December 3, 2021

Hi @PatrickF​ ,

We are testing spi dma 3Mbit/s data rate. After a while dma lock never turn unlock and not return errorcode.

I added the main;

int main ()
{
...
while(1)
{
 ...
 if (HAL_GetTick () - lastReadySpiDma)
 {
 HAL_SPI_Abort(&hspi4);
 }
 ....
}
...
}

Above code solved spi dma stuck problem. but why spi dma stays locked at 3Mbit/s data rate. I wonder if it's missing irq.

Why stays locked?

Best Regards

Mesut Ince

aliMesut
aliMesutAuthor
Associate III
December 3, 2021

Note: The code is actually

int main ()
{
...
while(1)
{
 ...
 if (HAL_GetTick () - lastReadySpiDma > 100)
 {
 HAL_SPI_Abort(&hspi4);
 }
 ....
}
...
}

PatrickF
Technical Moderator
December 6, 2021

Hi,

maybe try to enable FIFO

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
....
 hdma_spi4_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
 hdma_spi4_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
 hdma_spi4_tx.Init.MemBurst = DMA_MBURST_SINGLE;
 hdma_spi4_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
....

Did to try adding a debug wait time in between each HAL_SPI_Transmit_DMA() ?

This might highlight that there is some real time issue (e.g. start a new DMA when previous not completely finished).

Regards.

In order to give better visibility on the answered topics, please click on 'Best Answer' on the reply which solved your issue or answered your question.Tip of the day: Try Sidekick STM32 AI agent
PatrickF
Technical Moderator
December 15, 2021

Hi @aliMesut​ ,

did you progress on a more stable solution ?

Regards.

In order to give better visibility on the answered topics, please click on 'Select as Best' on the reply which solved your issue or answered your question. See also 'Best Answers'

In order to give better visibility on the answered topics, please click on 'Best Answer' on the reply which solved your issue or answered your question.Tip of the day: Try Sidekick STM32 AI agent
aliMesut
aliMesutAuthor
Associate III
January 12, 2022

Hi @PatrickF​ ,

I put a delay of 100 microseconds between the data, the problem does not appear for now. But it was not a good solution. Problems may arise in the future

Regards.

PatrickF
Technical Moderator
January 12, 2022

Hi,

I still recommend that instead of testing directly SPI HAL state like you mention:

if (&hspi4>State == HAL_SPI_STATE_READY)

you implement cleaner way using HAL_SPI_TxCpltCallback() interrupt.

such:

 bool volatile DMA_Finished = true;
 .......
 if (DMA_Finished == true)
 {
 DMA_Finished = false;
 HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);
 }
 ......
 
 void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
 {
 DMA_Finished = true;
 }

Regards.

In order to give better visibility on the answered topics, please click on 'Best Answer' on the reply which solved your issue or answered your question.Tip of the day: Try Sidekick STM32 AI agent
aliMesut
aliMesutAuthor
Associate III
December 15, 2021

Hİ @PatrickF​ 

Thank you for your suporting. But there was no improvement.

Regards.