cancel
Showing results for 
Search instead for 
Did you mean: 

Stm32mp157c Spi Dma Transfer Stuck Problem

aliMesut
Associate III

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

13 REPLIES 13
aliMesut
Associate III

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.)

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 'Accept as Solution' on the reply which solved your issue or answered your question.
aliMesut
Associate III

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

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 'Accept as Solution' on the reply which solved your issue or answered your question.

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
Associate III

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
Associate III

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
Associate III

Note: The code is actually

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

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 'Accept as Solution' on the reply which solved your issue or answered your question.