扫码加入

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

STM32H5 读取温度传感器校准值 HardFault 解决方案:MPU 缓存配置实操

2小时前
89
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

STM32H5 系列开启 ICACHE 后,读取温度传感器校准值(TS_CAL1/TS_CAL2)会触发 HardFault,核心原因是 OTP/RO 区域默认被配置为 cacheable,而该区域不支持缓存。通过 MPU(内存保护单元)将 OTP/RO 区域配置为 none-cacheable,即可在保留 ICACHE 提升效率的同时,正常读取校准值及 UID、Flash 容量等信息。本文基于 ST 官方 LAT1340 应用笔记,以 NUCLEO-H563ZI 为例,详解问题根源与分步解决流程。

1. 核心背景与问题定位

1.1 关键信息

  • 温度传感器校准值地址:TS_CAL1(30℃校准值)为 0x08FFF814-0x08FFF815,TS_CAL2(130℃校准值)为 0x08FFF818-0x08FFF819;
  • 区域属性:校准值所在的 RO 区域(0x08FFF800-0x08FFFFFF)与 OTP 区域(0x08FFF000-0x08FFF7FF)均为 Read-only,通过 AHB 总线访问;
  • 触发条件:仅开启 ICACHE 时出现 HardFault,关闭 ICACHE 可临时规避,但会降低代码执行效率。

1.2 问题根源

  • STM32H5 的 AHB 内存默认属性为 cacheable,但 OTP/RO 区域(含校准值、UID、Flash 信息)不支持缓存,直接访问会导致缓存冲突;
  • 需通过 MPU 手动将该区域配置为 none-cacheable,禁止缓存机制介入,确保总线访问正常。

2. 关键前提:OTP/RO 区域地址范围

OTP 与 RO 区域地址连续,合并配置即可覆盖所有相关区域:
  • 合并地址范围:0x08FFF000 - 0x08FFFFFF(共 2KB OTP + 2KB RO,合计 4KB);
  • 包含内容:温度传感器校准值、唯一设备 ID(UID)、Flash 容量、封装信息等只读数据。

3. 解决方案:MPU 配置实操

通过 STM32CubeMX 图形化配置 + 代码补充,快速完成 MPU 设置,无需手动操作寄存器

3.1 STM32CubeMX 配置步骤

  1. 打开工程,进入 “Pinout & Configuration”→“Configuration”→“Cortex-M55 MPU”;
  2. 启用 MPU:勾选 “MPU Enable”,设置 “MPU Control Mode” 为 “Background Region Privileged accesses only”;
  3. 配置区域 0(覆盖 OTP/RO):
    • MPU Region Base Address:0x08FFF000(区域起始地址);
    • MPU Region Limit Address:0x08FFFFFF(区域结束地址);
    • MPU Access Permission:ALL READS(只读权限,匹配 RO/OTP 属性);
    • MPU Instruction Access:DISABLE(禁止指令访问,仅允许数据读取);
    • MPU Cacheable Permission:NOT CACHEABLE(核心配置,禁用缓存);
    • MPU Shareability Permission:NOT SHAREABLE;
    • MPU Attributes:DEVICE nGnRnE(设备属性,适配 AHB 总线访问);
  4. 点击 “Project Manager”→“Generate Code”,生成包含 MPU 基础配置的代码。

3.2 补充 MPU 初始化代码

生成代码后,在main.c中添加完整 MPU 配置函数(确保在系统初始化后、校准值读取前调用):
void MPU_Config(void)
{
  MPU_Region_InitTypeDef MPU_InitStruct = {0};
  MPU_Attributes_InitTypeDef MPU_AttributesInit = {0};

  /* 禁用MPU,配置前必须执行 */
  HAL_MPU_Disable();

  /* 配置OTP/RO区域(0x08FFF000-0x08FFFFFF) */
  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
  MPU_InitStruct.BaseAddress = 0x08FFF000;
  MPU_InitStruct.LimitAddress = 0x08FFFFFF;
  MPU_InitStruct.AttributesIndex = MPU_ATTRIBUTES_NUMBER0;
  MPU_InitStruct.AccessPermission = MPU_REGION_ALL_RO;  // 只读权限
  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;  // 禁止指令执行
  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
  HAL_MPU_ConfigRegion(&MPU_InitStruct);

  /* 配置内存属性:none-cacheable + 设备属性 */
  MPU_AttributesInit.Number = MPU_REGION_NUMBER0;
  MPU_AttributesInit.Attributes = INNER_OUTER(MPU_DEVICE_nGnRnE | MPU_NOT_CACHEABLE | MPU_TRANSIENT | MPU_NO_ALLOCATE);
  HAL_MPU_ConfigMemoryAttributes(&MPU_AttributesInit);

  /* 启用MPU,使用特权模式默认配置 */
  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}

3.3 调用 MPU 配置函数

main()函数中,系统初始化后、读取校准值前调用MPU_Config()
int main(void)
{
  /* 复位所有外设,初始化Flash和Systick */
  HAL_Init();

  /* 配置系统时钟 */
  SystemClock_Config();

  /* 初始化所有配置的外设 */
  MX_GPIO_Init();
  MX_USART2_UART_Init();

  /* 关键步骤:配置MPU,禁用OTP/RO区域缓存 */
  MPU_Config();

  /* 读取温度传感器校准值,此时不会触发HardFault */
  uint16_t TS_CAL1_Val = *(uint16_t *)0x08FFF814;
  uint16_t TS_CAL2_Val = *(uint16_t *)0x08FFF818;

  /* 后续业务代码... */
  while (1)
  {
    // 业务逻辑
  }
}

4. 验证与注意事项

4.1 验证方法

  • 开启 ICACHE,运行程序,观察是否触发 HardFault;
  • 打印 TS_CAL1_Val 和 TS_CAL2_Val,若数值非 0xFFFF(默认未初始化值),说明读取成功。

4.2 关键注意事项

  1. 地址范围不可错:必须覆盖完整 OTP/RO 区域(0x08FFF000-0x08FFFFFF),遗漏会导致部分数据读取异常;
  2. 权限配置:仅设置为 “只读”,避免误写 OTP 区域(OTP 为一次性可编程,写操作不可逆);
  3. 调用时机:MPU 配置必须在读取校准值、UID 等数据前执行,否则仍会触发 HardFault;
  4. 兼容性:该配置适用于所有 STM32H5 系列芯片(H563/H573 等),无需修改地址范围。
STM32H5 读取温度传感器校准值触发 HardFault 的核心是缓存冲突,通过 MPU 将 OTP/RO 区域配置为 none-cacheable 即可彻底解决。该方案既保留了 ICACHE 对代码执行效率的提升,又确保了只读区域的正常访问,同时适用于 UID、Flash 容量等其他只读数据的读取。

相关推荐