
RT-Thread 双核 BSP 实战i.MX RT1180 EVK 上 CM33 拉起 CM7 并跑通 RPMsg-Lite 核间通信【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread这篇以 RT-Thread 双核 BSP 中的 i.MX RT1180 EVK 板级支持包为对象解决一个问题一颗芯片里装着 800MHz 的 Cortex-M7 和 240MHz 的 Cortex-M33怎么让两个核各自独立编译运行、由 CM33 主核把 CM7 从核拉起来再用 RPMsg-Lite 在共享内存上完成 ping-pong 通信。下文全部基于仓库里的 BSP 源码bsp/nxp/imx/imxrt/imxrt1180-nxp-evk逐步演示不涉及任何外部依赖说明。 场景一颗 M33 加一颗 M7各自该干什么活先交代一下这颗芯片的定位。i.MX RT1180 是 NXP 的跨界 MCU把两个内核塞在同一个 die 里Cortex-M7800MHz算力担当适合电机控制、实时信号处理这类重计算任务Cortex-M33240MHz带 TrustZone 安全扩展适合管安全启动、系统管理和网络协议栈。外围资源也很工业双千兆以太网、多种工业通信接口含 EtherCAT宽温范围。所以它面向的就是工业控制、电机驱动这类场景——而这些场景恰恰需要两个核分工协作一个干活一个管安全与系统。BSP 对此的设计是CM33 当主核masterCM7 当从核remote两个核各有一套完全独立的工程可以分别编译、分别下载如果不想手动下两个镜像也可以用 MCUXpresso Secure Provisioning Tool 生成一个可启动的双核镜像。小提示本文所有操作都在这块板子上做如果你手上是 RT1170 等其他 i.MX RT EVK流程基本通用只是串口和控制台配置不同。⚡ 三条命令跑通从 pkgs --update 到 Hello_World编译前先把依赖包拉下来这个 BSP 依赖NXP IMXRT 驱动包对应 cm33/rtconfig.h 里的PKG_USING_NXP_IMXRT_DRIVER。跳过这步编译必挂因为缺库。在 BSP 目录下打开 ENV 工具后执行pkgs --update生成工程并烧录MDK5、IAR、GCC 三条路都通了按自己习惯选scons --targetiar # 生成 IAR 工程 scons --targetmdk5 # 生成 KEIL MDK5 工程 scons -j8 # 直接并行编译 GCC 工程工具链参数和链接脚本由 cm33/rtconfig.py 决定生成的 IDE 工程落在对应核的目录如cm33/下。硬件侧只要两根线数据线接 PC板上自带调试器、打开电源开关。我以 IAR 为例双击project.eww打开工程点编译然后下载。工程默认走CMSIS-DAP下载——保证 CMSIS-DAP 连接正常后点下载按钮即可烧录不用额外配置。打开串口验证下载完系统自己就跑了。把开发板串口接 PC终端按115200-8-1-N打开复位后先看到启动 banner\ | / - RT - Thread Operating System / | \ 5.2.2 build May 15 2026 17:19:35 2006 - 2024 Copyright by RT-Thread team接着 CM33 工程会打印MIMXRT1180_CM33 Hello_World并翻转板载 LEDcm33/applications/main.c引脚GET_PIN(4, 27)500ms 一个来回CM7 工程则打印MIMXRT1180_CM7 Hello_World。看到这两句就说明两个核各自活着了。️ 工程地图cm33 和 cm7 两套工程怎么分工目录结构一眼能看明白——同一层下两个平行工程内部布局完全对称imxrt1180-nxp-evk/ ├── README.md / README_zh.md ├── cm33/ # 主核工程 │ ├── applications/ # main.c / multicore_thread.c / mnt.c │ ├── board/ │ │ ├── MCUX_Config/ # NXP 生成的时钟、引脚配置 │ │ ├── linker_scripts/ # RAM / FLEXSPI_NOR / HYPERRAM 三套 │ │ ├── ports/ # flexspi NOR flash 驱动、FAL 移植 │ │ └── Kconfig # 外设配置菜单 │ ├── xip/ # FlexSPI NOR XIP 启动配置 │ ├── rtconfig.h / rtconfig.py │ └── template.ewp / template.uvprojx ... └── cm7/ # 从核工程结构同 cm33此时你可能会问两个工程到底差在哪答案都写在各自的rtconfig.h里对比项cm33/rtconfig.hcm7/rtconfig.h架构宏ARCH_ARM_CORTEX_M33ARCH_ARM_CORTEX_SECUREARCH_ARM_CORTEX_M7ARCH_ARM_CORTEX_FPU控制台uart1LPUART1uart12LPUART12串口 DMA 通道RX ch0 / TX ch1RX ch22 / TX ch23版本RT_VER_NUM 0x50300RT-Thread 5.x同左默认外设BSP_USING_QSPIFLASH/BSP_USING_DMA/BSP_USING_GPIO/ 对应 LPUART同左记住一个关键点两个核的控制台不是同一个串口——CM33 走 UART1CM7 走 UART12调试时想同时看两边日志得接两路串口分别监听。BSP 目前的外设支持面以仓库现状为准板载QSPI Flash XIP外部 NOR Flash 直接跑代码、flexspi Flash 驱动、CherryUSB设备/主机两模式、NETC 交换控制器双千兆以太网、EtherCAT片上多核 kick-off、Rpmsg-lite、GPIO、LPUART1~12、LPSPI1~4、LPI2C1/2/3/6、ADC含 LPADC1 多通道 DMA 示例、TimerDWT 周期计数 微秒延时、SDIO可配 FATFS/LittleFS、RTC、FLEXCAN3暂不支持PWM文档标注后续版本规划用到前先确认。 外设按需开menuconfig 里这些开关各管什么BSP 默认只给最小串口配置其余外设全靠 ENV 工具开关。标准流程四步在核工程目录打开 ENV →menuconfig配置并保存 →pkgs --update→ 重新scons --targetmdk5或scons --targetiar。菜单本体在 cm33/board/Kconfigcm7 对应一份值得留意的项我归成三组。片上外设大部分带 DMA 联动DWT周期计数器 微秒级忙等延时提供dwt_init()/dwt_get_cycles()/dwt_delay_us()DMA总开关勾选任何 UART/SPI/I2C 的 DMA 选项会自动把它选中GPIO默认开自动选RT_USING_PIN配合GET_PIN()用RTC默认关USBCherryUSB先选控制器OTG1/OTG2再选角色Device/HostHost 模式下可勾BSP_CHERRYUSB_HOST_MOUSE_DEMO跑鼠标 shell 示例对应 cm33/board/usbh_mouse_demo.c 与 cm33/board/cherryusb_cdc_acm.cSDIO开了之后可再勾CODE_STORED_ON_SDCARD让 SD 卡当启动设备LPUART1~12每路独立使能各自配 RX/TX DMA 通道0~32默认递增LPSPI1~4同理可单独开 DMALPI2C1/2/3/6每路在 100kHz/400kHz 里选波特率CANFLEXCAN3默认开FLEXSPI1/2外部 Flash/SRAM 总线控制器QSPI Flash 和文件系统都压在它上面。板载外设与内存布局HyperRAMBSP_USE_HYPERRAM把外部 HyperRAM 挂成扩展内存以太网NETCBSP_USING_ETH会自动选中 lwIP/SAL/netdevNETC_USE_SWT选模式0 为 EP0 直连1 为 switch 交换PHY 默认开文件系统BSP_USING_FS下可以组合 SD 卡 FATFSBSP_USING_SDCARD_FATFS或 QSPI Flash LittleFSBSP_USING_QSPI_FLASH_FS依赖 FAL 分区表见 cm33/board/ports/fal_cfg.hQSPI FlashBSP_USING_QSPI_FLASHFlexSPI1 上 NOR Flash 的读写驱动。内存布局是三选一在 Kconfig 末尾的 Linker Script Selection 里对应 cm33/board/linker_scripts/ 下不同后缀的链接脚本BSP_LINKER_SCRIPT_RAM镜像全在内嵌 SRAM 里跑BSP_LINKER_SCRIPT_FLEXSPI_NOR外部 NOR Flash 上 XIP 执行默认BSP_LINKER_SCRIPT_FLEXSPI_NOR_HYPERRAMXIP HyperRAM 当附加 RAM。rtconfig.py会扫描rtconfig.h里的BSP_LINKER_SCRIPT_*宏自动挑脚本生成 Keil 工程时还通过update_keil_active_target()把project.uvoptx的当前 Target 同步成rtthread_ram/rtthread_flexspi_nor/rtthread_flexspi_nor_hyperram。也就是说menuconfig 里换完选项重新生成工程Keil 里的 Target 自己就跟着换了不用手动切。 源码拆解CM33 是怎么把 CM7 叫醒的多核逻辑全在 cm33/applications/multicore_thread.c。入口是multicore_init()通过INIT_APP_EXPORT在应用初始化阶段建一个名叫multicore的线程——栈 2048 字节、优先级 10、时间片 5线程内按顺序做完 kick-off、RPMsg-Lite 初始化再跑 ping-pong。kick-off 序列对应 Kconfig 的BSP_USE_MULTICORE_KICK_OFF默认开是这样的MCMGR_Init()初始化多核管理单元MCMGR_RegisterEvent(kMCMGR_RemoteApplicationEvent, ...)先注册回调等 CM7 上报就绪BOARD_GetCore1ImageAddrSize()拿到 CM7 镜像的源地址、目的地址、大小、启动地址并打印核对BOARD_PrepareCore1()把镜像搬到目标内存地址信息来自 cm33/board/board.hMCMGR_StartCore(kMCMGR_Core1, boot_addr, rpmsg_lite_base, kMCMGR_Start_Synchronous)同步方式启动 CM7注意第三个参数——RPMsg 共享内存基址是在放核那一刻直接传给从核的之后轮询等 CM7 通过RPMsgRemoteReadyEventData上报 ready每 10ms 查一次。为什么顺序不能乱因为从核放出来之前主核必须先完成镜像落位 复位向量指向正确地址 通信区地址告知这三件事否则 CM7 醒来第一件事就是跑飞。Kconfig 里BSP_USE_MULTICORE_KICK_OFF的 help 也写明了CM33master拉起 CM7remote时kick-off 是保证初始化顺序正确所必需的。 RPMsg-Lite在共享内存上做 100 轮 ping-pongRPMsg-Lite 是 RPMsg 协议的轻量实现两个核之间不靠中断消息、全靠一段双方都能访问的共享内存传消息对应 Kconfig 的BSP_USE_MULTICORE_RPMSG_LITE默认开。源码里有几个关键点共享内存区怎么放。定义了一个 6144 字节的rpmsg_lite_base[]数组且必须放进链接脚本约定的段里三种编译器各有各的写法#if defined(__ICCARM__) /* IAR */ #pragma location rpmsg_sh_mem_section static char rpmsg_lite_base[SH_MEM_TOTAL_SIZE]; #elif defined(__CC_ARM) || defined(__ARMCC_VERSION) /* Keil */ static char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(rpmsg_sh_mem_section))); #elif defined(__GNUC__) /* GCC */ static char rpmsg_lite_base[SH_MEM_TOTAL_SIZE] __attribute__((section(.noinit.$rpmsg_sh_mem)));段名必须和链接脚本里的定义对上换编译器或改链接脚本时这里最容易翻车。主核侧初始化链条rpmsg_lite_master_init()以 master 身份起来 →rpmsg_queue_create()建接收队列 →rpmsg_lite_create_ept()建本地端点地址默认 40带接收回调→rpmsg_ns_bind()绑定名称服务然后阻塞等待 CM7 的名称服务广播远端端点地址写进remote_addr。名称服务的作用就是自我介绍CM7 侧用约定的字符串广播自己CM33 侧听到才知道该往哪个地址发消息。跑通信rpmsg_lite_communication()循环 100 轮rpmsg_lite_send()发一个THE_MESSAGE{DATA}rpmsg_queue_recv()阻塞等对端回包标准 ping-pong 压测。收尾时rpmsg_lite_cleanup()依次销毁端点、队列、名称服务句柄并rpmsg_lite_deinit()。可配置参数Kconfig 里BSP_USE_MULTICORE_RPMSG_LITE下的子项源码用#ifndef兜底不配也能跑RPMSG_LITE_LINK_ID链路 ID默认 0即RL_PLATFORM_IMXRT1180_M33_M7_LINK_IDRPMSG_LOCAL_EPT_ADDRCM33 侧本地端点地址默认 40范围 0~65535RPMSG_NS_ANNOUNCE_STRINGCM7 广播服务用的字符串默认rpmsg-openamp-demo-channelRPMSG_SHARED_MEM_SIZE共享内存大小默认 6144 字节。⚠️ 避坑清单与延伸阅读踩过的坑我列在这里都是顺序不对就白忙级别的pkgs --update必须在编译前执行——NXP IMXRT 驱动包不拉下来编译直接失败CM33 和 CM7 是两个独立工程各编各的、各下各的CM33 是主核负责拉起 CM7只下 CM7 镜像而没有主核先跑从核不会自己动控制台串口不一样CM33 看 UART1CM7 看 UART12都是 115200-8-1-N别拿一根线等两边的日志换内存布局RAM / FlexSPI NOR / HyperRAM后一定要重新生成工程Keil Target 虽会自动同步但旧工程里的链接配置不会自己更新PWM 目前未支持做电机控制外设规划时注意这一点别在 menuconfig 里找它。延伸方向有两个一是同目录下 README_zh.md 有同系列其他 BSP 的双核外设细节可作对照二是 bsp/nxp/imx/imxrt/ 下还有 imxrt1021 / 1052 / 1060 / 1064 / 1170 等工程单核 i.MX RT 的外设驱动套路和 1180 基本一脉相承可以先拿它们练手。【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址: https://gitcode.com/gh_mirrors/rt/rt-thread创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考