Skip to main content
JohnsAby
Associate III
November 15, 2021
Solved

STM32F4 SPI with DMA is not working, Transmit only used. stuck at HAL_SPI_STATE_BUSY_TX

  • November 15, 2021
  • 24 replies
  • 8142 views

I have done the implementation of 3 wire SPI using DMA and when I do SPI transfer using

HAL_SPI_Transmit_DMA(&SPIx_handle, (uint8_t *)TxBuffer, 8u); the HAL_SPI_GetState(&SPIx_handle) is stuck at HAL_SPI_STATE_BUSY_TX.

Not changing the state.

My configuration of SPI and DMA is similar to this query : STM32F405 SPI Transmit using DMA not working

Thanks in advance

Edit: First time posting query here, if anything needed additionally please comment

Edit 2: Earlier mentioned HAL_SPI_STATE_BUSY, updated to HAL_SPI_STATE_BUSY_TX

This topic has been closed for replies.
Best answer by TDK

> Issue is when the NSS is high, Clock also present. 

The "NSS" signal on the STM32F4 is not a CS signal. It pulses at the end of each byte in TI mode, which is presumably what you have selected. You'll need to use a different method.

0693W00000GY2xbQAD.png 

24 replies

TDK
November 15, 2021

Ensure MX_DMA_Init is called before MX_SPI_Init.

If that's not it, show how you're using it or post the SPI and DMA register values.

"If you feel a post has answered your question, please click ""Accept as Solution""."
JohnsAby
JohnsAbyAuthor
Associate III
November 15, 2021

Hi TDX,

Thanks for the response.

MX_DMA_Init is done before MX_SPI_Init

DMA2 Stream 4 and SPI5 is used.

0693W00000GXbLuQAL.png0693W00000GXbLVQA1.png 

please find the above images attached.

TDK
November 15, 2021

The DMA stream isn't enabled. Might be some flags set in DMA2_HISR.

Since NDTR=0, it could be that the transfer is complete, but you don't have the DMA transfer complete interrupt implemented or handled correctly, or interrupts are disabled.

"If you feel a post has answered your question, please click ""Accept as Solution""."
JohnsAby
JohnsAbyAuthor
Associate III
November 16, 2021

0693W00000GXj7qQAD.pngHi TDK,

Thanks for the response.

DMA stream is Enabled and TC and HF bits in HISR are getting set after Transfer.

NDTR is getting populated during transfer.

Still then

_inline_ static void spi5_dataTransfer(uint16_t *TxBuffer)
{
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_RESET);
 HAL_SPI_Transmit_DMA(&SPIx_handle, (uint8_t *)TxBuffer, 8u);
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_SET);
 while (HAL_SPI_GetState(&SPIx_handle) != HAL_SPI_STATE_READY);
}

the control is not stopping at while(mentioned above).

And SPI state remains in "HAL_SPI_STATE_BUSY_TX" state.

Please help me to understand, what made you think "but you don't have the DMA transfer complete interrupt implemented or handled correctly, or interrupts are disabled".

Kindly reply, its helping me to understand more.

waclawek.jan
Super User
November 16, 2021

You appear to try to use SPI with CRC, is it intentional?

Do you use C++?

JW

JohnsAby
JohnsAbyAuthor
Associate III
November 16, 2021

Hi JW,

Thanks for the response

I use C language.

My SPI is configured without CRC (SPI_CRCCALCULATION_DISABLE)

waclawek.jan
Super User
November 16, 2021

Sorry I misread the bits in SPI_CR1, indeed, you don't have CRCEN set (rather, BIDIMODE and BIDIOE).

JW

TDK
November 16, 2021

Since TCIE is set and TCIF is set, and the cpu isn't jumping into the handler, the corresponding NVIC enable bit isn't set, interrupts are disabled, or a higher priority interrupt is being ran.

"If you feel a post has answered your question, please click ""Accept as Solution""."
JohnsAby
JohnsAbyAuthor
Associate III
November 16, 2021

Hi TDK,

Thanks for the response

The NVIC is enabled, I will check by modifying interrupt priority.

JohnsAby
JohnsAbyAuthor
Associate III
November 17, 2021

Hi TDK,

I checked with high priority, still the behavior is same

_inline_ static void spi5_dataTransfer(uint16_t *TxBuffer)
{
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_RESET);
 HAL_SPI_Transmit_DMA(&SPIx_handle, (uint8_t *)TxBuffer, 8u);
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_SET);
 while (HAL_SPI_GetState(&SPIx_handle) != HAL_SPI_STATE_READY);
}

the control is not stopping at while(mentioned above).

And SPI state remains in "HAL_SPI_STATE_BUSY_TX" state.

But if I disable the "while" as shown below

_inline_ static void spi5_dataTransfer(uint16_t *TxBuffer)
{
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_RESET);
 HAL_SPI_Transmit_DMA(&SPIx_handle, (uint8_t *)TxBuffer, 8u);
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_SET);
 // while (HAL_SPI_GetState(&SPIx_handle) != HAL_SPI_STATE_READY);
}

the ISR (DMA2_Stream4) is getting called at fixed interval(as I call spi5_dataTransfer() in a repeated task), so interrupt is enabled and working right?

Please correct me if am wrong.

NVIC set priority and enabled are done for both DMA stream and SPI

Kindly reply, as your replies are helping

waclawek.jan
Super User
November 17, 2021

> in a repeated task

RTOS?

Where do you call spi5_dataTransfer from? Aren't interrupts disabled globally at that point, or isn't it from an interrupt context with priority equal or higher than DMA2_Stream4 interrupt priority?

JW

JohnsAby
JohnsAbyAuthor
Associate III
November 17, 2021

Hi JW,

Thanks for the response

Not RTOS, a repeated task is created using a timer interrupt.

spi5_dataTransfer is called from this task.(No global interrupts are disabled)

I will look for issue from interrupt context and will update here.

TDK
November 17, 2021

> a repeated task is created using a timer interrupt.

> spi5_dataTransfer is called from this task

If spi5_dataTransfer is called from an interrupt, probably the DMA2_Stream4 IRQ has the same or lower priority than it. If you don't know what it's in, set a breakpoint and look at VECTACTIVE bits to determine which interrupt it's in.

> HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_RESET);

> HAL_SPI_Transmit_DMA(&SPIx_handle, (uint8_t *)TxBuffer, 8u);

> HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_SET);

If your intention is to hold NSS low until the transmission completes, you need to wait for it to complete. As written, the code will only set NSS low briefly, perhaps for a single bit or less, as the transmission will continue in the background. You can instead set NSS high in the receive complete callback function.

"If you feel a post has answered your question, please click ""Accept as Solution""."
JohnsAby
JohnsAbyAuthor
Associate III
November 18, 2021

Hi TDK,

Thanks for the response.

You were correct about the interrupt,

For testing purpose, I changed to flow and called HAL_SPI_Transmit_DMA from main().

It worked fine for single byte transfer.

0693W00000GY18XQAT.png 

But when I pass multiple bytes( like 8, 25 etc) for last byte in the sequence is getting identified

 Please see below, Here data send are "12345678", but only 8 is identified(Data from 1-7 also present in transfer but during the ChipSelect high clock is present)

another example if "ABCDEFGH" is send means H will be identified.

0693W00000GY18mQAD.png 

Note: HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_SET); is called inside HAL_SPI_TxCpltCallback() and is fine.

waclawek.jan
Super User
November 18, 2021

> But when I pass multiple bytes

How?

Post relevant portion of code.

JW

JohnsAby
JohnsAbyAuthor
Associate III
November 18, 2021

Hi JW

Thanks for the quick response

I pass

uint8_t aTxBuffer[] = "ABCDEFGH";

to this

void spi5_dataTransfer(uint8_t *TxBuffer)
{
 HAL_GPIO_WritePin(SPIx_NSS_Port, SPIx_NSS_Pin, GPIO_PIN_RESET);
 HAL_SPI_Transmit_DMA(&SPIx_handle, TxBuffer, 8u); //8u //1u
 while (HAL_SPI_GetState(&SPIx_handle) != HAL_SPI_STATE_READY);
}

waclawek.jan
Super User
November 18, 2021

> //8u //1u

Was the lower waveform (with red circles) taken with 8u or 1u?

And channel 3 displays the SPIx_NSS_Pin?

JW

TDK
TDKBest answer
November 18, 2021

> Issue is when the NSS is high, Clock also present. 

The "NSS" signal on the STM32F4 is not a CS signal. It pulses at the end of each byte in TI mode, which is presumably what you have selected. You'll need to use a different method.

0693W00000GY2xbQAD.png 

"If you feel a post has answered your question, please click ""Accept as Solution""."
waclawek.jan
Super User
November 18, 2021

> TI mode, which is presumably what you have selected

Nice catch, TDK!

Indeed, CR2 is 0x32 i.e. FRF is set.

In that case, also CR1.SSM is moot.

But this also implies that given pin is set as AF, rather than Out, in GPIO - is this the case?

JW

JohnsAby
JohnsAbyAuthor
Associate III
November 18, 2021

Hi JW,

Thanks for the response

Closing this issues "STM32F4 SPI with DMA is not working, Transmit only used. stuck at HAL_SPI_STATE_BUSY_TX", since SPI with DMA in transmit mode is working fine. But second part is due to internal project issue, I will figure it out later.

I appreciate the time and effort you put, Thanks

Dude
Associate III
November 25, 2022

Check for peripheral conflicts, is anything competing for that DMA channel?