1. 从一颗芯片的选型纠结说起:CH592到底卡在什么位置
做低功耗蓝牙产品的硬件工程师,大概都经历过这样的场景:项目立项会上,产品经理拍着桌子说“续航要撑一年,成本压到二十块以内,还要带蓝牙”,然后所有人的目光齐刷刷转向你。这时候你脑子里飞速过一遍市面上的方案——进口的贵,便宜的功耗高,功耗低的开发资料又少得可怜。CH592这类芯片,恰恰就是在这种夹缝里被推到台前的。
CH592是沁恒微电子推出的一款基于RISC-V内核的蓝牙MCU,把BLE 5.3射频、USB控制器、触摸按键检测、LCD驱动、ADC、多路串口这些外设全部塞进了一颗芯片里。它的定位很明确:不是跟那些跑蓝牙协议栈还要外挂一颗主控的方案抢饭碗,而是面向那些“一颗芯片搞定所有事”的紧凑型产品——智能门锁、电子价签、温湿度记录仪、穿戴设备、无线键鼠、车载胎压监测这类对体积和功耗都敏感的场景。
我接触这颗芯片是从一个无线温控器的项目开始的。当时的需求是:CR2032纽扣电池供电,每30秒采集一次温度并通过蓝牙上报,待机功耗要控制在微安级别,整体BOM成本不能超过十五块。评估了一圈,CH592几乎是唯一能在价格和功耗上都满足要求的选项。但真正用起来之后才发现,这颗芯片的“低功耗”不是自动实现的,它需要你对它的电源域、时钟树、射频唤醒机制有足够深的理解,否则实测功耗可能比预期高出十倍不止。
这篇文章就是把我从选型、硬件设计、固件架构到实测调优的完整过程拆开来讲。不管你是刚接触CH592的新手,还是已经在用但功耗降不下来的老手,下面这些内容应该都能帮你少走一些弯路。
2. CH592的集成架构:一颗芯片里到底塞了什么
2.1 RISC-V内核带来的开发体验变化
CH592用的是RISC-V内核,具体是沁恒自研的RISC-V3A系列,主频最高跑到80MHz。很多人一听到RISC-V就觉得“生态不成熟”“工具链难搞”,但实际用下来,沁恒的MounRiver Studio(MRS)已经把GCC工具链、调试器驱动、烧录工具全部打包好了,安装完就能直接编译下载,体验上跟用Keil开发STM32没有本质区别。
RISC-V内核在这颗芯片上的实际意义,主要体现在两个方面。一是中断响应速度,RISC-V的硬件中断嵌套机制让射频中断和定时器中断的响应延迟非常低,这对蓝牙协议栈的时序稳定性很关键。二是代码密度,RISC-V的压缩指令集让同样的功能代码占用更少的Flash空间,CH592的Flash只有448KB,看起来不大,但实际跑一个完整的BLE从机协议栈加上应用逻辑,通常还能剩下一半以上。
不过要注意,RISC-V的调试体验和ARM还是有差异的。比如在MRS里打断点,有时候会出现断点漂移的情况,尤其是开了编译优化之后。我的习惯是在调试阶段把优化等级设为-O0,等功耗调优时再切回-Os,这样能避免很多“代码明明写了但执行顺序不对”的诡异问题。
2.2 射频与基带的集成逻辑
CH592的蓝牙射频是集成在片内的,支持BLE 5.3协议,包括2Mbps高速模式和Long Range模式。射频部分的接收灵敏度在1Mbps下可以做到-95dBm左右,这个指标在同价位芯片里算是相当能打的。
但集成射频带来的一个直接问题是:射频工作时的高峰值电流。CH592在射频发射时的峰值电流大约在8mA到12mA之间(取决于发射功率设置),接收时大约在6mA到8mA。这个电流对于纽扣电池来说是很可观的,所以低功耗设计的核心思路就是——让射频尽可能少地工作,每次工作尽可能短。
这里有个很多人容易忽略的点:蓝牙协议栈的连接间隔(Connection Interval)直接决定了射频的工作频率。如果连接间隔设成100ms,那射频每100ms就要醒来一次进行收发;如果设成1s,那射频的工作占空比就降低了十倍。但连接间隔不能无限拉长,因为很多应用场景对响应速度有要求。我的经验是,对于温湿度采集这类慢速场景,连接间隔设到500ms到1s是完全可接受的;对于无线键鼠这类需要快速响应的场景,连接间隔通常要设在7.5ms到15ms之间,这时候功耗就会明显上升。
2.3 外设资源的分配与复用
CH592的外设资源相当丰富,但引脚数量有限(根据封装不同,从20pin到48pin不等),所以外设的引脚复用规划就变得很重要。我整理了一个常用外设的引脚分配优先级表,供参考:
| 外设 | 优先级 | 典型用途 | 注意事项 |
|---|---|---|---|
| BLE射频 | 最高 | 无线通信 | 天线引脚固定,不可复用 |
| SWD调试 | 高 | 烧录调试 | 量产时可复用为GPIO |
| UART0 | 高 | 日志输出/外设通信 | 建议保留用于调试 |
| ADC | 中 | 电池检测/传感器采集 | 注意参考电压选择 |
| PWM | 中 | 蜂鸣器/LED调光 | 与定时器共享资源 |
| TouchKey | 中 | 触摸按键 | 需要专门的触摸检测电路 |
| USB | 低 | 充电/数据通信 | 仅在需要时启用 |
| LCD驱动 | 低 | 段码屏显示 | 占用较多引脚 |
在实际项目中,我通常会先把射频、调试口、电源管理这几个“不可妥协”的部分占用的引脚锁定,然后再根据产品功能需求分配剩余引脚。如果引脚不够用,优先砍掉LCD驱动和USB,因为这两个外设的替代方案比较多。
3. 低功耗设计的三个命门:电源域、时钟、唤醒源
3.1 电源域的划分与休眠模式选择
CH592的电源管理是低功耗设计的基础。它支持多种低功耗模式,从浅到深依次是:Idle模式、Sleep模式、Deep Sleep模式、Shutdown模式。每种模式下的功耗和唤醒时间差异很大,选错了模式,要么功耗降不下来,要么唤醒太慢导致蓝牙连接断开。
先看一组实测数据(3.3V供电,室温25度,关闭所有无用外设):
| 工作模式 | 典型电流 | 唤醒时间 | 可唤醒源 | 适用场景 |
|---|---|---|---|---|
| 运行模式 | 3.5mA | - | - | 射频收发/数据处理 |
| Idle | 1.2mA | 即时 | 任意中断 | 短时等待 |
| Sleep | 180uA | <10us | 任意中断 | 射频间隔期 |
| Deep Sleep | 2.5uA | <1ms | GPIO/定时器/RTC | 长时间待机 |
| Shutdown | 0.8uA | >5ms | 特定GPIO | 运输/仓储模式 |
从表格可以看出,Deep Sleep和Shutdown之间的功耗差距其实不大(2.5uA vs 0.8uA),但唤醒时间的差距很大(1ms vs 5ms)。所以我的建议是:除非产品需要长期仓储(比如电池已经装好但几个月后才发货),否则没必要用到Shutdown模式,Deep Sleep已经足够覆盖绝大多数低功耗场景。
这里有个关键细节:进入Deep Sleep之前,必须把射频彻底关闭,否则射频模块的残留状态会导致休眠电流偏高。我遇到过好几次休眠电流在50uA左右降不下来的情况,最后查出来都是因为射频没有完全进入Sleep状态。正确的做法是在调用休眠函数之前,先确认BLE协议栈已经进入Idle状态,然后再关闭射频时钟。
3.2 时钟树的配置策略
CH592的时钟源有三个:内部高速RC(HSI)、内部低速RC(LSI)、外部低速晶振(LSE,32.768kHz)。这三个时钟源的选择直接影响到功耗和蓝牙连接的稳定性。
HSI的精度大约在±2%左右,够用但不精确,适合作为系统主时钟。LSI的精度更差,大约在±10%到±30%之间,只能用于对时间精度要求不高的场景,比如LED闪烁。LSE的精度最高,可以达到±20ppm,是蓝牙协议栈维持连接间隔的基准时钟。
很多新手会问:能不能不用外部晶振,省掉两个引脚和一颗晶振的成本?答案是:如果你的应用对蓝牙连接的稳定性要求不高,比如只是偶尔广播一下数据,那可以尝试用内部RC作为蓝牙时钟源。但如果你需要维持稳定的蓝牙连接,尤其是需要支持多个连接或者对连接间隔有严格要求,那外部32.768kHz晶振几乎是必须的。
我实测过用内部RC维持蓝牙连接的情况,在室温下勉强能用,但一旦温度变化超过10度,连接就会开始出现丢包甚至断开。所以对于量产产品,我的建议是老老实实加上外部晶振,这颗晶振的成本不到两毛钱,但能省掉大量的售后问题。
3.3 唤醒源的配置与优先级
CH592支持多种唤醒源:GPIO中断、RTC定时器、蓝牙射频事件、比较器输出等。在低功耗设计中,唤醒源的配置决定了系统能不能“该醒的时候醒,该睡的时候睡”。
我的常规做法是:把RTC定时器作为主唤醒源,用于周期性的传感器采集和蓝牙上报;把GPIO中断作为辅助唤醒源,用于按键触发或外部传感器的事件通知;蓝牙射频事件则交给协议栈自动处理,不需要应用层干预。
这里有个容易踩的坑:多个唤醒源同时使能时,如果中断优先级配置不当,可能会出现“唤醒了但没处理完又睡了”的情况。比如RTC定时器唤醒了系统,但系统还没来得及读取传感器数据,蓝牙射频事件又触发了,这时候如果射频中断优先级更高,就会打断传感器读取过程,导致数据异常。我的解决方案是:在唤醒后的处理流程中,先关闭其他唤醒源,等当前任务处理完毕后再重新使能,避免中断嵌套带来的竞态问题。
4. 从原理图到PCB:硬件设计中的功耗陷阱
4.1 天线匹配网络的调试经验
CH592的射频输出是差分形式,需要通过巴伦电路转换成单端信号再连接到天线。这个匹配网络的设计直接影响到射频的发射效率和接收灵敏度,而射频效率又直接决定了功耗——发射效率越低,为了达到同样的通信距离,就需要更大的发射功率,功耗自然就上去了。
我的经验是:不要完全照搬参考设计上的匹配参数。参考设计通常是在特定的PCB叠层和板材下测出来的,如果你的板子层数、介质厚度、走线宽度跟参考设计不一样,匹配参数就需要重新调试。调试的工具很简单:一台矢量网络分析仪(VNA)就够了。把天线匹配网络看成是一个双端口网络,测出S11参数,目标是让S11在2.4GHz到2.5GHz频段内尽可能低(最好低于-10dB)。
如果没有VNA,也可以用一种更土但有效的办法:在发射功率固定的情况下,逐步调整匹配电容和电感的数值,同时用频谱仪或者蓝牙测试仪观察发射功率和接收灵敏度的变化,找到最优值。这个过程比较耗时,但一旦调好,射频效率能提升3dB到6dB,相当于功耗降低了一半左右。
4.2 电源去耦与纹波控制
CH592对电源纹波比较敏感,尤其是在射频工作的时候。如果电源纹波过大,会导致射频性能下降,进而增加重传次数,最终反映为功耗上升。
我的做法是在CH592的每个电源引脚旁边都放一颗100nF的陶瓷电容,距离引脚不超过2mm。在整体的电源入口处,再放一颗10uF的钽电容或者MLCC作为储能电容。如果板子上还有其他大电流器件(比如电机、LED驱动),一定要用磁珠或者电感把CH592的电源和这些器件隔离开,避免大电流器件工作时产生的电源波动影响到射频。
还有一个容易被忽略的点:电池内阻。纽扣电池的内阻通常在几十欧姆到几百欧姆之间,当射频发射瞬间需要十几毫安的电流时,电池内阻上的压降可能会导致CH592的供电电压瞬间跌落,严重时甚至会导致芯片复位。解决方法是紧挨着电池放一颗大容量的MLCC(比如100uF),让射频发射的瞬间电流主要由这颗电容提供,而不是从电池抽取。
4.3 未使用引脚的处理方式
CH592的很多引脚在具体项目中是用不到的,这些引脚如果处理不当,会成为漏电的通道。我的处理原则是:
- 对于确定不用的GPIO,配置为输出低电平或者输入带上拉,不要悬空。
- 对于有模拟功能的引脚(比如ADC输入),如果不用,配置为数字模式并加上拉或下拉。
- 对于电源引脚,即使不用对应的外设,也要保证电源引脚有正确的去耦。
我见过一个案例:一个客户的产品在实验室里功耗正常,但到了现场功耗就偏高。最后查出来是因为现场环境湿度大,PCB表面有轻微凝露,导致悬空的引脚之间产生了微弱的漏电流。把悬空引脚全部配置为确定电平之后,问题就解决了。所以不要小看这些细节,量产产品必须考虑到各种环境因素。
5. 固件层面的功耗优化:代码怎么写才能省电
5.1 蓝牙协议栈的配置参数调优
CH592的蓝牙协议栈提供了丰富的配置参数,这些参数的设置直接影响到射频的工作占空比。我整理了几个关键参数及其对功耗的影响:
| 参数 | 典型值 | 对功耗的影响 | 调优建议 |
|---|---|---|---|
| 广播间隔 | 100ms | 间隔越长功耗越低 | 非连接状态可设到500ms以上 |
| 连接间隔 | 30ms | 间隔越长功耗越低 | 根据响应速度需求权衡 |
| 从机延迟 | 0 | 延迟越大功耗越低 | 可设到4-6,允许从机跳过若干连接事件 |
| 发射功率 | 0dBm | 功率越低功耗越低 | 近距离场景可降到-10dBm |
| MTU大小 | 23字节 | 越大单次传输效率越高 | 可协商到247字节减少分包 |
其中“从机延迟”(Slave Latency)是最容易被忽略但效果最明显的参数。它的含义是:从机可以跳过多少个连接事件不响应。比如连接间隔是30ms,从机延迟设为9,那么从机实际上每300ms才需要响应一次,其余时间射频可以完全关闭。这对于那些数据更新频率很低的应用(比如温度采集)来说,能大幅降低平均功耗。
但要注意,从机延迟不能设得太大,否则会导致主机发送的数据无法及时送达从机,影响通信的实时性。我的经验是:从机延迟的设置要保证“有效连接间隔”不超过应用层数据更新周期的两倍。比如温度每5秒更新一次,那有效连接间隔可以设到2.5秒左右。
5.2 传感器采集与数据处理的省电写法
固件层面的功耗优化,除了协议栈配置之外,应用代码的写法也很关键。同样的功能,不同的实现方式,功耗可能差好几倍。
第一个原则是“能不用CPU就不用CPU”。CH592的很多外设都可以在CPU休眠的情况下独立工作,比如ADC可以配合DMA自动采集数据并存入内存,RTC可以在设定时间自动唤醒CPU。所以我的做法是:把周期性的传感器采集交给ADC+DMA+RTC这套组合,CPU只在数据准备好之后醒来处理一下,处理完立刻继续睡。
第二个原则是“能少算就少算”。CH592的RISC-V内核在80MHz下运行时电流大约3.5mA,如果降频到8MHz,电流可以降到1mA左右。对于那些不需要高速运算的场景(比如温度数据的滤波和打包),完全可以把主频降下来。我通常会在初始化时把主频设为80MHz用于射频和USB通信,然后在进入低功耗循环之前把主频切到8MHz或者更低。
第三个原则是“能批量处理就批量处理”。比如蓝牙上报数据,不要每采集一个数据点就上报一次,而是攒够一批数据再一次性上报。这样射频只需要唤醒一次,而不是多次。批量处理还能减少协议栈的开销,因为每次连接事件都有固定的协议开销(比如包头、CRC校验等),批量传输能摊薄这些开销。
5.3 中断服务程序的精简与优化
中断服务程序(ISR)是固件中功耗最容易失控的地方。因为ISR执行期间CPU必须全速运行,如果ISR写得过于复杂,执行时间过长,就会导致平均功耗上升。
我的ISR编写原则是:ISR里只做最紧急的事情,比如读取数据寄存器的值、清除中断标志、设置一个软件标志位,然后立刻退出。具体的处理逻辑放到主循环里去执行。这样ISR的执行时间可以控制在几微秒以内,对功耗的影响微乎其微。
举个例子:ADC采集完成中断。我见过有人在ISR里直接做数据滤波和蓝牙打包,结果ISR执行了几百微秒,CPU在这段时间里一直全速运行。正确的做法是:ISR里只把ADC数据读到一个缓冲区,然后设置一个“数据就绪”标志,主循环检测到这个标志后再做滤波和打包。这样ISR的执行时间可以缩短到几微秒,功耗自然就降下来了。
还有一个细节:ISR里不要调用任何可能阻塞的函数,比如延时函数、等待标志位的循环等。这些操作会让CPU在ISR里空转,白白消耗电流。
6. 实测调优:从数据中发现功耗异常
6.1 功耗测量工具与方法
功耗调优的第一步是准确测量。没有准确的测量数据,所有的优化都是盲目的。我常用的测量工具是一台高精度的源表(比如Keysight B2900系列)或者一台带电流测量功能的示波器(配合电流探头)。
测量时要注意几点:一是测量设备的采样率要足够高,因为蓝牙射频工作的瞬间电流变化很快,如果采样率不够,测到的平均电流会偏低。二是测量时要模拟真实的工作场景,比如让蓝牙保持连接、让传感器周期性采集,而不是只测静态电流。三是测量时间要足够长,至少覆盖几个完整的蓝牙连接周期,这样才能看到平均功耗的真实水平。
如果手头没有专业设备,也可以用一种简单的方法:用一个已知阻值的精密电阻串联在电源回路中,用示波器测量电阻两端的电压差,根据欧姆定律算出电流。这种方法的精度取决于电阻的精度和示波器的分辨率,但对于判断功耗的大致水平已经够用了。
6.2 常见功耗异常与排查路径
在实际项目中,我遇到过各种各样的功耗异常。下面整理几个典型案例和排查路径:
案例一:休眠电流偏高(实测50uA,预期2.5uA)
排查路径:首先检查所有GPIO的配置,确认没有悬空引脚。然后检查射频是否完全关闭,可以通过读取射频状态寄存器来确认。最后检查是否有外设时钟没有关闭,比如UART、SPI等外设的时钟如果一直开着,会持续消耗电流。这个案例最终发现是一个未使用的UART时钟没有关闭,关闭后电流降到3uA。
案例二:蓝牙连接后功耗飙升(从2.5uA升到200uA)
排查路径:首先检查连接间隔和从机延迟的配置,确认参数是否合理。然后检查应用层是否有频繁的定时器中断,导致CPU频繁唤醒。最后检查是否有数据频繁上报,导致射频频繁工作。这个案例最终发现是应用层每100ms就上报一次数据,把连接间隔设成了100ms,导致射频一直在工作。把上报周期改成5秒后,功耗降到15uA。
案例三:低温环境下功耗异常(-20度时功耗翻倍)
排查路径:首先检查晶振的低温特性,确认晶振在低温下是否还能正常起振。然后检查电池的低温特性,确认电池内阻是否增大导致供电电压跌落。最后检查芯片的低温漏电流。这个案例最终发现是晶振在低温下起振困难,导致蓝牙连接频繁断开重连,射频反复工作。更换低温特性更好的晶振后问题解决。
6.3 功耗与性能的平衡取舍
低功耗设计从来不是“功耗越低越好”,而是要在功耗、性能、成本之间找到平衡点。我见过一些团队为了追求极致的低功耗,把连接间隔设到几秒钟,结果用户抱怨“按了按键要等好几秒才有反应”。也见过一些团队为了追求响应速度,把连接间隔设到7.5ms,结果电池一周就没电了。
我的经验是:先明确产品的核心使用场景,然后根据场景来确定功耗目标。比如智能门锁的核心场景是“用户按指纹后1秒内开锁”,那连接间隔就不能超过100ms,从机延迟也不能太大。而温湿度记录仪的核心场景是“每分钟记录一次数据”,那连接间隔设到1秒甚至更长都没问题。
在明确场景之后,再通过参数调优来逼近功耗目标。如果调优之后还是达不到目标,那就需要考虑硬件层面的优化,比如换更大容量的电池、优化天线效率、降低发射功率等。总之,低功耗设计是一个系统工程,需要软硬件协同优化,而不是单靠某一方面的调整就能解决的。
7. 一些踩坑之后的个人体会
CH592这颗芯片我用了一年多,从最初的“能跑起来就行”到后来的“每一微安都要抠”,中间踩过的坑确实不少。最大的体会是:低功耗设计不是某一个环节的事情,而是从选型、原理图设计、PCB布局、固件架构到参数调优的全链路工程。任何一个环节的疏忽,都可能让最终的功耗偏离预期。
另外一个很深的感受是:数据比经验更可靠。很多时候我觉得“这样应该没问题”,但实测数据一出来就发现完全不是那么回事。所以我的建议是,在功耗调优的每一个阶段都要有实测数据作为依据,不要凭感觉做判断。
最后分享一个实用的小技巧:在固件里加一个“功耗调试模式”,通过串口输出当前的工作状态、唤醒次数、射频工作时长等信息。这样在调优的时候可以快速定位到哪个环节消耗了最多的功耗,比盲目猜测高效得多。这个调试模式在量产固件里可以通过宏定义关掉,不会影响最终产品的功耗。