十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32H747双核MCU实战:启动引导、共享内存与外设分配

STM32H747双核MCU实战:启动引导、共享内存与外设分配 主控芯片既要跑复杂的图形界面或网络协议栈又要维持电机电流环、编码器等强实时任务时往往会出现中断延迟抖动、主循环被高优先级任务挤占、片上资源分配困难等问题。STM32H747 这类双核异构 MCU正是解决这类矛盾的硬件基础但上手后会发现它的难点不在“频率高”而在于两个内核如何启动、如何共用内存、如何同步外设权限。这篇文章将围绕 STM32H747 在实际嵌入式项目中容易踩坑的技术点展开结合启动引导、通信机制、外设分配、调试排查等内容整理成一套可直接指导开发的系统笔记。1. STM32H747 双核融合的意义与应用场景1.1 STM32H747 到底是一颗什么样的芯片从名字上理解STM32H747 是 STM32H7 系列中的一员但它并不是一颗普通的 Cortex-M 微控制器而是一颗双核异构 MCU。芯片内部集成了一个 Cortex-M7 内核和一个 Cortex-M4 内核典型工作频率分别是 480MHz 和 240MHz两个内核可以运行不同的程序甚至在两个内核上分别运行不同的 RTOS。相比一颗高主频单核 MCU这种设计的核心价值在于“物理隔离”重量级任务和强实时任务不再抢同一个 CPU而是各占一个物理内核。很多人会把“双核”下意识理解为类似 PC 上“两个核心同时调度同一个操作系统”的 SMP 模型。实际上 STM32H747 更偏向 AMP非对称多处理架构两个核心没有共享的操作系统实例彼此之间需要通过约定的内存区域和事件通知机制协作。这种架构给嵌入式工程带来了更多可能性也要求开发者具备更强的系统设计意识。ST 在 H747 上提供了比较丰富的硬件资源包括大容量 Flash 和 SRAM、LTDC 显示控制器、DMA2D 图形加速器、FMC 外部存储控制器等。但“算力翻倍”并不意味着项目开发难度减半真正需要花心思的是两个核心之间的互斥保护、启动顺序、数据同步和固件更新策略。1.2 为什么实际项目需要双核 MCU过去在工业控制领域特别是伺服驱动器、机器人控制器、高性能电源等场景中通常会采用“DSP MCU”或“MCU FPGA”的方式一颗芯片负责实时控制另一颗芯片负责通信、监控、显示或上位机交互。这样的方案成熟可靠但成本较高、硬件设计复杂、板级面积大两个芯片之间的通信链路易受干扰。STM32H747 的出现让设计者有机会在单颗 MCU 内完成这些分工。Cortex-M7 内核主频高适合承担复杂运算、图形界面、文件系统、物联网协议栈Cortex-M4 内核虽然主频低一些但对大部分控制环路来说已经足够而且可以从体系结构上避免被 M7 上复杂应用干扰。双核之间通过内部共享内存交换数据不存在外置 SPI 或 UART 通信那样的低速瓶颈。此外H747 提供了相对完善的安全与低功耗特性例如硬件加密、随机数发生器、独立看门狗、多种低功耗模式使得它既可以做高性能计算平台也可以在某些场景下通过关闭其中一颗核心来达到功耗控制目标。1.3 适合用 STM32H747 的典型场景综合工程经验来看STM32H747 比较适合下列几类场景一是工业控制器M7 负责 Ethernet、USB、文件系统与人机交互M4 负责高速电流环或伺服控制二是带屏的物联网网关或数据采集设备M7 运行 RTOS GUIM4 负责不依赖系统调度的固定周期采样三是需要同时运行多种协议的通信设备一个核心跑一种协议栈可避免不同类型中断之间的激烈竞争四是科研教学中的多核嵌入式系统课程它很适合用来演示双核通信、缓存一致性、异构启动等技术原理。需要提醒的是使用 H747 之前要先评估项目是否真的需要双核。如果只是一个普通传感器采集任务用一颗高性能单核 MCU 会更简单也能避免双核调试带来的复杂度增加。2. 开发环境准备与工程结构说明2.1 工具链与开发板选型开发 STM32H747官方推荐使用 STM32CubeIDE、Keil MDK 或 IAR Embedded Workbench三者都支持 Cortex-M7 与 Cortex-M4 双核调试。STM32CubeMX 负责图形化生成工程代码可以配置时钟树、外设、DMA、FreeRTOS 和双核相关选项。需要注意版本问题不同芯片批次、不同固件包版本生成的外设驱动和启动文件可能存在差异建议始终根据你手上开发板对应的官方包版本生成工程不要盲从网络博客中过时的配置。硬件方面可以选用 ST 官方开发板例如 NUCLEO-H747ZI 或 STM32H747 探索板。这类板子通常板载 ST-LINK 调试器只需一根 USB 线就能下载和调试两个核心。如果你用的是自研硬件至少要确保调试器支持 Cortex-M7 和 Cortex-M4并且能识别芯片的两个内核。量产阶段通过 UART 或 USB DFU 下载固件时也需要提前规划双核固件的合并和烧录方案。2.2 理解双核工程的结构双核工程与普通单核工程最大的不同是一个完整应用需要编译出两个独立的二进制文件分别对应 core 1 和 core 2 工程。通常 STM32CubeIDE 项目中会创建 CM7 和 CM4 两个子工程CM7 对应主核CM4 对应从核。从软件职责看CM4 工程更像一个独立的小型单片机项目有自己的 main 函数、HAL 初始化、中断向量表和链接脚本。而 CM7 工程除了实现主核业务外还要负责引导 CM4、检查从核固件状态、在必要时完成从核固件的二次加载。因此在实际操作时很多团队会先完成 CM4 工程把它编译成 bin 或 hex再放入 CM7 工程的 Flash 地址规划中CM7 上电后先做自身初始化再跳转到 CM4 固件所在地址。这种主从式工程结构非常适合从零理解双核开发因为所有协作逻辑都由开发者自己控制不会像 SMP 那样由操作系统隐藏并行细节。缺点是需要开发者对内存布局有更高敏感度稍不注意就会出现两个工程地址范围重叠、符号冲突、数据互相覆盖的问题。2.3 建议的工程目录组织方式我建议在项目最开始就使用清晰的目录分隔避免把所有代码堆在一起。下面是一个相对合理的参考结构demo_h747/ ├── CM4/ │ ├── Core/ │ │ ├── Inc/ │ │ ├── Src/ │ │ └── Startup/ │ ├── link_script/ │ └── build/ ├── CM7/ │ ├── Core/ │ │ ├── Inc/ │ │ ├── Src/ │ │ └── Startup/ │ ├── link_script/ │ └── build/ ├── shared/ │ ├── include/ │ │ ├── shm_protocol.h │ │ └── board_resources.h │ └── src/ └── tools/ ├── merge_firmware.py └── flash_map.mdCM7 与 CM4 各自保留独立源码共享部分放在shared目录中例如两个核心都会引用的共享消息结构体、内存地址宏、外设资源编号等。tools目录用于存放固件合并、地址校验脚本这对于后续工厂量产很有价值。3. STM32H747 的架构与存储域拆解3.1 双核心与内存访问的基本关系分析双核 MCU不能只看 CPU 指令集还要看总线拓扑和内存归属。STM32H7 系列芯片把内部资源划分为多个域这样做的目的是让不同外设和内存挂载到合适的总线上兼顾访问速度与功耗控制。STM32H747 上的两个核心并不对称。Cortex-M7 通常作为主核对整个系统的 Flash、外部存储控制器、显示控制器等资源拥有更强的掌控能力Cortex-M4 更像一个实时加速处理器可以独立运行控制程序也可以访问被明确允许的 RAM 区域和外设。由于处理器复位后往往只有一个核心从主 Flash 启动另一个核心需要主核辅助引导这一特点直接影响上电执行流程。这里需要特别留意的是M7 拥有紧耦合内存 TCM它对 M7 访问延迟极低许多开发者喜欢把中断服务函数或关键数据结构放进 TCM但 TCM 通常不是全芯片共享资源。若 M4 也要访问同一份数据就不能把数据放在 M7 私有内存区域里而应放在两个 CPU 都能访问的 SRAM 上。这个区别看起来简单实际项目里很容易被忽略导致出现“M7 能读到数据、M4 读不到”的异常。3.2 D1、D2、D3 域与低功耗管理在 STM32H7 数据手册中资源会按 D1、D2、D3 域进行描述。D1 域通常由 Cortex-M7 主处理器和其高带宽外设组成D2 域可以理解为第二个处理器域D3 域则带有更多低功耗相关逻辑。默认情况下CPU 复位后并不是所有域都会被打开开发者如果没有激活目标外设所在域的时钟和电源即使代码看起来已经调用了外设初始化函数外设也可能没有任何反应。这意味着在双核项目中初始化代码不再像单片 MCU 那样“一次全部打开”而要有清晰的域管理概念。比如当你使用某个挂载在 D2 域的定时器时M7 访问之前需要确认对应总线时钟已经被使能当你想让 M4 把一个 DMA 搬运结果写到共享内存时也需要保证共享内存所在域在低功耗模式下不会被意外断电。从调试经验看H7 系列外设“没反应”的问题很多并不出在寄存器配置而出在域时钟开关与复位状态上。因此遇到症状时可以先回查当前外设属于哪个电源域是否使能了对应域时钟而不是反复修改寄存器值。3.3 RAM 类型与共享内存的选择STM32H747 内部有多个 SRAM 块但它们的访问特性差别很大。有些 SRAM 挂在较高带宽的 AXI 总线上适合 DMA、显示缓冲等大数据吞吐场景有些 SRAM 与内核紧耦合延迟低但容量较小还有一些 SRAM 位于低功耗域在系统休眠时需要特别处理。在规划共享内存时建议从两个维度筛选第一M7 与 M4 是否都能访问第二共享内存是否需要被 DMA 和外设访问。如果共享缓冲只是两个 CPU 之间传递控制参数选择一块访问速度满足应用需求的 SRAM 即可如果共享缓冲还要与 DMA 数据传输联动就要考虑总线带宽、Cache 一致性、对齐要求等问题。设计时还会遇到 Flash 分配问题。M7 与 M4 各自运行独立固件通常把 M4 固件写在 Flash 的一个独立扇区或 Bank 中。启动时 M7 通过某种方式将 M4 复位向量加载到正确地址使其开始执行。两个内核的 Flash 区域必须要隔离清楚不能让 M4 程序区覆盖 M7 的程序区也不能因为 Flash 擦写操作导致另一个内核正在执行的代码被破坏。3.4 内存映射信息的获取方式不同型号的 H7 芯片内部 SRAM 大小和映射并不完全一致即使是同一系列的不同封装外设数量和内存边界也可能不同。编写本文时无法给出一个适用于所有子型号的绝对地址表因为硬件细节永远以官方数据手册和参考手册为准。最稳妥的做法是打开你的 STM32 工程在链接脚本或 memory 分区文件里查看实际使用的 RAM/Flash 地址范围再结合数据手册中的 memory map 确认哪些区域允许两个 CPU 同时访问。很多工程师习惯把地址宏放到shared/include头文件中统一管理比如M4_FW_START_ADDR、SHM_BUFFER_ADDR、SHM_BUFFER_SIZE这样在 CM7 和 CM4 两个工程中引用同一套定义能减少地址不一致导致的问题。4. 双核启动流程与引导配置4.1 为什么需要关心双核启动顺序在单核单片机中启动流程通常由复位向量、启动文件和 main 函数确定开发者并不需要过多介入。但在 STM32H747 上两个核心最终都要运行系统必须明确谁先生成谁后运行。常见的启动策略是M7 为主核默认从 Flash 启动并执行主流程M7 初始化自身系统时钟、电源和外设后再检查 M4 固件是否存在于指定地址如果存在就设置好 M4 的起始地址并解除 M4 复位使 M4 开始运行。这种方式便于实现主核统一管理、便于在工厂中把 M4 固件和 M7 固件合并成一个镜像。另一种方式是配置选项字节让系统复位后 M4 直接从某个 Flash 地址启动。这种方式在产线烧录和固件更新策略上会更复杂因为两个核心都希望获得独立的启动控制权容易出现“两核都尝试格式化 Flash”的冲突。多数开发板和示例工程默认采用 M7 引导 M4 的方式对学习也更友好。4.2 从向量表理解 M4 的启动入口ARM Cortex-M 内核的启动机制比较简单复位后内核会从向量表取出前两个 32 位数据第一个作为主栈指针 MSP第二个作为复位向量 Reset_Handler然后跳转到该地址执行。M7 引导 M4 时本质上也是利用这个机制。假设 M4 固件被烧录在 Flash 的0x08100000地址开头那么0x08100000处存放的是 M4 初始栈顶地址0x08100004处存放的是 M4 复位函数地址。M7 程序只要读取这两个字再配合芯片提供的从核复位控制就能让 M4 像一个普通 Cortex-M 芯片那样启动。有一类很容易出现的问题M4 固件被放在一个错误的分区或者 M4 固件的链接脚本没有把向量表放在区段起始位置导致 M7 按约定地址读到的前两个数值并不正确。这时系统可能出现 M7 正常运行但 M4 完全没有执行或者跑飞的现象。调试时建议查看 M4 固件的链接脚本同时用调试器读取 Flash 起始地址中的内容确认向量表是否真的是 M4 的向量表。4.3 M7 跳转 M4 的代码示例下面是一个简化的 M7 引导 M4 的代码流程重点展示实现思路。实际项目中应根据 STM32CubeMX 生成的双核引导代码替换其中的复位与跳转操作不要直接把伪代码原样复制到没有适配的工程里。/* 文件路径CM7/Core/Src/m4_boot.c */ #define M4_FW_START_ADDR 0x08100000U /* M4 固件在 Flash 中的起始地址 */ typedef void (*Jump_Func)(void); void Jump_To_M4_Core(void) { uint32_t m4_sp; uint32_t m4_reset_pc; Jump_Func jump_to_m4; if (M4_FW_START_ADDR 0U) { return; } /* 读取 M4 向量表前两个字 */ m4_sp *(volatile uint32_t *)M4_FW_START_ADDR; m4_reset_pc *(volatile uint32_t *)(M4_FW_START_ADDR 4U); /* 简单有效性检查防止地址异常造成 HardFault */ if ((m4_sp 0U) || (m4_reset_pc 0U)) { return; } jump_to_m4 (Jump_Func)m4_reset_pc; /* 跳转前关闭全局中断避免中断上下文错乱 */ __disable_irq(); /* * 在 CubeMX 生成的工程中通常会有 CM4 核复位控制逻辑。 * 你需要先设置 CM4 的启动地址再释放 CM4 的复位 * 也可以直接调用官方生成的 boot 函数。 * 此处仅保留跳转示意。 */ jump_to_m4(); /* 正常情况下不会回到这里 */ while (1U) { } }需要注意的是实际 H7 的从核启动常常涉及芯片内部的复位控制寄存器不能只做一个普通函数指针跳转。M7 必须确保 M4 的复位状态被正确释放同时要让 M4 的异常向量表指向 M4 固件所在地址。如果使用 DSP 库、浮点运算单元或系统定时器M4 启动代码也需要在进入用户 main 函数前完成相应初始化。4.4 链接脚本与扇区规划双核项目中对链接脚本的修改一定要谨慎。CM4 工程的 Flash 起始地址与长度必须与 CM7 工程中预留的 M4 区域一致RAM 区域也不能与共享内存区域混淆。比如规定0x08100000到0x08140000属于 M4 固件区那么 M4 链接脚本的FLASH起始地址应设置为0x08100000长度不要跨越到别的分区。在 CM7 工程中还可以定义固定的符号来保存 M4 固件长度与校验值。量产阶段读取这些字段可判断 M4 固件是否被合法烧写避免在空片或烧写中断状态下盲目跳转。使用内部 Flash 时还要特别注意不要在 M4 正在运行时擦写 M4 所在扇区否则 M4 会立即失去指令流产生不可预知的故障。5. 双核通信方案从共享内存到 OpenAMP/RPMsg5.1 双核之间需要交换哪些数据确定双核通信方案前先要梳理两个核心之间的数据流。工业控制项目中常见的通信内容包括M7 向 M4 发送使能指令、转速目标、控制参数M4 向 M7 反馈当前状态、故障码、采样数据两个核心可能共用同一个传感器数据缓冲也可能需要互相通知事件。不同类型的消息适合不同通信方式并没有一种通用方案能覆盖所有场景。如果数据量很小频率很高例如 10kHz 电流环的任务通知比较复杂的大协议栈可能并不合适如果 M7 需要把大批量文件或图像内容传给 M4那么共享大缓冲区加 DMA 会更有效。比较好的设计思路是把“实时性要求高、数据长度固定”的部分设计成独立共享通道把“异步、命令类”的消息走消息邮箱这样既保留低延迟也保证系统易维护。5.2 共享内存的基本模型共享内存是双核通信中最基础的手段。它本质上是在两个 CPU 都能访问的内存区域中划分一块缓冲区定义清楚数据结构与读写状态。最简单的模型包括三个要素数据区、状态标志、方向约定。例如可以向下面这样定义共享协议/* 文件路径shared/include/shm_protocol.h */ #ifndef SHM_PROTOCOL_H #define SHM_PROTOCOL_H #include stdint.h #define SHM_MAGIC_WORD 0x48473437U /* HG47 的 ASCII 组合用于校验 */ #define SHM_CMD_BUFFER_SIZE 16U typedef enum { SHM_STATE_IDLE 0, SHM_STATE_M7_WRITE_DONE, SHM_STATE_M4_PROCESS_DONE } ShmState_t; typedef struct { uint32_t magic; /* 共享内存标识 */ volatile ShmState_t state; /* 状态标志 */ uint32_t cmd_id; /* 命令 ID */ uint32_t seq; /* 序号用于丢包检测 */ uint32_t param[4]; /* 通用参数 */ uint8_t data[SHM_CMD_BUFFER_SIZE]; /* 自定义数据 */ } SharedCmd_t; #endifM7 侧写入数据并更新状态SharedCmd_t *shm_cmd (SharedCmd_t *)SHM_BUFFER_ADDR; shm_cmd-cmd_id CMD_START_MOTOR; shm_cmd-seq; shm_cmd-param[0] target_speed; shm_cmd-state SHM_STATE_M7_WRITE_DONE;M4 侧轮询状态并对数据进行处理SharedCmd_t *shm_cmd (SharedCmd_t *)SHM_BUFFER_ADDR; if (shm_cmd-state SHM_STATE_M7_WRITE_DONE) { /* 解析命令并执行控制 */ execute_motor_command(shm_cmd-cmd_id, shm_cmd); /* 处理完成后把状态切回 IDLE 或写完后状态 */ shm_cmd-state SHM_STATE_M4_PROCESS_DONE; }这种“状态位 数据区 轮询”的方式非常直观是所有共享内存通信的基础。但它也存在明显问题如果 M7 正在写数据时 M4 突然读到半新半旧的数据就会产生不一致。因此在复杂通信中要引入锁、乒乓缓冲或硬件信号量来保护共享区。同时如果 M7 和 M4 都启用了 Cache还需要考虑缓存一致性问题否则可能出现调试器里看到内存已更新、CPU 却仍然读到旧缓存的情况。5.3 进入共享临界区的安全手段跨核共享内存与单核中的线程安全有所不同。单核内可以通过关中断或者使用 RTOS 的互斥量来保护临界区但在两个独立 CPU 之间一个核关闭中断并不能阻止另一个核心访问共享区域。因此STM32H7 提供了硬件信号量 HSEM 等机制用于在两个内核之间建立互斥。当需要修改共享结构体时可以先获取硬件信号量成功后再进行操作操作完成后释放信号量。如果获取失败说明另一个核心正在操作数据当前核心可以等待或重试。使用 HSEM 能避免“两个核同时对同一个缓冲区执行写操作”的风险。不过 HSEM 的使用也有讲究它只能保护软件设计中对共享资源的访问顺序无法自动保证 DMA 与外设操作的一致性开发者仍然需要设计合理的访问协议。除了加锁机制也可以采用“单写者”原则某一段共享数据只允许 M7 写M4 只读另一段数据只允许 M4 写M7 只读。单写者模型在大部分实时控制场景中足够用而且能绕开很多棘手的并发问题。如果通信双方都需要修改同一个复杂结构体才需要引入更严格的锁机制。5.4 OpenAMP 与 RPMsg 通信框架完全手动实现共享内存协议优点是灵活、延迟低且可控缺点是各类标志、锁、缓存维护逻辑需要自行验证项目越大越容易出错。ST 官方在部分软件包中提供了 OpenAMP 支持它能帮助用户建立基于 RPMsg 的消息通信通道。RPMsg 是一种用于远程处理器消息传递的协议常见于 AMP 多核系统。它构建在共享内存和硬件中断通知机制之上提供相对抽象的发送和接收接口。调用方不用关心消息具体放在哪个内存地址也不需要手动管理复杂的就绪标志框架会维护通信通道。相比手写共享内存OpenAMP/RPMsg 功能更完整更适合传输不规则命令、配置包或日志。但使用 OpenAMP 也需要付出系统资源代价代码体积更大、初始化流程更复杂、内存占用更多。对于那些只需要传一个 32 位速度值的应用未必比一个简单的共享内存变量更有优势。因此在工程上常见做法是混合使用底层实时控制数据用共享内存直接传递上层复杂命令和固件管理消息走 OpenAMP/RPMsg。下面的表格简单对比两个方案的特点维度手写共享内存OpenAMP/RPMsg实时性高可由应用直接控制中上取决于配置代码复杂度低适合小型数据交换中高需要中间件初始化功能完整性需自行实现锁和协议提供标准化消息通道调试难度较高需要自己排查同步问题相对统一但中间件内部逻辑复杂适用场景高频、固定长度控制数据多变命令、配置、日志同步6. M7 与 M4 的分工与外设分配策略6.1 常见任务分配方式理论上一颗芯片里的两个 CPU 可以执行任何代码但实际项目应根据总线资源、外设归属和实时性需求设计分工。一种典型方式是“应用核 控制核”。M7 运行 RTOS承担 Ethernet、USB、LCD 显示、SD 卡文件系统等低速复杂业务M4 单独运行一个带固定周期中断的控制代码执行电流采样、编码器读取、PWM 更新。这样可以保证控制环路的执行时间非常稳定不会被 M7 上的高延迟任务或频繁中断干扰。另一种方式是“主协议核 采集核”。M7 负责运行主要通信协议和用户指令解析M4 负责多路 ADC 采集、传感器故障判断和硬件保护。如果 M4 运行在较独立的环境中即使 M7 因为网络异常出现任务堆积仍然能保持系统安全监控。还有一个常见的派生用法一颗核负责高可靠性隔离另一颗核负责需要频繁更新或第三方调试的功能。这种分配通常不是性能需求而是工程管理需求。开发者可以把未稳定代码限制在一个核内减少不稳定代码对另一个核安全逻辑的影响。6.2 外设资源分配原则STM32H747 上同一个外设通常只有一个寄存器实例例如项目里只有一个指定 UART、一个指定 TIMx 等。两个 CPU 不能同时对一个外设寄存器执行配置否则会导致前一核写入的值被后一核覆盖。因此外设分配应当尽量做到“谁初始化、谁使用”而不是“两边都能访问”。例如 UART 打印日志可以只分配给 M4 或 M7用不同串口输出各自日志。如果串口资源紧张可以在硬件上使用一个带 DMA 的缓冲结构但必须保证 DMA 配置和缓冲区的消费者逻辑是清晰分层的。中断服务函数也不能随意同时挂在两个内核上需要确定该中断到底由哪个 CPU 响应。ST 芯片通常允许通过中断控制器或者相关配置将外设中断路由到指定核心。分配外设时建议建立一张“外设资源表”把每个外设、归属核、主要用途、是否共享、是否启用中断等信息全部记录。这个表格可能不会直接写进代码但它能有效阻止后期并行开发过程中两个工程师同时修改同一外设配置。6.3 中断与实时性设计双核系统中中断延迟是实时性重要指标。M4 核控制环路如果希望获得确定中断响应就要尽量减少 M4 上的其他高优先级中断避免锁中断时间过长。M7 上可以比较宽容地运行 GUI 或网络栈但仍要避免 M7 的误配置影响 M4。两个 CPU 都有各自独立的总线和调试单元但最终仍共享内存带宽和外设总线。当一个核频繁启动大量 DMA 搬运大块数据时另一个核可能出现总线延迟或者共享内存竞争这种“软影响”不容易从代码逻辑上发现。测量时会表现为控制环路偶尔多出几百纳秒到几微秒延迟因此在高实时系统中需要合理分配 DMA 和内存访问优先级。7. 实战参考M7 做显示与指令管理M4 做控制循环7.1 项目需求与功能拆分本节以一个简化的双核协作系统为例说明如何把理论应用到工程结构中。假设项目需要实现一个带屏幕的电机控制器屏幕上显示实时转速、电流和故障信息用户通过按键或触控设定目标转速。M7 负责显示与用户交互M4 负责读取编码器并更新 PWM 输出。之所以这样拆分是因为屏幕上如果直接由控制核驱动LCD 刷屏和显示缓冲搬运可能对控制周期造成不确定性。而 M4 只负责窄而固定的控制流程更容易通过逻辑分析仪观察实时性。系统之间通过共享内存传递三种信息命令信息M7 发送“启动”“停止”“目标速度”给 M4状态信息M4 定时向 M7 回传“当前速度”“电流”“错误码”握手信息用于确认共享通道是否正常、固件版本是否匹配。7.2 共享结构体设计项目中可以将共享结构体分为两个方向尽量避免同时读写typedef struct { volatile uint32_t cmd_valid; /* 置 1 表示 M7 已发送新命令 */ uint32_t cmd_code; int32_t target_speed; uint32_t cmd_timeout_ms; } M7ToM4_t; typedef struct { volatile uint32_t ack_valid; /* 置 1 表示 M4
返回列表