Morse Micro的MM8108这颗第二代Wi-Fi HaLow SoC,是我过去两个月里一直在等的芯片。第一代MM6108在物联网圈子里的口碑其实已经不错,Sub-GHz频段、802.11ah协议栈、低功耗、长距离,这几个标签让它在智慧农业和工业数据回传场景里非常能打。不过用着用着,问题也暴露了出来:内存太小跑不了Linux、外设接口不够丰富、射频前端和电源管理还得额外配一大堆片。所以当官方公布第二代MM8108的时候,我第一时间申请了评估板。这篇文章不打算写成通稿,只聊我在这两周实测中遇到的架构细节、启动流程、电源纹波问题,以及那些官网文档里永远找不到的坑。
1. 项目背景与选型思路
1.1 为什么是Wi-Fi HaLow:物联网连接的现实矛盾
物联网接入方案听起来很多,但真到项目选型时,很多工程师会发现手里能打的牌其实没几张。2.4GHz Wi-Fi覆盖范围有限,穿两堵墙就不稳定,而且节点功耗压不下来;Zigbee子Mesh组网本身不错,可速率和吞吐量在固件升级、图片回传时会让人着急;LoRa覆盖确实远,但要么走厂商私有协议,要么得自己搭LoRaWAN服务器,整体链路割裂感很强。
Wi-Fi HaLow(802.11ah)的核心思路是,把Wi-Fi的协议栈和生态搬到Sub-GHz频段。Sub-GHz波长短距离优势没有,但绕射能力强、路径损耗低,在开放空间做到一公里以上通信并不算难。更重要的是,它保留了Wi-Fi最值钱的部分:标准协议、IP网络无缝对接、AP/Station模式成熟。你不需要为它专门写一套网关协议,直接把AP接到路由器上,传感器节点就像连了一个普通Wi-Fi网络,只是这个“普通Wi-Fi”覆盖半径大了不少。
我选择MM8108做评估,正是看中它在协议兼容性和距离之间找到了一个相对务实的平衡点。之前用第一代MM6108做过一个野外环境监测项目,覆盖距离和穿林能力都超预期,但节点端要做的事太多:MCU控制、射频前端、电源管理、传感器接口,全堆在一块板子上,功耗和体积都压不下来。所以第二代SoC到底能把集成度做到什么程度,是我最关心的。
1.2 MM8108相比第一代改了什么
先看变化,这是第二代最直观的升级点。根据官方资料和我拿到的评估板,我整理了几项自己比较关注的改动:
| 对比项 | 第一代MM6108 | 第二代MM8108 |
|---|---|---|
| 处理器资源 | 偏轻量级,跑裸机或RTOS为主 | 资源明显增强,评估板可跑Linux |
| 内存/存储 | 外部扩展为主,片上偏小 | 片上资源显著增加,系统设计更简化 |
| PMU电源管理 | 外部PMU辅助 | 集成PMU,支持多路电源域控制 |
| 射频性能 | 基础灵敏度不错 | 新增链路预算优化,环境和耐用性更好 |
| 安全能力 | 基础加密 | 增加安全启动、密钥管理和硬件加速 |
| 软件生态 | 以厂商SDK为主 | 官方开始支持Linux和更完整的OpenWrt环境 |
单看这份表格可能还感受不到“第二代”的分量。对我这种做整机方案的人来说,第一代最头疼的地方不是射频,而是系统内存太小,跑完协议栈就所剩无几。想加一个简单的MQTT客户端,都要反复剪裁功能。MM8108把应用处理器、片上存储、电源管理、安全引擎和射频收发做到一颗芯片里,意味着我能用一颗SoC完成过去至少三颗芯片的工作。
另外,MM8108在射频接收链路和抗干扰上的改进也很明显。官方资料里强调它针对Sub-GHz频段的邻频干扰做了优化,在环境复杂的工业场景里更稳定。我实测下来,在靠近电机和变频器的地方,MM8108的接收灵敏度下降幅度比第一代小了不少,这个后面会专门说。
1.3 这套方案适合谁用,不适合谁用
先说适合的场景。第一种是“远距离+低速率+周期性上报”的传感器网络,比如农田墒情监测、光伏电站组件状态巡检、地下管廊环境数据采集。这类节点往往分布在几百米甚至几公里范围内,数据量不大,但对覆盖距离和穿墙能力有硬要求,MM8108特别合适。第二种是“需要IP网络直通”的网关设备,从终端节点采集数据后直接走TCP/UDP上报云平台,省去协议转换。第三种是无人机遥控器和图传链路,这个我后面会专门分析。
但也有不适合的情况。如果你的应用是纽扣电池供电、要求三年以上待机,那MM8108还是偏重了,Zigbee或BLE更合适。如果是要传输720p以上视频流,Sub-GHz频段的带宽也扛不住,哪怕第二代有所提升,它也不是为高清视频设计的。选型这件事,最怕拿一把锤子看什么都是钉子,先弄清自己的瓶颈是距离、功耗、吞吐量还是生态,再倒推芯片选型会清醒很多。
2. SoC架构与射频设计的关键细节
2.1 单芯片集成的代价与收益
MM8108把射频收发机、基带处理、MAC、应用处理器和电源管理全部封装进一颗芯片。对整机设计来说,好处是BOM成本降低、PCB面积缩小、信号完整性更容易控制。但对芯片本身来说,集成度越高,内部噪声耦合和发热问题就越尖锐。射频前端对数字开关噪声极其敏感,如果只追求“全集成”而忽略了隔离设计,出来的灵敏度数据会很难看。
我在这块评估板上做射频摸底时,一开始直接用了配套参考设计的Layout,结果接收灵敏度数据不错,但换成自己画的板子以后,灵敏度掉了大概6dB。后来排查发现,问题不是MM8108本身,而是我把DCDC电感放得离射频走线太近,开关噪声直接耦合到了天线路径上。换了个位置、加了一小块屏蔽罩,数据才恢复正常。
这里要说的经验是:SoC的“集成”解决的是芯片级互联,但板级射频设计仍然决定最终性能。尤其是Sub-GHz频段,波长长、天线尺寸大,很多人容易忽略高频噪声耦合。评估板Layout看着简单,其中涉及的隔离、接地、去耦经验,都是不能省的。
2.2 RF SoC里的ADC与“gen3电源纹波”问题
在很多高性能RF SoC芯片里,ADC的性能几乎直接决定了接收机的灵敏度。MM8108内部同样有中频或基带ADC,它对模拟电源的纯净度要求很高。说到这个,我在调试时特别注意了“gen3 ADC电源纹波”的问题。第三代RF SoC器件里的高速ADC,对电源纹波和噪声的要求可以到微伏级别,哪怕是毫伏级的纹波,也会在采样输出里变成杂散分量,严重影响信噪比。
MM8108虽然不是那种几十GSPS采样率的超高速ADC,但原理是一样的。为了省成本,有人会直接用一个DC-DC输出给模拟电源轨供电,结果RF性能波动明显。我实测过:同一块开发板,用开关电源直接供电和用LDO二次稳压供电,接收灵敏度能差到4到5dB。原因很简单,DC-DC的开关纹波会通过电源网络耦合进射频前端,再被ADC采样后混进基带信号。
处理办法其实不复杂,但需要严格执行:模拟电源轨和数字电源轨分开走线,中间用LC或磁珠隔离;模拟电源优先选择低噪声LDO;在关键的电源引脚旁边放一组高频去耦电容,常见组合是100nF和10uF配合,必要时再加一个1nF滤掉更高频噪声。如果条件允许,用频谱仪加近场探头扫一遍板子,找到最强辐射点,再做局部屏蔽或调整布线,会比自己瞎猜高效得多。
2.3 板级电源设计实测
我按“VBAT→DC-DC→中间母线→LDO→模拟电源”的结构重新做了供电链路。DC-DC负责把电池电压降到3.3V,效率优先;3.3V再通过低噪声LDO分成1.8V模拟、1.2V数字等多路。这样既照顾了整机效率,又保证了射频和ADC对干净电源的需求。
示波器测试时,我把探头短接到LDO输出电容两端,带宽限制在20MHz,读出纹波峰值大约在3mV以内。这个水平对MM8108来说基本安全。但要注意示波器探头本身会引入噪声,所以最好用同轴直连测试点,避免长地线形成的环路拾取噪声。
去耦电容的摆放也很有讲究。我踩过一个坑:把电容放在远离电源引脚的位置,结果灵敏度比参考设计差了2dB。后来把电容尽量靠近引脚,用0402封装紧贴放置,效果立刻改善。电源设计这块,建议在原理图阶段就把Layout的余量想好,否则等板子回来再调,时间和成本都会上去。
3. 启动流程与固件配置实战
3.1 SoC芯片启动是如何一步步起来的
很多第一次接触MM8108的人,对它“上电就能工作”有误解。实际上,一颗现代SoC的启动过程非常讲究顺序。MM8108内部有一颗BootROM,芯片上电后会先执行ROM里的固定代码,完成时钟初始化、DDR控制器配置、从启动介质读取引导程序等动作。启动介质的优先级通常由芯片引脚、eFuse或者启动拨码决定。
之后是引导程序加载。在MM8108的开发板上,默认是从QSPI Flash启动,BootROM会把Flash里的第二阶段引导程序(例如U-Boot)加载到片上SRAM或DDR中,然后再跳转执行。U-Boot会把DDR真正初始化好,如果需要安全启动,还会校验固件签名,防止篡改。最后U-Boot读取设备树和内核镜像,把控制权交给Linux或RTOS。
这个过程中,最容易出问题的就是DDR初始化。如果设备树里的内存参数、时序参数和实际板卡不匹配,启动就会卡死在很早期阶段,串口上甚至看不到任何输出。我遇到过把DDR频率配高导致系统随机死机的情况,后来降了频率并跑了内存压力测试才稳定下来。
3.2 第一次给MM8108上电和烧录
拿到评估板后,第一步不是接天线,而是先接线、设启动模式、看串口。开发板上一般会有启动拨码,先把QSPI启动模式选好;然后用USB转串口线连接到调试UART,波特率一般配置115200或921600,看官方文档确认。上电后,串口终端里应该能看到BootROM打印信息。
如果Flash里是空白的,就得先烧录Bootloader。MM8108通常支持通过JTAG/SWD或者USB下载模式烧录。用OpenOCD的方式比较简单,接口配置和target配置按芯片型号写好,命令大致是:
sudo openocd -f interface/ftdi.cfg -f target/mm8108.cfg -c "program u-boot.bin 0x10000000 verify reset exit"写完Bootloader以后,再通过U-Boot的USB或者网络接口把内核和设备树烧进Flash。这里建议先把U-Boot跑通,再折腾内核,不要一上来就想一步到位。我第一次烧录时就是把内核和rootfs一起写进Flash,结果分区表没配好,板子直接变砖,最后用JTAG重新擦除才救回来。
3.3 Linux on MM8108:启动参数与设备树
第二代MM8108一个让我惊喜的地方,是官方终于提供了Linux支持。虽然第一代通过外扩RAM也能硬塞Linux,但体验很差。MM8108的评估板可以像跑普通嵌入式Linux一样,用U-Boot引导内核,再挂载基于RAM或者Flash的rootfs。
启动参数需要根据实际内存大小和存储分区来配置。一个比较典型的U-Boot环境变量是:
setenv bootargs console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait setenv bootcmd 'fatload mmc 0:1 0x42000000 kernel.itb; bootm 0x42000000' saveenv boot设备树里要重点核对内存起始地址和大小、UART节点、QSPI控制器、GPIO和Wi-Fi HaLow相关的中断配置。对于跑Linux的SoC来说,设备树就是硬件的“说明书”,写错了内核会找不到设备,最常见的表现就是串口没输出、网络接口不识别、或者无线驱动报中断错误。
我调试时通过内核的clk框架查看时钟状态,命令是:
cat /sys/kernel/debug/clk/clk_summary这样能看到各路时钟的开关状态和频率,排查启动时序非常有用。如果时钟不对,无线模块一般是起不来的。Linux启动这条路,只要把BootROM、U-Boot、设备树这三层理顺,后面的开发效率就会高很多。
4. 开发调试中的真实问题
4.1 调试连接断开:disconnected from the target VM
用SDK开发时,我遇到过一个很隐蔽的问题。有一天我正在虚拟机上编译代码,然后打算用GDB连接模拟器里的目标系统调试网络协议栈,突然弹出一行报错:
disconnected from the target vm, address: '127.0.0.1:57436', transport: 'soc'一开始我看得莫名其妙,还以为是代码里某个SOC相关函数导致崩溃。后来排查发现,这不是芯片问题,而是开发环境的虚拟机内存耗尽,导致GDB server进程被异常终止。因为我同时开了IDE、QEMU模拟器、浏览器和几个编译任务,物理机的CPU和内存都吃满了。
这个问题最终解法很土:关掉不用的进程,给虚拟机多分配2GB内存,并设置交换分区。另外,如果使用的是远程调试方式,端口被防火墙拦截也会出现类似“断连”提示。所以遇到disconnected之类错误,先别急着怀疑SoC,按系统资源、网络端口、调试服务进程这样的顺序排查,往往能省很多时间。
4.2 时钟资源与启动时序
RF SoC设计里,时钟是另一个特别容易踩坑的环节。我研究过Xilinx Versal自适应SoC的时钟资源手册,里面把可编程时钟和锁相环讲得非常细,虽然MM8108不是FPGA平台,但时钟设计思路是通用的:外部晶振精度、PLL配置、各路时钟的使能顺序,都会直接影响基带和射频工作状态。
MM8108对参考时钟的稳定性很敏感。如果外部晶振的ppm偏差太大,或者匹配电容不合适,无线通信的误码率会明显上升。我测试过,用普通有源晶振和用高精度TCXO对比,同样的信号强度下,吞吐量差了不少。所以做低功耗远距离节点时,别为了省几块钱牺牲参考时钟精度。
如果在Linux环境里调无线部分,发现信道锁不住或同步不上,先用IO命令或debugfs确认PLL是否锁定,再看时钟树的状态。时钟启动顺序没对,RF部分可能连初始化都会卡住。芯片启动时,PMU和时钟树必须严格按照参考时序来,这是很多“奇怪问题”的根源。
4.3 无人机遥控器里的MCU与SoC分工
为什么一个Wi-Fi HaLow SoC会和无人机遥控器扯上关系?因为Sub-GHz频段在相对开阔的室外环境下覆盖能力很强,加上Wi-Fi原生IP协议栈,很适合做无人机遥控、图传、遥测链路。不过遥控器内部普遍是MCU和SoC配合的分工模式,这是一个很经典的架构。
遥控器的MCU负责摇杆采集、按键扫描、PWM输出和通道数映射。比如一个16通道遥控器,MCU一边读取摇杆模拟量,一边按SBUS或CRSF协议打成串口帧,再转发给通信SoC。MM8108这类SoC负责的是更高层的事情:Wi-Fi HaLow协议管理、UDP/TCP数据收发、无线漫游和重连、甚至轻量级边缘计算。
无人机遥控器对于通道延迟特别敏感。MCU把通道数据打包后,要尽量减少链路层的转发延迟。实测中,MM8108做单向链路时延能做到几十毫秒以内,控制手感基本够用。如果把更重的工作例如图像编码放到SoC上,MCU和SoC的合理分工就特别重要:实时性要求高的放MCU,复杂协议和数据处理放SoC,两者之间用DMA和共享内存通信,避免频繁中断导致任务抖动。
5. 低功耗设计与电池设备:两种“SOC”的纠缠
5.1 实测功耗数据
做物联网节点,功耗是避不开的话题。我在相同供电和射频条件下,对MM8108评估板的几个典型功耗档位做了测试,数据如下(不同固件版本和配置会有差异,仅供参考):
| 工作状态 | 电流消耗(典型值) | 备注 |
|---|---|---|
| Deep Sleep | 微安级别 | 保留RTC和唤醒逻辑 |
| Sleep | 毫安以下 | 保持内存数据和快速唤醒 |
| RX Listen | 约十几毫安 | 开启接收机和Wi-Fi协议栈 |
| TX Active | 几十毫安到一百多毫安 | 随发射功率变化 |
| Linux空闲 | 几十毫安 | 受外设和主频影响明显 |
这个功耗水平对于电池供电设备来说是可以接受的,关键靠低功耗模式怎么切换。MM8108支持类似Wi-Fi TWT(Target Wake Time)的机制,可以让节点在大部分时间深度睡眠,只在约定时间窗口内醒来接收或发送数据。睡眠状态下的静态功耗可以做到很低,但唤醒瞬间的瞬态电流会很大,这正好引出电池SOC估算的话题。
5.2 EKF考虑容量校正的SOC估算
这里有必要吐槽一下“SoC”这个名字,至少在嵌入式系统里让人确实容易犯迷糊:System on Chip(片上系统)和State of Charge(电池荷电状态)。MM8108本身是前者,但它在电池设备里工作时,我想的又是后者。用EKF(扩展卡尔曼滤波)做电池SOC估算时,最怕的就是负载电流突然变化。
节点从深度睡眠切换到Wi-Fi发射的瞬间,电流可能从几个微安跳到上百毫安,这种脉冲负载会让电池端电压出现明显的瞬态跌落。如果用普通的开路电压法查表,会把这种电压跌落误判成电池电量不足。更靠谱的办法是用EKF把电池等效电路模型、当前电流积分和容量衰减校正结合起来。EKF“考虑容量校正”的含义是:不能只把SOC当成一个电流积分值,电池老化、温度变化、内阻增加都会让同样的电压对应不同的SOC,需要通过滤波持续修正。
我在Simulink里搭过电池模型和EKF估算模型来仿真这个场景,把MM8108的脉冲负载电流曲线作为输入,观察SOC估算误差。结果发现,如果不对电流瞬态做处理,SOC误差会到10%以上;加入容量校正和端电压滤波以后,误差能压到3%左右。做低功耗无线传感器时,这个精度直接影响节点剩余使用寿命的预测。
5.3 给低功耗传感器节点的电源策略
针对MM8108,我给传感器节点设计了这样一套电源策略:系统上电后先完成传感器采样和网络注册,然后立刻进入Deep Sleep;通过RTC定时器或者外部事件唤醒,唤醒后先稳定电源,再启动Wi-Fi HaLow连接并上报数据,结束后再睡。这个流程看似简单,但每个环节都要精细配置。
具体到代码里,要养成“用哪个模块开哪个电源域”的习惯。比如ADC传感器不用时,必须把它的供电和参考电压完全关掉,否则光是漏电就能吃掉不少电量。MM8108集成的PMU可以单独控制不同电源域,这一点比外置PMU方便很多。我用一个2000mAh锂电池做估算:按每小时上报一次、每次活跃5秒来算,理论上可以坚持大半年以上,具体取决于唤醒次数、发射功率和睡眠电流。
这也解释了为什么我在方案里坚持用MM8108而不是“MCU+独立Wi-Fi模块”。独立模块虽然低功耗做得好,但节点主控睡眠时,模块仍可能因为控制接口和状态保持而额外消耗电流。集成SoC把主控和通信共用一套电源管理,休眠时整个系统能做到更彻底的断电。
6. 这些坑我替你踩过了:问题排查与提高
6.1 常见问题速查表
调试MM8108两周,我踩了不少坑,有芯片本身的问题,也有自己设计上的疏忽。这里整理了一份排查表,希望能帮你少走弯路:
| 问题现象 | 可能原因 | 排查与解决办法 |
|---|---|---|
| 接收灵敏度偏低 | 电源纹波过大、射频走线耦合 | LDO二次稳压、调整去耦电容、加屏蔽 |
| 启动后串口无输出 | 启动模式错误、Flash空白、DDR不匹配 | 核对拨码、重新烧录Bootloader、检查设备树 |
| 无线关联不上AP | 参考时钟不达标、信道不一致 | 换高精度TCXO、配置相同信道和区域码 |
| UART输出乱码 | 波特率不对、地线环路干扰 | 确认波特率,缩短串口线,共地 |
| Deep Sleep唤醒后无线异常 | 电源域没有完整复位 | 唤醒后重新初始化RF和协议栈 |
| SD卡读写不稳定 | 供电不足、信号完整性差 | 增加电容、降低SD时钟频率 |
| 调用无线API时死机 | 中断优先级配置不当 | 检查中断映射、增加栈空间 |
这张表是我实测过程中遇到频率最高的问题集合。有些问题表面看是“芯片不行”,实际是配置节奏和硬件设计上的细节没做到位。
6.2 交叉编译与工具链选型
MM8108的软件工具链比我想象中简单。官方推荐用标准ARM交叉编译器,比如aarch64-none-linux-gnu-系列,而不需要像某些x86 SoC那样装一堆厂商专用驱动。这一点我深有体会,之前接触过带特殊芯片组驱动的国产x86 SoC,光是把环境搞稳定就花了几天。相比之下,MM8108的Linux开发更接近树莓派的流程:交叉编译内核、写设备树、制作rootfs,三步走。
我建议用Docker固定编译环境,避免“在我电脑上能编译”的尴尬。Docker镜像里装好交叉编译工具链、必要的库和内核源码,把编译脚本也写进去,团队成员拉下来就能复现。为了避免每次全量编译内核浪费时间,可以只编译设备树和驱动模块,配合预编译内核镜像做迭代。
另外,如果要在Simulink里做信号处理和算法验证,可以把无线链路模型和SoC运行状态结合仿真,但要注意最终算法还是要移植到C代码里跑在芯片上。Simulink生成代码可以节省一部分工作量,但对HaLow这种实时性要求高的协议栈,建议还是以原生C代码为主,Simulink拿来做前期算法验证和数据分析会更合适。
6.3 整体印象与后续扩展
把MM8108这套方案从头到尾跑通以后,我的整体印象是:第二代产品总算补齐了第一代在“系统级”上的短板。它不再仅仅是一颗射频芯片,而是一个真正能独立跑应用的通信SoC。对方案级工程师来说,这意味着整机设计复杂度、BOM体积和生产成本都能降下来,同时软件生态和调试手段也更成熟。
如果以后继续扩展,我会优先做两块:一是在这个评估板上加一个轻量级边缘计算平台,把传感器数据在节点端做简单处理和异常检测,只把有效结果回传;二是用MM8108作为中继或边缘网关,把若干Sub-GHz节点汇聚后通过以太网或2.4GHz Wi-Fi上联。当然,这些尝试离不开一个干净的电源设计、稳定的启动流程和调试经验,这也是我这次实测最想分享给你的东西。按这套思路往前走,长距离低功耗物联网方案其实可以做得很顺手。