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文件可能还会继续更新。