HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post here first, or if you can't find a relevant section!
thisdp
Posts: 9
Joined: Wed Mar 17, 2021 12:07 pm
Answers: 1

HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by thisdp »

Same code works directly using CubeIDE.

Chip: STM32H750XBH6

DMA Config
Mode: Circular
Data Width: Byte/Byte
No Sync/Event used

SPI Config:
Mode: Slave with hardware SS Input
Frame Format: Motorola
Data Size: 8Bits
Other configs are default.

Here I encountered a strange problem.

Code: Select all

//This is the definition of the DMA Buffers
uint8_t pTX[8];
uint8_t pRX[8];

Code: Select all

//in "setup" function, I use this function to start SPI with DMA
HAL_SPI_TransmitReceive_DMA(&hspi2, (uint8_t *)pTX, (uint8_t *)pRX, 8);
pRX[0]~pRX[7] keeps empty and can be modified (DMA doesn't transfer data).

After I change the definition of pTX and pRX to the following code, data appears in pRX[0] ~ pRX[7] (DMA transfers data) and the data is exactly what I send.

Code: Select all

uint8_t pTX[16];
uint8_t pRX[16];
I try to figure out if it is the problem of memory alignment, but finally I confirmed it's not memory alignment related.
Because I try to force the variable at the same memory address in CubeIDE as the address in Arduino, everything works fine.

I've tested that when X is between 8 to 12, DMA won't transfer. And when X is equal to or larger than 13, data present in pRX.

Code: Select all

uint8_t pTX[X];
uint8_t pRX[X];
During the process of reproducing this.
Sometimes it can work after I exchange the definition of pTX and pRX.

Code: Select all

uint8_t pRX[8];	//was pTX
uint8_t pTX[8];	//was pRX
And somethings data in pRX only has the front 4 bytes.

Well, my brain keeps exploding for several days :x
I'd appreciate it very much if someone could save me from this hell. :)
by thisdp » Tue Feb 11, 2025 5:16 am
OK I found the main cause. Because Arduino turns on D Cache by default
Go to full post
fpiSTM
Posts: 1944
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 108
Location: Le Mans
Contact:

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by fpiSTM »

Hard to answer without the full code.

As the SPI DMA is not (yet) supported by the core it probably comes from your code.
thisdp
Posts: 9
Joined: Wed Mar 17, 2021 12:07 pm
Answers: 1

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by thisdp »

fpiSTM wrote: Thu Feb 06, 2025 2:30 pm Hard to answer without the full code.

As the SPI DMA is not (yet) supported by the core it probably comes from your code.
SPI Code is genreated by CubeMX

Code: Select all

//STM32H750XBH6
#define USE_ARDUINO
#include "hal_conf_custom.h"
#include "STM32H750XBH6/Core/Src/main.c"
#include "STM32H750XBH6/Core/Src/stm32h7xx_hal_msp.c"
#include "STM32H750XBH6/Core/Src/stm32h7xx_it.c"

uint8_t pTX[8];
uint8_t pRX[8];

void setup(){
  HAL_MAIN();
  HAL_SPI_TransmitReceive_DMA(&hspi2, (uint8_t *)pTX, (uint8_t *)pRX, 8);
}

void loop(){}
in main.c, I change the name of main to HAL_MAIN, it has void return value, since there's no return in the function.

Code: Select all

#ifdef USE_ARDUINO
void HAL_MAIN(void){
#else
int main(void)
{
#endif
fpiSTM
Posts: 1944
Joined: Wed Dec 11, 2019 7:11 pm
Answers: 108
Location: Le Mans
Contact:

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by fpiSTM »

I don't think that simply adding the cube file is a good idea because some stuff are duplicated like weak function already overridden and don't which one the linker use.
You can see this topics on how to convert a Cube example in Arduino.
viewtopic.php?t=110
thisdp
Posts: 9
Joined: Wed Mar 17, 2021 12:07 pm
Answers: 1

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by thisdp »

fpiSTM wrote: Fri Feb 07, 2025 9:45 am I don't think that simply adding the cube file is a good idea because some stuff are duplicated like weak function already overridden and don't which one the linker use.
You can see this topics on how to convert a Cube example in Arduino.
viewtopic.php?t=110
I know that. But in my case, I only have SPI enabled.
The #include "stm32h7xx_hal_msp.c" is actually optional.

In "main.c", there are only "SystemClock_Config", "MX_SPI2_Init", "MX_DMA_Init", "MX_GPIO_Init" and "MPU_Config", which are what I need.
By the way, function name of "Error_Handler" is changed to deal with conflict of Arduino Core.

In "stm32h7xx_hal_msp.c", there are only "HAL_MspInit", "HAL_SPI_MspInit" and "HAL_SPI_MspDeInit", which are also what I need.

DMA IRQs are disabled.
ag123
Posts: 1898
Joined: Thu Dec 19, 2019 5:30 am
Answers: 30

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by ag123 »

thisdp wrote: Fri Feb 07, 2025 12:40 pm DMA IRQs are disabled.
I think DMA IRQs are actually needed, some samples from HAL codes, this is for F4
https://github.com/stm32duino/Arduino_C ... pi.c#L1926

well I'm not sure, but in some of my codes, I've enabled them.
https://github.com/ag88/stm32duino_spi_ ... X.cpp#L148
either way do note that I've not tested my codes yet
viewtopic.php?p=15283#p15283

I think HAL uses them to update some status variables and closing ops such as to clear overflows, read / flush buffers etc.
https://github.com/stm32duino/Arduino_C ... pi.c#L2825
thisdp
Posts: 9
Joined: Wed Mar 17, 2021 12:07 pm
Answers: 1

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by thisdp »

ag123 wrote: Fri Feb 07, 2025 2:29 pm
thisdp wrote: Fri Feb 07, 2025 12:40 pm DMA IRQs are disabled.
I think DMA IRQs are actually needed, some samples from HAL codes, this is for F4
https://github.com/stm32duino/Arduino_C ... pi.c#L1926

well I'm not sure, but in some of my codes, I've enabled them.
https://github.com/ag88/stm32duino_spi_ ... X.cpp#L148
either way do note that I've not tested my codes yet
viewtopic.php?p=15283#p15283

I think HAL uses them to update some status variables and closing ops such as to clear overflows, read / flush buffers etc.
https://github.com/stm32duino/Arduino_C ... pi.c#L2825
Same code in CubeIDE works correctly (H750 and F407).
F407 in Arduino works correctly with IRQ disabled.
H750XBH6 in Arduino can not work.

As you said, IRQ updates some status, does some buffer related things and handles errors.
In my case, DMA just doesn't write data into buffer or it writes only half data all the time in some conditions.
In theory, the first transfer shouldn't be affected by IRQ.

What is the most weird is that.. I can make it work by just change the size of buffer array?? Or exchange the variable order??
ag123
Posts: 1898
Joined: Thu Dec 19, 2019 5:30 am
Answers: 30

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by ag123 »

well, I'm yet to test my DMA codes
viewtopic.php?p=15283#p15283

so I do not really know if it works.
But that while I worked the codes, I noted that there can be conditions of overrun if data not read etc. e.g. that RXNE (receive buffer not empty) is set.
If those flags are not cleared and the next attempt / transaction to do SPI transfers starts, the next transfer may instead be reading data from the *last* transfer.

DMA uses the flags complete and half complete to indicate completion of transfers, if you do not use interrupts, you would need to check the flags (manually) in codes and respond when they are set. A trouble is, this would normally be ok, but you may not be able to use HAL_SPI_TransmitReceive_DMA if that use the interrupts. e.g. you may to write your own version of HAL_SPI_TransmitReceive_DMA to handle the half complete and complete events.

There are also some things that I'm not sure about such as HAL_SPI_TransmitReceive_DMA is likely async, i.e. it returns immediately instead of waiting for the transfer to complete. transfer is done completely independently off program codes and there is no interaction with your program codes.
If that being the case, when you read the receive buffer, e.g. after you called HAL_SPI_TransmitReceive_DMA, the transfer may actually not be complete. e.g. You would need to do additional checks e.g. to check the transfer counts etc.

stm32H7 has a complex / elaborate SPI peripheral with FIFO etc, along with a pretty complex DMA peripheral, you would need to review all that codes to see if you are missing anything handling SPI, the FIFO, and DMA etc. FIFO makes the prospects of checking those events SPI receive, DMA complete, half complete etc significantly more complicated. Normally, with DMA, you need to fill the buffer / count completely before the complete event is flagged.
And FIFO adds to the complexity as that also have some requirements e.g. in that if the FIFO is half filled, some data may remain in the FIFO.
For master, as you determine the clocks it is easier, but for slaves, the clock is determined by the master, and you are dealing with those added complexity.
thisdp
Posts: 9
Joined: Wed Mar 17, 2021 12:07 pm
Answers: 1

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by thisdp »

ag123 wrote: Sat Feb 08, 2025 3:52 am well, I'm yet to test my DMA codes
viewtopic.php?p=15283#p15283

so I do not really know if it works.
But that while I worked the codes, I noted that there can be conditions of overrun if data not read etc. e.g. that RXNE (receive buffer not empty) is set.
If those flags are not cleared and the next attempt / transaction to do SPI transfers starts, the next transfer may instead be reading data from the *last* transfer.

DMA uses the flags complete and half complete to indicate completion of transfers, if you do not use interrupts, you would need to check the flags (manually) in codes and respond when they are set. A trouble is, this would normally be ok, but you may not be able to use HAL_SPI_TransmitReceive_DMA if that use the interrupts. e.g. you may to write your own version of HAL_SPI_TransmitReceive_DMA to handle the half complete and complete events.

There are also some things that I'm not sure about such as HAL_SPI_TransmitReceive_DMA is likely async, i.e. it returns immediately instead of waiting for the transfer to complete. transfer is done completely independently off program codes and there is no interaction with your program codes.
If that being the case, when you read the receive buffer, e.g. after you called HAL_SPI_TransmitReceive_DMA, the transfer may actually not be complete. e.g. You would need to do additional checks e.g. to check the transfer counts etc.

stm32H7 has a complex / elaborate SPI peripheral with FIFO etc, along with a pretty complex DMA peripheral, you would need to review all that codes to see if you are missing anything handling SPI, the FIFO, and DMA etc. FIFO makes the prospects of checking those events SPI receive, DMA complete, half complete etc significantly more complicated. Normally, with DMA, you need to fill the buffer / count completely before the complete event is flagged.
And FIFO adds to the complexity as that also have some requirements e.g. in that if the FIFO is half filled, some data may remain in the FIFO.
For master, as you determine the clocks it is easier, but for slaves, the clock is determined by the master, and you are dealing with those added complexity.
I am using GDB to check if there are data in receive buffer. So my problem is the receive buffer keeps empty or half of 8bytes that I am transfering. The empty area is even not modified by DMA.
thisdp
Posts: 9
Joined: Wed Mar 17, 2021 12:07 pm
Answers: 1

Re: HAL_SPI_TransmitReceive_DMA doesn't transfer properly under Arduino Core (STM32H750XBH6)

Post by thisdp »

By the way, I can not enable DMA IRQ. Because program will get into WWDG_Handler.
Post Reply

Return to “General discussion”