Skip to main content
Visitor II
November 11, 2025
Question

Non blocking SPI DMA transceive never completes in RTOS application

  • November 11, 2025
  • 3 replies
  • 271 views

Description:

My RTOS application on NUCLEO-H563ZI board runs a thread CollectSamplesThread. I generate an interrupt every 8Khz using a timer and the ISR triggers a non blocking SPI transfer:

The application code:

 
void InitAdeSpi()
{
 // SPI1 Initialisation
 if (hSPI.hdmarx != NULL)
 {
 HAL_DMA_RegisterCallback(hSPI.hdmarx, HAL_DMA_XFER_CPLT_CB_ID, AdcSpiRxCallback);
 }
}

void AdcSpiRxCallback()
{
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 // Release the sempahore thats blocked to validate the frames in CollectSamplesThread
 xSemaphoreGiveFromISR(xSpiRxSemph, &xHigherPriorityTaskWoken);
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
 
 
void TIM3_IRQHandler(void)
{
 EvbDataRdyTimerHandler();
}
 
void EvbDataRdyTimerHandler(void) // Ensure this matches the existing declaration
{
 __HAL_TIM_CLEAR_FLAG(&hTimDready, TIM_FLAG_UPDATE);
 // Release the sempahore that is blocked in the CollectSamplesThread for Dready callback
 xSemaphoreGiveFromISR(xSamplesAvailSemph, &xHigherPriorityTaskWoken);
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
} 
 
 
void CollectSamplesThread(void *pArg)
{
 HAL_StatusTypeDef halStatus;
 int32_t status = 0;
 if (pArg == NULL)
 {
 while (1)
 {
 if (xSemaphoreTake(xSamplesAvailSemph, portMAX_DELAY) == pdTRUE)
 {
 halStatus = HAL_SPI_TransmitReceive_DMA(hSPI, pTxData, pRxData, (uint16_t)numBytes);
 if (halStatus != HAL_OK)
 {
 status = -1;
 }
 if (status == 0)
 {
 if (xSemaphoreTake(xSpiRxSemph, portMAX_DELAY) == pdTRUE)
 {
 //Validate samples
 }
 }
 }
 }
}
 
I enabled SPI1 IRQ and also DMA Tx & Rx channel IRQs.

Issue:

Tx DMA ISR is hit, Rx DMA ISR is not hit. SPI1 ISR, SPI1_IRQHandler, is also not hit.

Additional info:

System clock is configured to 250 Mhz.

Before calling HAL_SPI_TransmitReceive_DMA, 

  • SPI1->SR = 0x00011002 (TXP=1, TXC=1, no EOT)
  • SPI1->IER = 0x0 (interrupts disabled)

At if (halStatus != HAL_OK),

  • SPI1->SR = 0x00010012 (TXP=1, EOT=1, TXC=1) ✓ EOT flag is set
  • SPI1->IER = 0x00000360 (EOTIE=1, bits 5,6,8,9 enabled) ✓ EOT interrupt is enabled

 

 

    This topic has been closed for replies.

    3 replies

    Graduate
    November 11, 2025

    While I have no idea on what's wrong with SPI DMA, I can see some other problems with your code.

    To minimize jitter you should move all ADC-related actions to timer ISR; you should do fixed-frequency sampling anyway.

    With the default SysTick freq of 1 kHz anything requiring higher frequency and implemented in a RTOS thread will only have chance to work if the thread is the only one with the highest priority.

    My likely solution would be: control ADC operation in timer ISR, put ADC data to buffer of system queue in RX DMA ISR, process the data from this queue in a thread. No semaphores needed.

    Super User
    November 11, 2025

    Have not used H5, but in general hSPI.hdmarx is used internally by HAL.

    You could implement 

    void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)

    or void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) ?

    at the global level, overriding the default "do nothing" handlers.

    hth

    KnarfB 

    Technical Moderator
    November 11, 2025

    Hello @WCarey 

    It is better to first get your SPI communication working without an RTOS. Once it is functioning correctly, you can then integrate the operating system.

    Please check the example below as reference to implement your SPI transfer:

    STM32CubeH5/Projects/NUCLEO-H503RB/Examples/SPI/SPI_FullDuplex_ComDMA_Master at main · STMicroelectronics/STM32CubeH5