STM32H7 DMA与ld文件
最近把项目构建工具链由STM32CubeIDE
换成了CMake
,在测试过程中发现原先的LCD代码无法使用,经过排查后发现是SPI3
的DMA
传输出了问题,下面是问题的解决过程。
我将CubeMX
生成的两种工具链的代码进行了比对,发现CubeMX
和CMake
项目下的ld链接文件有所不同
在CubeIDE
项目下,STM32H723
的内存分配如下:
1 | /* Highest address of the user mode stack */ |
CMake
项目的ld中这一部分的代码如下:
1 | /* Highest address of the user mode stack */ |
两者对比发现在_estack
栈顶的地址上有区别,CubeIDE
将栈区定义在了RAM_D1
上(对应CMake
项目文件的RAM
块),而CMake
项目中把栈区定义在了DTCMRAM
这块内存上。
还有一个区别就是CMake
项目的RAM
内存块比CubeIDE
项目中的RAM_D1
块少了192Kb,少的这部分RAM在数据手册中定义为RAM shared between ITCM and AXI
意思是这块内存是RAM_D1
和ITCMRAM
共享的,全部分配给RAM_D1
或不分配在项目较小时没啥影响。
比对ld文件的其他部分,两个项目的区别还有.data
、.bss
和._user_heap_stack
段在CMake
项目中存储在了DTCMRAM
块,在CubeIDE
项目中存储在了RAM_D1
块,关于存储在不同内存块中有没有其他功能受影响还有待考证
翻阅数据手册的总线矩阵发现DTCMRAM
不能与DMA
通信,如图所示:
使用DMA的SPI通信说需要的函数为HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, const uint8_t *pData, uint16_t Size)
,需要传入pData
指针,这个指针指向了需要传输数据的内存,然而经常我们需要传输的数据是局部变量,局部变量存储在栈区,栈顶的地址在之前ld文件里_estack
定义了,这就造成了DMA有可能访问不到我们需要的地址。
综上,由于DMA访问不到DTCMRAM
这块内存,而恰巧CubeMX生成的CMake项目把栈区定义在了这里,造成了DMA的传输失败
我认为这是ST官方的模板没有统一内存的分配导致的,我使用的CubeMX版本是6.12.0
,在最新的6.12.1
版本中Cmake项目的ld文件把上述的差异部分留空让自己填写( 这个已确认是bug ),后续这个ld文件可能还会继续更新。