Skip to main content
Explorer
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

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

    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.

    aliMesutAuthor
    Explorer
    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

    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.

    aliMesutAuthor
    Explorer
    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

    aliMesutAuthor
    Explorer
    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.

    aliMesutAuthor
    Explorer
    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

    aliMesutAuthor
    Explorer
    December 3, 2021

    Note: The code is actually

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

    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.

    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'

    aliMesutAuthor
    Explorer
    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.

    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.

    aliMesutAuthor
    Explorer
    December 15, 2021

    Hİ @PatrickF​ 

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

    Regards.