Skip to main content
Associate
July 20, 2026
Question

STM32H562 HAL_SPI_Transmit_DMA erroneously reporting transmit is still busy

  • July 20, 2026
  • 2 replies
  • 27 views

I am using SPI6 on an STM32H562 to write data to a WS2812 LED strip. 

The following code is called once per second to  write the data:

    LOGIF ("bytes left=%d", GPDMA1_Channel2->CBR1);
LOGIF ("TXC %d", (WS2812_SPI.Instance->SR & SPI_SR_TXC) != 0);
LOGIF ("ready=%d", HAL_SPI_GetState(&WS2812_SPI)== HAL_SPI_STATE_READY);
if (HAL_SPI_GetState(&WS2812_SPI) != HAL_SPI_STATE_READY) {
LOGIF ("error=%d", HAL_SPI_GetError(&WS2812_SPI));
HAL_SPI_Abort (&WS2812_SPI);
}

HAL_SPI_Transmit_DMA (&WS2812_SPI, spi_bytes, RESET_BYTES + nvalues * BYTES_PER_FRAME);

 

Here is the log output for the first two calls:

[101] ws2812 75: bytes left=0
[101] ws2812 76: TXC 1
[101] ws2812 77: ready=1

[201] ws2812 75: bytes left=0
[201] ws2812 76: TXC 1
[201] ws2812 77: ready=0
[201] ws2812 79: error=0

The first time, GetState reports READY, but the second time it does not, even though bytes_left is zero and TXC is 1, so an Abort is required before the next transmit. Unfortunately, this produces a nasty glitch on the MOSI line and, as the WS2812 protocol does not use the clock line, the glitch upsets the WS2812 LED strip.

 

This is the SPI setup:

 hspi6.Instance = SPI6;
hspi6.Init.Mode = SPI_MODE_MASTER;
hspi6.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
hspi6.Init.DataSize = SPI_DATASIZE_8BIT;
hspi6.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi6.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi6.Init.NSS = SPI_NSS_SOFT;
hspi6.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
hspi6.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi6.Init.TIMode = SPI_TIMODE_DISABLE;
hspi6.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi6.Init.CRCPolynomial = 0x7;
hspi6.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
hspi6.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
hspi6.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi6.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi6.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi6.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi6.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi6.Init.IOSwap = SPI_IO_SWAP_DISABLE;
hspi6.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
hspi6.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;

This is the DMA setup:

    handle_GPDMA1_Channel2.Instance = GPDMA1_Channel2;
handle_GPDMA1_Channel2.Init.Request = GPDMA1_REQUEST_SPI6_TX;
handle_GPDMA1_Channel2.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST;
handle_GPDMA1_Channel2.Init.Direction = DMA_MEMORY_TO_PERIPH;
handle_GPDMA1_Channel2.Init.SrcInc = DMA_SINC_INCREMENTED;
handle_GPDMA1_Channel2.Init.DestInc = DMA_DINC_FIXED;
handle_GPDMA1_Channel2.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE;
handle_GPDMA1_Channel2.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE;
handle_GPDMA1_Channel2.Init.Priority = DMA_LOW_PRIORITY_LOW_WEIGHT;
handle_GPDMA1_Channel2.Init.SrcBurstLength = 1;
handle_GPDMA1_Channel2.Init.DestBurstLength = 1;
handle_GPDMA1_Channel2.Init.TransferAllocatedPort = DMA_SRC_ALLOCATED_PORT0|DMA_DEST_ALLOCATED_PORT0;
handle_GPDMA1_Channel2.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER;
handle_GPDMA1_Channel2.Init.Mode = DMA_NORMAL;

The DMA interrupt is enabled but enabling the SPI interrupt causes a lockup of some kind.

Is there some way to convince the SPI driver that the previous transmit completed successfully, without causing a glitch on the MOSI line? 

2 replies

ST Technical Moderator
July 20, 2026

Hello ​@javalatte 

Please make sure the DMA interrupts have higher priority than the SPI interrupts.

 

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. Saket_Om
javalatteAuthor
Associate
July 20, 2026

HI ​@Saket_Om,

Thank you for your reply.

I enabled the SPI6 interrupt and set the interrupt priorities like this:

  /* GPDMA1 interrupt Init */
HAL_NVIC_SetPriority(GPDMA1_Channel2_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(GPDMA1_Channel2_IRQn);


/* SPI6 interrupt Init */
HAL_NVIC_SetPriority(SPI6_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(SPI6_IRQn);

The system stops functioning during or soon after the first HAL_SPI_Transmit_DMA: if I pause it using the debugger, I get this stack trace:

Note that, in an answer to this this question, you suggested setting DMA priority to 2 and SPI priority to 1. I tried that as well, and the system still locks up.

ST Technical Moderator
July 20, 2026

Hello ​@javalatte 

Could you please share the content of SPI SR register ?

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. Saket_Om
TDK
July 20, 2026

The WWDG IRQ is often listed for the default handler which could mean the program is jumping to an IRQ that isn’t in the code. Look at VECTACTIVE bits in SCB to determine the IRQ it’s in and why it’s not implemented. Could be a typo in IRQ name, could be that it’s not generated at all.

In any case, stack trace points to other issues besides priority.

"If you feel a post has answered your question, please click ""Accept as Solution""."