拓冰建站拓冰建站
首页 / 资讯中心 / 正文

低功耗双核MCU+BLE 5.2方案设计与实战解析

做低功耗物联网设备的人这几年应该都有同感BLE协议栈越来越重应用功能越来越复杂单核MCU渐渐有点吃不消了。我去年做一款电池供电的资产追踪标签用的就是一颗低功耗双核MCU一个核跑业务逻辑一个核专门伺候BLE 5.2协议栈配合下来既保住了功耗又给应用留足了算力。这篇就围绕“低功耗双核MCU BLE 5.2”这个组合把架构思路、协议栈特性增量、功耗优化的实操细节以及我在实际项目中踩过的坑一并整理出来给正在做选型和方案设计的同行一个参考。1. 双核MCU的架构思路为什么非要多塞一个核1.1 单核方案的两个难言之隐在BLE 4.x时代单核MCU跑协议栈是完全够用的。比如nRF52832一颗Cortex-M4内核既跑Nordic的SoftDevice协议栈又跑应用逻辑大部分场景下相安无事。但从BLE 5.0开始事情起了变化——广播扩展、2M PHY、Coded PHY这些新特性让协议栈的代码量和运行开销明显上去了。再加上很多产品已经不再满足于“连上手机传几个字节”这种简单需求还要本地处理传感器数据、跑加密算法、做显示交互单核的调度压力就到了一个临界点。临界点的表现很典型射频事件是实时性要求极高的任务协议栈在BLE连接事件到来时会抢占CPU如果此时应用正在做耗时的计算比如刷新一块屏幕、算一遍加密两边就会打架。轻则增加系统响应延迟重则丢包、掉连接。你可能会想把应用任务优先级调低一点不就行了问题在于应用任务的实时性也可能很重要比如电机控制的电流环延迟几十微秒都会出事。这就引出了双核方案的核心价值——把实时性要求高的射频协议栈扔给一个专用核让应用核专注跑业务逻辑。两个核各干各的活谁也不用迁就谁。这是架构上的解耦不是单纯堆料。1.2 双核的分工模式与典型组合目前市面上低功耗双核MCU的内核组合大致有这么几类。第一类是两个M33内核比如Nordic nRF5340一颗M33跑应用支持TrustZone另一颗M33跑协议栈和射频。同类内核的好处是编译工具链统一工程管理简单功能安全认证也相对好做。第二类是M33加M0的异构组合比如Dialog DA1469x系列。M33负责应用M0专门跑BLE协议栈。M0的功耗和面积更小把协议栈这种固定逻辑吃下来非常合适。还有一个隐藏优势M0核跑协议栈不容易被应用代码的bug波及协议栈的稳定性更有保障。第三类是把双核概念延伸到“无线子系统”的形式比如STM32WB系列Cortex-M4跑应用Cortex-M0跑协议栈。虽然产品定位略有不同但本质思路一脉相承。不管哪种组合分工逻辑都是一致的协议栈、射频调度、加密相关的安全操作放在专用核传感器采集、用户逻辑、外设控制放在应用核。这么做还有一个附带好处——固件升级时可以独立升级协议栈和应用镜像不用动不动就整包重刷。1.3 跨核通信双核协同的命门双核架构不是把两个核放进同一颗芯片就完事了关键在于核与核之间的通信机制。我把几个主流方案列一下邮箱Mailbox核间发送短消息比如“数据包已就绪请在共享缓冲区读取”属于事件通知机制。共享内存大块数据比如GATT payload、音频流放在指定RAM区域两个核通过指针访问。事件标志Event Flags或信号量用于同步比如协议栈核完成一次连接事件后置位通知应用核可以处理数据了。跨核中断IPC Interrupt一个核触发另一个核的中断是上述机制落地的硬件基础。实操中需要特别注意的是共享内存的互斥访问。双核共享RAM如果没有锁机制应用核在写数据的时候协议栈核在读同一块区域就会出现竞态、读到半截数据。解决办法通常是为每个共享区域配一个信号量或者用单生产者单消费者的环形缓冲区配合内存屏障指令__DMB、__DSB保证数据可见性。我第一次调双核通信时就在这个上面栽过跟头——数据偶尔错乱debug两天最后发现是共享队列的读写指针没有做原子操作。这个坑后面在常见问题部分还会细说。1.4 双核启动流程主核先跑再带从核再来说说双核启动流程这是很多从单核转过来的工程师容易忽略的地方。单核MCU上电后从Reset向量开始执行按部就班初始化时钟、外设、跑main就完事了。双核没这么简单——两颗核必须有一个约定好的启动顺序。通常流程是这样的主核应用核上电后先执行启动代码初始化系统时钟和电源管理然后从Flash的指定地址加载协议核镜像到SRAM或者直接在Flash里执行释放协议核的复位信号协议核就开始从自己的Reset向量执行。协议核启动后完成射频、协议栈初始化再通过共享事件通知主核“我准备好了”两边才开始正式通信。这里有个容易踩的坑协议核镜像的存放地址必须在链接脚本里固定好主核加载时是从固定偏移地址去读如果你改了链接脚本忘记同步更新加载地址协议核就会从错误位置取指令启动后要么HardFault要么跑飞。另外两个核使用同一个时钟源进入低功耗模式时的时钟切换策略要提前设计好比如低频时钟LFO、LFCLK校准、32.768kHz晶振的起振时间这些都会影响唤醒时间和功耗表现。谈到时钟就多说一句很多工程师在开发调试阶段发现有“杂散电流”——明明进入了sleep电流却比手册标称值高不少。排查到最后往往是32.768kHz低速时钟没有正确切换或者外设时钟没有关闭。搞双核MCU时这种问题翻倍因为两颗核的外设都要逐一确认。建议在进入睡眠前用调试器检查两个核各自的电源域寄存器状态确认没有漏关的外设。2. BLE 5.2的增量价值选双核芯片前先看懂协议栈2.1 从BLE 4.2到5.2版本演进到底多了什么不少同行选型时对BLE版本不太在意觉得“BLE就是BLE稳定就行”。其实从4.2到5.2每一代协议栈的增量都是有实实在在价值的尤其是对于低功耗双核MCU协议栈新特性恰恰是双核架构能发挥优势的场景。BLE 4.2引入LE Secure Connections椭圆曲线加密和扩展长度包DLE数据包从27字节扩展到251字节这在物联网安全性要求越来越高的今天非常关键。BLE 5.0带来三个大件2M PHY物理层速率翻倍、LE Coded PHY通过编码实现更远距离、广播扩展Advertising Extensions广播数据容量大幅提升。BLE 5.1加了方向定位AoA、AoD5.2最大的变化是LE Audio和Enhanced ATTEATT以及LE Power Control。这些新特性对MCU的算力和存储要求是在逐步上升的。单核方案跑5.2协议栈不是跑不动而是和应用抢资源的矛盾会被放大。双核MCU在这个背景下成为很多产品线的“安心之选”。2.2 2M PHY、Coded PHY和广播扩展的实际意义一个个说。2M PHY比较好理解物理层速率从1Mbps提升到2Mbps效率翻倍。注意这里的2Mbps是物理层码率实际吞吐还受连接间隔、包间隔、协议开销影响实测下来大概能到1.3到1.4Mbps左右但相比1M PHY的提升是非常明显的。应用场景比如OTA固件升级、音频流传输、批量数据同步这些对速率敏感的场景都吃到了红利。LE Coded PHY则是反其道而行之——速率降下来换距离。它把数据用编码方式传输有S2500kbps和S8125kbps两种模式。S8模式下接收灵敏度可以获得大约8dB的增益配合高增益天线开放环境下通信距离可以从几十米拉到几百米。对于资产追踪、仓储盘点这类需要长距离覆盖的产品Coded PHY的意义大于高速率。广播扩展Advertising Extensions是BLE 5.0里我非常喜欢的一个特性。传统BLE广播信道数据最多31字节很多产品为了多塞几个字节的数据费尽心思。广播扩展把广播数据放到了数据信道上通过AUX_ADV_IND指针链式引用广播数据理论上可以做到255字节甚至更多。再加上周期广播Periodic Advertising接收端可以在固定的时间点去听广播不用一直开着接收机这对功耗是实打实的好处。2.3 LE Audio与ISO信道双核MCU的主场BLE 5.2真正重量级的更新是LE Audio。它引入了等时信道Isochronous ChannelISO支持时间同步的音频流传输并定义了LC3音频编解码器音质在同等码率下比SBC好很多。LE Audio还带来了Auracast广播音频和助听器支持这些能力对未来的音频穿戴、会议设备的架构会产生很大影响。但也正因为音频流是时间同步的MCU必须在精确的时间点准备好数据交给射频前端发送。这个调度精度要求很高——如果应用核同时还在做其他事情很容易错过音频数据包的调度窗口。双核MCU在这里的优势就体现出来了协议栈核专门管理ISO信道的调度应用核专心做音频编解码和业务处理两不耽误。从资源消耗角度看LC3编解码器的运算量虽然比SBC小这也是LC3的一个卖点但仍然需要持续的CPU时间片。如果你用的MCU带硬件加速器比如Nordic的PDM接口配合PDM微控制器、或专用的音频编解码外设应用核的压力会进一步降低。评估芯片时不仅要看内核主频还要看有没有配套的音频硬件外设能省很多事。2.4 LE Power Control被忽视的低功耗帮手相比LE AudioLE Power Control关注度低很多但它和低功耗的关系非常直接。这个特性让通信两端可以动态调整发射功率——当接收端信号很好时可以请求对端降低发射功率省电当信号变差时请求提升功率保证链路质量。在双核MCU方案里协议栈核可以自主完成功率调整的闭环控制应用核完全不用介入。我在一个项目中实测过在信号较强的室内环境下通过Power Control把发射功率从0dBm降到-8dBm发射电流大约能降低3到4mA虽然单次看起来不多但对纽扣电池供电的设备积少成多对整机续航的影响不容小觑。这个特性也提醒我们低功耗不是只有“进入睡眠”一条路通信链路本身的动态优化同样重要。选型时如果芯片和协议栈支持LE Power Control建议规划进去。3. 低功耗实操从引脚配置到功耗测量3.1 先分清几种功耗模式别一上来就sleep功耗优化首先得把芯片的功耗模式摸清楚。以常见的低功耗双核MCU为例一般有运行模式、睡眠模式Sleep、深度睡眠模式Deep Sleep、关机模式System Off、Hibernate这么几档区别主要在于CPU是否运行、内存是否保持、哪些外设还能工作。运行模式两个核全速跑电流通常在毫安甚至几十毫安级别只有处理任务时才用。睡眠模式CPU时钟停了但RAM和寄存器保持外设时钟可以继续跑。电流在几十到几百微安不等唤醒快微秒级适合频繁短时唤醒的场景。深度睡眠大部分时钟和外设都关掉只保留RTC、IO唤醒、BLE的射频唤醒如果开启。电流可以到几微安甚至更低但唤醒延迟在几十微秒到毫秒级。关机模式除了少数唤醒源整个芯片几乎断电RAM内容可能丢失取决于具体芯片。电流可以压到亚微安级代价是唤醒后要重新初始化系统。实际项目中最常用的是“深度睡眠 RTC定时唤醒 外部中断唤醒”的组合。比如温度传感器节点每10分钟醒一次采样、通过BLE上报、再睡回去平均电流就能压得很低。关键是选择合适的唤醒源和唤醒后要做的初始化工作不要为了省那么一点睡眠电流结果把唤醒后的处理时间拖长了反而得不偿失。功耗这块要算总账不是单看某个模式下的电流值。3.2 串口接收端口到底要不要上拉这事有好多人搞错之前有同行在群里问“MCU串口接收端口是否有上拉”这个问题的回答直接影响低功耗和可靠性值得展开说说。先解释一下为什么RXD引脚要“默认高电平”。UART空闲状态是高电平接收端靠检测起始位高到低的跳变来判断一帧数据的开始。如果RXD配置成浮空输入外部又没有接线或者走线很长引脚电位处于不确定状态一个微小噪声就可能被误判为起始位产生垃圾字节甚至频繁唤醒MCU。所以RXD的上拉是必要的。至于用内部上拉还是外部上拉我的经验是如果MCU内部上拉电阻存在且阻值合理一般几十千欧可以先用内部上拉省一颗电阻。但如果通讯双方距离比较远、或者环境电磁干扰较强建议外部加一颗4.7kΩ到10kΩ的上拉电阻内部上拉阻值偏大抗干扰能力不如外部上拉强。在低功耗场景里还有一个隐藏的坑如果你在深度睡眠下把UART当作唤醒源RXD引脚的外部电路变化比如主机发来一帧唤醒数据必须能被引脚中断检测到。这时不仅仅是上拉的问题还要确认UART外设在睡眠模式下是否开启了时钟和中断有的MCU需要做特殊配置比如把RXD复用为GPIO外部中断等唤醒后再切换回UART功能。3.3 ADC工作原理与低功耗采样策略再聊ADC。很多传感器节点都离不开ADC——读电池电压、读温度传感器、读光电二极管都是ADC的活。MCU里最常见的是SAR ADC逐次逼近型。它的工作原理很像用天平称重量内部有一个比较器从最高位开始依次把DAC输出的参考电压和输入电压比较通过逐位逼近的方式确定每一位的值N位ADC就需要N次比较。这个过程的功耗和转换时间基本成正比转换越快动态功耗越高。低功耗采样策略的核心思路就是“能少转就少转能批量转就批量转”。具体做法有降低采样率。很多物理量的变化是慢速的1秒采一次已经足够没必要用1kHz去采。批量采样。ADC每次转换前如果需要对输入电容充电频繁开启的功耗很可观。把多个通道的采样安排在一次转换序列里完成然后统一进入睡眠比单通道反复唤醒更省电。合理选择参考电压和分辨率。有的MCU支持可配置分辨率从8位到12位、16位低分辨率意味着更少的转换时间在精度要求不高的场景比如电池电量粗略判断可以降低到8位或10位。传感器供电门控。如果在采样间隙把传感器的电源彻底断开通过MOS管或负载开关传感器本身的漏电流就不会拖累整机功耗。这个技巧在电池设备里非常实用代价是多一个GPIO控制信号。另外特别提醒一下ADC的参考电压VREF选择对低电压应用很关键。如果电池电压在2V以下就不要选内部参考电压了可以试试按比例采样也就是用电池电压做参考直接读比例值省掉一个基准源功耗和成本都能降一点。3.4 平均功耗怎么算电池寿命估算公式功耗优化的最终效果要落在数字上。给一个我常用的估算方法假设节点的工作周期是每10分钟唤醒一次唤醒后工作2秒包括传感器稳定、ADC采样、BLE连接上报工作电流平均值10mA睡眠电流3μA使用200mAh的纽扣电池。平均电流 (工作电流 × 工作时间 睡眠电流 × 睡眠时间) / 周期总时间 (10mA × 2s 0.003mA × 598s) / 600s ≈ (20 1.794) / 600 ≈ 0.0363 mA 36.3 μA电池寿命 电池容量 / 平均电流 × 效率系数 200mAh / 0.0363mA × 0.7 ≈ 3857小时 ≈ 160天这里的效率系数是经验值考虑了电池自放电、电压跌落、温度影响一般取0.7到0.8比较保守。你看如果睡眠电流能压低几个微安或者唤醒工作时间能压缩到1秒寿命就有明显提升。这就是为什么低功耗设计要同时盯着“睡眠电流”和“唤醒时间”两头不能只优化一边。这个估算方法也推荐在项目立项时就做一遍用Excel拉个表格把不同连接间隔、广播间隔、采样周期都算一遍选型就有依据了。4. 开发环境与调试心得双核工程不比单核省心4.1 开发环境VS Code已经是很主流的选择现在做MCU开发早就不局限于厂商自带的IDE了。VS Code ARM GCC CMake的搭配在圈子里越来越流行跨平台、插件丰富、代码浏览体验好还能和Git、CI流程无缝衔接。前阵子有人问“VS Code中怎么搭建普冉MCU开发环境”这类需求越来越多——厂商的官方SDK大多已经支持命令行构建配合VS Code的CMake插件、Cortex-Debug插件就能跑起来。搭建和调试的流程大致是安装ARM GCC交叉编译器、安装CMake和Ninja、克隆厂商SDK、在VS Code里配置CMake kit指向GCC、用Cortex-Debug配置调试器J-Link、DAP-Link、ST-Link都行、设置好Flash算法或烧录脚本然后就可以在VS Code里打断点、看寄存器、看变量了。相比厂商IDEVS Code最大的优势是“通吃”——不同厂商的芯片你都可以用同一套工作流不用切来切去。但也有一个需要注意的地方双核MCU的调试器配置比单核复杂你在VS Code的launch.json里要分别配置两个核的调试会话有些调试器一次只能连接一个核需要先连接主核再连从核或者在调试主核时让从核保持自由运行。具体怎么配要仔细看芯片厂商提供的调试指南。4.2 双核工程的构建、烧录与镜像管理双核工程的构建有几种模式。一是厂商提供联合构建脚本一条命令同时编译应用核和协议核镜像然后自动合并成单个烧录文件。最简单建议优先用这个。二是各自独立工程、独立编译最后用合并工具拼成一个烧录文件适合两个核代码由不同团队维护的场景。三是完全分开烧录主核固件和从核固件分别用不同的烧录脚本写入Flash适合协议栈镜像相对固定、只升级应用固件的产品。我个人的建议是开发阶段用第一种一键构建一键烧录效率高生产阶段用第二种或第三种把协议栈镜像和应用镜像分开管理方便做差异化定制和OTA升级。说到OTA双核的OTA比单核要复杂一截。单核升级只需要管理一个镜像区、一个版本号双核至少要管理两个镜像的存储布局、各自的有效标志位、以及跨核升级的协作流程——比如新版协议栈镜像下载完成后是让主核重启后统一搬运还是协议栈核自己分块搬这些在设计阶段就要确定不然后期改很痛苦。4.3 低功耗调试的几个技巧低功耗调试和普通功能调试是完全不同的思路踩过坑的人才懂。第一严禁用串口打印来调低功耗。串口本身要供电、要跑时钟、要驱动外设一个串口开在那儿几条毫安的电流就没了。更麻烦的是串口打印会让MCU频繁从睡眠中醒来测出来的功耗曲线完全失真。正确做法是用GPIO翻转配合逻辑分析仪把关键事件进入睡眠、唤醒、ADC采样完成、BLE事件的电平变化采下来时间戳清清楚楚。第二仿真器连接状态下测不到真实功耗。大多数调试器需要MCU保持调试时钟运行这会破坏低功耗模式。测功耗前要断开调试器或者把调试连接配置为“在低功耗模式下自动断开”。我习惯的做法是先接上仿真器看功能逻辑确认没问题再拔掉仿真器用万用表或功耗分析仪测真实电流。第三深睡眠下唤醒源的排查。如果设备睡下去之后偶尔被莫名唤醒最常见的嫌疑是GPIO中断配置错误、RTC闹钟误触发、UART噪声误判。建议在唤醒入口打印用RTT注意不是串口或翻转一个GPIO来标记唤醒源跑一段时间看日志就能定位是哪个外设在捣乱。RTT在SystemView或者J-Link RTT Viewer里看都非常方便还不会影响低功耗。5. 实战案例一节纽扣电池跑一年的BLE 5.2节点5.1 需求定义与芯片选型用一个具体项目来收束前面的方法论设计一个电池供电的资产追踪标签目标是用一颗CR2032纽扣电池在1秒广播间隔、0dBm发射功率的条件下持续广播超过一年同时支持手机连接读取实时位置和传感器数据。需求拆解下来对MCU的要求是睡眠电流要足够低目标3μA以下广播功耗要小RAM要能装下协议栈和应用堆栈而且最好支持BLE 5.2的广播扩展这样可以在广播包里一次性塞下更多数据比如经纬度、电池电压、温度手机端不用连接就能读到这些信息。选型时我重点对比过几颗芯片支持BLE 5.2和双核的芯片典型代表有Nordic nRF5340、Dialog DA1469x以及某些国产新势力厂商的新品。综合评估下来nRF5340的软件生态最成熟例子多、文档全双核开发资料也多DA1469x的优势是集成度更高PMU电源管理单元做得好对电池供电非常友好。如果产品对成本敏感国产芯片这两年进步也很大但要注意评估协议栈的成熟度和厂商支持力度——BLE协议栈不是光看芯片参数表就能判断好坏的一定要求厂商提供demo板跑一下实际场景。5.2 工程结构双核怎么分工干活这个项目里我让应用核负责传感器数据读取使用外部I2C温湿度传感器、电池电压ADC采样、以及资产状态判断比如加速度计检测到移动就改变广播数据。协议栈核负责BLE协议栈、广播调度、连接管理、以及电源管理包括射频时序、广播事件唤醒等。工程上分为两个镜像分别维护但用联合构建脚本统一编译。应用核代码的结构大概是// 主循环应用核 int main(void) { app_init(); // 初始化传感器、ADC、共享内存 ble_ipc_init(); // 初始化与协议核的跨核通信 rtc_start_periodic_wakeup(); // 配置RTC定时唤醒 while (1) { uint8_t sensor_data[16]; read_sensor(sensor_data); // 读传感器 float vbat read_battery(); // 读电池电压 update_shared_data(sensor_data, vbat); // 写入共享内存 notify_protocol_core(); // 通知协议核更新广播数据 enter_deep_sleep(); // 进入深度睡眠 } }协议核侧的代码通常由SDK的例子改造重点是配置广播参数// 协议栈核配置广播伪代码 ble_gap_adv_params_t adv_params { .interval_ms 1000, // 广播间隔1秒 .channel_map ALL, // 使用所有三个广播信道 .enable_ext_adv true, // 开启广播扩展 .power 0, // 0dBm发射功率 }; ble_gap_adv_data_set(adv_params, shared_data);这里的shared_data就是两个核共享内存中的广播数据区应用核更新后通过IPC通知协议核协议核在下次广播事件到来时直接使用新数据。整个过程应用核不需要关心射频时序代码清爽很多。5.3 参数调优与功耗实测这个项目的功耗优化有几个关键参数。广播间隔1秒广播间隔下广播电流平均大约5到10μA取决于单个广播包的时长和发射功率。如果调到2秒广播功耗可以几乎减半但对可发现性有影响。资产追踪场景下手机不一定一直靠近标签我选择1秒间隔作为折中。连接间隔与从机延迟当手机建连后连接间隔设到30ms从机延迟设为4意味着从机可以连续跳过4个连接事件不监听非数据交互期间功耗降低非常明显。唤醒时间优化传感器从上电到读数稳定的时间通常有几十毫秒如果让传感器一直上电漏电流是个负担。我用一个GPIO控制传感器的电源只在采样前的10ms内
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门