• 正文
  • 相关推荐
申请入驻 产业图谱

STM32H5 开启 TrustZone 后 ADC DMA 报错

07/17 10:04
145
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

前言

近日在调试一个 STM32H5 + TrustZone 项目时,碰到了两个小问题:

* ADC1 + DMA 搬运数据时报错,进入 HAL_DMA_ERROR_USE* sprintf("%.2f") 无法正常输出浮点数 

本文把排查过程整理出来,供同仁参考。

项目背景

本次项目环境如下:

MCU:STM32H563

TrustZone:开启

ADC1:配置在

Non-secure域DMA:用于搬运 ADC 转换结果

开发环境:VSCode + STM32CubeIDE  for VSCode 插件

利用STM32CubeMx进行配置并创建基于HAL库的代码串口打印:通过 Secure区的 UART 输出

目标功能很简单:

    • ADC 在TIMER触发下持续采样;DMA 持续搬运数据到内存 buffer;在DMA完成中断的回调函数中计算并打印结果;

问题 一:ADC DMA 运行时报HAL_DMA_ERROR_USE

1.1 现象

在 DMA 中断中,程序进入了下面这段代码:

if (__HAL_DMA_GET_FLAG(hdma, DMA_FLAG_USE) != 0U){ if (__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_USE) != 0U) {__HAL_DMA_CLEAR_FLAG(hdma, DMA_FLAG_USE); hdma->ErrorCode |= HAL_DMA_ERROR_USE; }}

这说明 DMA 触发了HAL_DMA_ERROR_USE错误。

这个错误通常表示出现了DMA用户配置错误,比方跟DMA有关的参数、对齐问题等。结合本人对STM32H5芯片DMA的使用经验,基本参数方面应该问题不大,也不难快速验证。倒是对开启trustzone条件下各种安全属性及权限的配置不是很熟悉,所以,很怀疑这方面的问题。

1.2 第一反应:怀疑 TrustZone 安全属性

因为工程启用了 TrustZone,所以一开始优先从这些方向排查:

ADC1 是否真的配置成了Non-secure;

DMA Channel 是否也是Non-secure;

ADC 结果 buffer 是否在Non-secure RAM;

DMA request 是否正确;DMA 方向、宽度、模式是否正确;

通过STM32CubeMx的DMA 配置界面里,看到的是:

    • Channel      = Non-secureSource      = Non-secureDestination      = Non-securePrivileged      =

Non-privileged

看上去没什么问题,毕竟也是基于cubeMx的默认配置。

1.3 检查 ADC buffer 的地址

ADC buffer 的地址实际打印出来是:0x200501EC

NS 工程链接脚本中的 RAM 定义是:

MEMORY

{

RAM    (xrw) : ORIGIN = 0x20050000, LENGTH = 320K

FLASH  (rx)  : ORIGIN = 0x08100000, LENGTH = 1024K

}

所以可以确认:

adc_buffer 落在 NS 工程的 RAM 区间;从链接地址角度看,变量放置没有问题;

这一步基本可以排除ADC buffer 被链接到了 Secure RAM。

1.4 继续看 GTZC / MPCBB 配置

查看 Secure 工程中的 MX_GTZC_S_Init(),可以看到的安全属性配置如下:

MPCBB_Area_Desc.AttributeConfig.MPCBB_SecConfig_array[0] = 0x00000000;MPCBB_Area_Desc.AttributeConfig.MPCBB_SecConfig_array[19] = 0x00000000;

这说明 SRAM3 对应区域被配置成了Non-secure。

所以从安全属性上看,内存区域的配置也是没问题的。

1.5 真正的问题:Privileged 属性冲突

继续往下看,同一段 GTZC 代码里还有这一组:

MPCBB_Area_Desc.AttributeConfig.MPCBB_PrivConfig_array[0] = 0xFFFFFFFF;...MPCBB_Area_Desc.AttributeConfig.MPCBB_PrivConfig_array[19] = 0xFFFFFFFF;

这意味着SRAM3 都被配置成了 Privileged,而 DMA Channel 的配置却是Non-privileged,于是出现了如下冲突:

DMA CH0 = Non-privileged

SRAM3   = Privileged

换句话说,DMA 正在尝试用非特权访问去写一个特权内存区域,这就解释了为什么 DMA 无法正常工作。

当然,这里真正的原因不是单纯的 Secure / Non-secure 配置错误,而是:

Privileged / Non-privileged 属性不匹配。

具体来说就是:

SRAM3     被配置成了 Privileged;DMA-CH0 却配置成了 Non-privileged;

导致DMA写 adc_buffer 时访问失败,最终触发 HAL_DMA_ERROR_USE。

1.6 解决办法

把 DMA Channel 的属性从NON PRIVILEGED 改成 PRIVILEGED。

修改后,DMA工作立刻恢复正常,ADC数据可以正常搬运。

问题 二:sprintf("%.2f")浮点输出异常

2.1 现象

DMA 正常后,在 ADC 回调中做了电压换算,并尝试打印带两位小数的结果:

float voltage;sprintf(buf, "ADC Voltage: %.2fVrn", (double)voltage);SECURE_UART_Print(buf);

结果输出异常,具体就是不能正确显示浮点数据。

2.2 原因分析

应该说,这个问题和 ADC/DMA以及UART都没关系,因为现在可以看到ADC结果,其它非浮点数字符打印都是正常的。所以这应是工具链配置问题

在常用的GCC / newlib-nano 环境下, 默认不会启用 printf 的浮点支持。因此像这种格式 %.2f,如果没有额外配置,常常就会输出异常。

2.3 解决方法

在链接选项中加入:-u _printf_float

我这边使用的是 VSCode + STM32CubeIDE for VSCode 插件的开发环境,就在工程的 CMakeLists.txt 中加入了相应链接参数。

#Linker options

set(STM32_LINKER_SCRIPT STM32H563xx_FLASH_ns.ld)

set(STM32_LINKER_OPTION "-u _printf_float")

加上黄色高亮代码行后,浮点数打印输出恢复正常。

这个选项的作用是告诉链接器把 printf 相关的浮点格式化支持一起链接进来。如果使用STM32CubeIDE工具的话,在工程属性的相关配置里有专门的勾选项。参见下图示意:

三、小结

两个问题都不算复杂,但都挺“隐蔽”。第一个坑在 TrustZone 权限属性;第二个坑在 工具链 linker 配置。Ok,今天的分享就到这里,下次再聊。

 

相关推荐