cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 SPI RX DMA not working - bug in HAL?

Jack3
Senior II

This project uses STM32Cube_FW_H7_V1.3.2.

On STM32H7 I'm using DMA for SPI transfer. I use SPI1 and SPI4, both in D2 domain, together with RAM_D2.

In the linker file I added:

.dma_buffer :
  {
   . = ALIGN(4);
    
   *(.dma_buffer)
    
  } >RAM_D2

The buffer is declared like:

uint8_t buf[2048] __attribute__ ((section(".dma_buffer"))) __attribute__ ((aligned (32)));

Transmitting using DMA works:

/* Mem-to-Peri */
SCB_CleanDCache_by_Addr((uint32_t*)(((uint32_t)buf) & ~(uint32_t)0x1F), len + 32);
errorcode = HAL_SPI_Transmit_DMA(interface->hspi, (uint8_t*) buf, len);

Receiving data from SPI without using DMA also works, I get valid data in.

But if I use DMA, the buffer gets filled with 0's after cache invalidation:

/* Peri-to-Mem */
errorcode = HAL_SPI_Receive_DMA(interface->hspi, (uint8_t*) buf, len);
 
/* Some code to wait for the transfer to be finished */
wait_dma_rx_ended(interface);
 
SCB_InvalidateDCache_by_Addr((uint32_t*)(((uint32_t)buf) & ~(uint32_t)0x1F), ((len+31)/32)*32);

I also configured the MPU, but I think it is not needed when using the cache maintenance functions.

void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = { 0 };
 
  /* Disable the MPU */
  HAL_MPU_Disable();
 
  /* Initialize and configure the Region and the memory to be protected */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x30001000;
  MPU_InitStruct.Size = MPU_REGION_SIZE_8KB;
  MPU_InitStruct.SubRegionDisable = 0x0;
  MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
  MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
  MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
  MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
  MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
 
  HAL_MPU_ConfigRegion(&MPU_InitStruct);
 
  /* Enable the MPU */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

My SPI and DMA in initialized like this:

So the problem is I do not receive valid data when using DMA, but I do get valid data when not using DMA. So I think the SPI is configured correctly for the device.

Using DMA, if I don't invalidate the cache, I see the same data in the buffer as before calling HAL_SPI_Receive_DMA, which is expected. But after cache invalidation (calling SCB_InvalidateDCache_by_Addr), I do read all 0's, instead of valid data, which is not expected.

Using DMA transmit SPI works just fine, as does SPI receive without DMA.

What can I do to troubleshoot the problem further?

Has anybody seen this behavior on STM32H7 MCU's?

Once the problem is solved, I can explain which change worked, and provide the updated code on github to help others:

https://github.com/bkht/KSZ8851SNL_no_LwIP

Thank in advance for help!

6 REPLIES 6

It is not clear to us from the given information why you use 0x30001000 to setup the MPU region.

Apparently a small 8KB window. Thought you needed equivalent granularity/alignment. Not sure a 4KB alignment on an 8KB window is super productive.

The test would probably be better is applied more broadly, and the transfer address was actually displayed/validated as falling within the window.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you. I tried 0x30000000 too, I use cache maintenance functions, so the MPU configuration would likely not be required at the moment. But both locations are in RAM_D2, so I didn't see a problem with that. What problem do you see in it? It is not clear enough to me, to understand it.

Using HAL_SPI_Receive, it receives correct data, I do not have the D Cache problems then, because the MCU handles the traffic, instead of the DMA.

Using HAL_SPI_Receive_DMA gives no error, it generates the expected a SPI RX DMA interrupt, but followed by SCB_InvalidateDCache_by_Addr it received all 0x00's. (buffer located at RAM_D2 0x30000000).

This project uses STM32Cube_FW_H7_V1.3.2.

There is also erata for SPI, maybe this affects me too:

2.12.1 Spurious DMA Rx transaction after simplex Tx traffic

So I can try the workaround, resetting the SPI peripheral.

Thanks, I noticed it. I changed it back to 0x30000000, but it seems not the solution, both regions are located in RAM_D2, or am I missing something?

Hi Jack,

Did you find any solution for this problem?

We are facing same problem with SPI+DMA on stm32h7.

calling HAL_SPI_Receive_DMA gives all 0's after calling HAL_SPI_Transmit_DMA.

Thanks in Advance.

Asantos
Senior

Hi,

I also have the same problem. Some solution? ST guys, a little help please?

Please ST, put the F7 SPI in newer H7s. H7 SPI is ridiculous. It is complex, slow and doesn't works with DMA.