mokongking

H7双核调试

1、stm32H747有两个内核使用,都可以跑freertos操作系统,如果用这个芯片做电机控制,一个内核跑算法,一个内核跑通信逻辑,借助M7核的mpu配置D3区域的地址0x38000000地址开始配置成共享区域,mpu控制共享区域要注意4字节对齐,非对齐读写都有问题,受mpu保护的访问不对齐的直接进入硬件错误,

在 STM32H7 系列中,内存是分域(Domain)管理的。SRAM4 位于 D3 域(或称 SRD 域)。即使你配置了 MPU,如果没给这个内存区域供电/开时钟,CPU 访问该地址会立即触发 Bus Fault(进而导致 HardFault)

#define RCC_AHB4ENR_SRDSRAMEN_Pos   (28U)                                      
#define RCC_AHB4ENR_SRDSRAMEN_Msk   (0x1UL << RCC_AHB4ENR_SRDSRAMEN_Pos)       /*!< 0x10000000 */
#define RCC_AHB4ENR_SRDSRAMEN       RCC_AHB4ENR_SRDSRAMEN_Msk

开启这个时钟的代码这个需要手动补齐

STM32H747 的 D3 域(Smart Run Domain)是一个非常特殊的区域:

  • 地址范围0x38000000 - 0x3800FFFF (64KB)。

  • 特性:它是唯一一个在 CPU 核心处于深度睡眠时还能保持运行的内存域。

  • 总线访问:M7 和 M4 访问它都要通过 AHB4 总线。由于它不在 D1/D2 域,所以时钟必须手动开启,否则任何对该地址的读写(包括 memsetMotorObject[i].motor_param_info->...)都会导致总线错误(Bus Fault)

  • 这个遇见访问错误就是遇见硬件错误,或者写uint8_t 能写进去,uint32_t写不进去硬件错误,如果遇见写0x38000000这个地址写不进去就要看看0x38000000这个地址有没有内容,这两个可以当做一个问题去看代
  • 既然你能“看到”内容(说明时钟已经开启,地址总线通了),但“不能写”(一写就进 HardFault),这说明你碰到了 ARM MPU 最经典的“内存类型限制”陷阱

    在 STM32H7 中,当 MPU 配置为 IsCacheable = NOIsBufferable = NO 时,该内存会被识别为 强顺序内存(Strongly Ordered Memory)设备内存(Device Memory)

    1. 核心原因:非对齐访问限制

    这是导致“能读不能写”最常见的凶手:

    • 规则:ARM 架构规定,访问“设备内存”或“强顺序内存”时,指令必须是对齐的

    • 你的情况:你使用了 #pragma pack(1)。这意味着结构体里的 SetFrequency(32位)可能落在了一个类似 0x38000013 这种不能被 4 整除的地址上。

    • 结果:当你尝试往这个不对齐的地址写一个 32 位数据时,CPU 硬件会直接拦截并抛出 Alignment Fault(在 H7 中表现为 HardFault)。

      • // 尝试写一个字节,字节访问永远是对齐的 *(volatile uint8_t *)0x38000000 = 0xAA;可以使用这个代码写一下看能不能写进去
      • 方案 A:修改 MPU 属性

        将 M7 和 M4 的 MPU 配置中,SRAM4 对应的 Region 属性修改为 Bufferable。这允许 CPU 进行非对齐操作。

        C
         
        /* 修改 MPU 配置 */
        MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; // 必须设置为 ENABLE
      • 方案 B:优化结构体布局

        去掉 #pragma pack(1),改为手动对齐。这样既能保证 M7 和 M4 看到的偏移量一致,又能获得最高的访问性能,且不会触发 Fault。

        调整原则:按成员长度从大到小排列。

        C
         
        typedef struct _share_motor_param {
            /* --- 4字节对齐区 --- */
            volatile int32_t   SetMax_Move_Step; 
            volatile int32_t   SetMax_Speed;
            volatile int32_t   Target_Move_Step;
            volatile int32_t   Cur_Move_Step;
            volatile uint32_t  SetFrequency;      // 现在它一定落在 4 字节边界上
            volatile float     SetSpeed;
            
            /* --- 2字节对齐区 --- */
            volatile uint16_t  subdivision;
            
            /* --- 1字节对齐区 --- */
            volatile uint8_t   SetMotorDir;
            volatile uint8_t   MotorDirState;
            volatile uint8_t   UseEncoder;
            
            /* 补齐到 4 字节边界,方便数组计算地址 */
            uint8_t            reserved[1]; 
        } share_motor_param;
        在调试是不能初始化外设时钟啥的最好在一个内核,调试的时候要选择调试模式,现在m7或者m4内核不能Reset

posted on 2026-04-16 22:25  虎啸岳林  阅读(115)  评论(0)    收藏  举报

导航