
AD9361的RSSI是所有用这颗芯片做接收机、频谱监测、信号强度上报的人绕不开的一个功能。我最早接触它的时候想得很简单不就是读个寄存器拿个数值嘛结果真上手之后发现完全不是这么回事——读数不稳定、和功率计对不上、AGC一开数值就“不动了”甚至有时候读出来一直是同一个数。前前后后折腾了好几个晚上翻手册、看驱动源码、搭信号源实测才算把这条链路彻底理清楚。这篇文章就把我配置AD9361 RSSI的完整过程、寄存器细节、校准方法和踩过的坑全部整理出来给准备做接收功率检测、需要把RSSI换算成dBm做上报的工程师一份可以直接上手的参考。内容主要面向三类人正在用AD9361做收发系统、需要RSSI支撑AGC策略或者信号检测的嵌入式工程师读UG-570手册读得头疼、想找人话解释寄存器bit位含义的初学者以及已经能读到RSSI数值、但发现读数跟实际功率对不上、不知道怎么校准的开发者。文章会从RSSI的测量原理讲起再把相关寄存器逐个拆开然后给出一套从初始化到读出有效值的完整配置流程最后重点解决“RSSI code怎么变成精准dBm”这个核心问题。1. RSSI到底在测什么先把测量链路理清楚很多人拿到AD9361的第一反应是RSSI嘛射频芯片自带的功率检测功能读出来就是输入信号强度。这个理解大方向没错但少了一个很关键的中间环节AD9361的RSSI模块并不直接测量天线口的射频功率它测量的是接收链路经过放大、混频、滤波、AGC之后在ADC数字域输出的信号幅度。换句话说RSSI code反映的是“后端数字化之后的信号电平”而不是“前端进来的射频功率”。1.1 数字域的“功率计”是怎么工作的AD9361的接收链路从天线口开始依次经过LNA、混频器、TIA、低通滤波器、PGA最后进入ADC完成模数转换。RSSI检测模块挂在数字基带部分对ADC输出的I/Q样本做幅度统计计算方法本质上是对I2Q2做积分或平均再映射成一个12位的数值。0对应极小信号4095对应接近ADC满量程的信号。理解了这个位置关系就能推出很多结论。第一RSSI读数和前端增益强相关。同样的天线口输入功率LNA增益和PGA增益不同ADC输出的信号幅度就不同RSSI code自然也不同。第二RSSI的响应速度受模拟链路带宽和数字滤波配置影响不是瞬时值。第三RSSI本身是个相对量它只能告诉你“ADC输入口信号比满量程低多少”至于天线口到底是-20dBm还是-40dBm还必须结合当前链路总增益反推。用个生活类比RSSI模块就像一个装在暖气片上的温度计它测量的是暖气片表面的温度。暖气片温度跟房间温度有关系但你要从温度计读数推出房间实际温度就必须知道暖气片的进水温度、阀门开度这些信息。AD9361里的“阀门开度”就是增益配置。1.2 增益状态对RSSI读数影响有多大这部分我实测过差别非常直观。把AD9361配置成手动增益模式固定LNA和PGA增益然后用信号源从-50dBm扫到-10dBm每5dB记录一次RSSI code得到的是一条单调变化的曲线读数跟着输入功率走非常好用。但一旦把AGC打开情况就变了。ADC输出的信号幅度会实时变化RSSI code也会随之波动。在慢速AGC模式下AGC会尽力把信号电平维持在一个目标值附近RSSI code的变化范围被压缩得很小——比如输入功率从-50dBm变到-20dBmRSSI code可能只从2800变到3200变化非常有限。很多刚接触的人在这里会误以为芯片坏了或者配置错了实际上恰恰相反这说明AGC正在努力工作。所以在AGC模式下做功率测量不能只读RSSI code就完事必须同时读取AGC的增益索引gain index或者从寄存器里读出当前生效的RX1/RX2增益值把“链路总增益”和“数字化信号幅度”结合起来才能反推输入功率。这也是很多工程师在RSSI上翻车的第一个大坑。1.3 为什么不能把RSSI当dBm直接读第二个大坑是单位换算。RSSI输出的是一个12位的无符号整数不是浮动的毫瓦数也不是已经换算好的dBm。手册里给出的RSSI实测曲线横轴是输入功率纵轴是RSSI code两者并不是简单的线性关系而是一条在对数域近似线性、但在两端会明显弯曲的曲线。靠近满量程时读数增长变缓靠近底噪时读数会进入一个“平台区”不再随功率下降而明显减小。如果图省事用一个固定公式把所有code都映射到dBm结果误差往往有3-5dB甚至更大。做信号强度指示灯这种对精度要求不高的功能勉强能用但要用来做发射功率控制闭环或者信号覆盖检测这个精度是不够的。后面第4部分会专门讲怎么校准这里先记住一个结论RSSI code到dBm的映射必须基于实测校准不能靠公式硬猜。2. RSSI相关寄存器逐一拆解AD9361的RSSI功能涉及的寄存器不多核心就是0x2A、0x2B、0x2C、0x2D这几个但每个寄存器的bit位都牵涉到测量模式和结果读取方式配置错了很容易出现“读出来数据是错的但不报错”的情况。我从寄存器地图上把这几个寄存器逐个拆开讲带着bit位一起看。2.1 0x2A模式与测量窗口的主控制寄存器寄存器0x2A是RSSI的主控制寄存器主要配置两块内容测量模式和测量窗口。测量模式由bit[5:3]控制常用三种模式。连续模式continuous mode下RSSI模块持续不断地更新测量结果适合观察长时间连续的信号比如调试时监测接收链路是否正常工作或者配合上位机做实时曲线显示。单次模式single mode下,RSSI模块只测量一次结果保持住直到下一次触发适合对突发信号抓拍或者需要和外部时序精确对齐的场景。延迟模式delayed mode则是在触发后等待一个可配置的延迟时间再开始测量适合在收发切换后等模拟链路稳定下来的场景比如TDD系统里刚切到接收状态时前端还有发射残留等几百微秒再测会更干净。测量窗口由bit[2:0]配置决定了RSSI模块对多少时间长度的I/Q样本做积分。这个值可以从1微秒到32微秒不等以2的幂次递增。窗口越长测量结果越平滑抗噪声能力越强但响应速度越慢对短脉冲信号的捕捉能力越差。窗口越短响应越快但单次测量的随机起伏会比较大。实际操作中我的建议是做连续信号监测用8微秒窗口起步做突发信号检测先用短窗口试如果读数抖动再逐渐加长直到抖动在可接受范围内。2.2 0x2BRSSI权重的滤波控制寄存器0x2B的bit[3:0]是RSSI权重值取值范围0到15。这个权重控制的是一阶IIR滤波器的系数作用是对RSSI测量结果做时间上的平滑。权重设为0时RSSI结果不做平均直接输出最新一次测量值权重越大历史值占的比重越高输出曲线越平滑但滞后越明显。很多教程会忽略这个寄存器直接用默认值但如果你发现RSSI数值在相邻两次读取之间跳得很厉害先别急着怀疑硬件看看是不是这里配成了0。我自己调试时碰到过一次信号源输出稳定的正弦波RSSI读数却在几十个code的范围内来回跳排查到最后发现就是weight设成了全通。设为8左右之后读数明显平稳了一个量级。2.3 0x2C和0x2D12位测量结果的拼接方式测量结果是一个12位的数据分散在两个寄存器里。0x2C存放高8位0x2D的bit[3:0]存放低4位。组合方式是把0x2C的值左移4位再与0x2D的低4位按位或。写成C语言就是uint8_t reg2c spi_read(0x2C); uint8_t reg2d spi_read(0x2D); uint16_t rssi_code ((uint16_t)reg2c 4) | (reg2d 0x0F);这里有一个很容易忽略的小坑0x2D的高4位可能是其他状态标志或者保留位读取后必须用0x0F把高位屏蔽掉否则拼接出来的数值会凭空多出一大截。我第一次写读取代码时没做掩码读回来的值一直在4096以上飘白白浪费了不少时间。2.4 三种测量模式的场景选择建议模式选择不是越高级越好而是要看你的应用场景。我做TDD系统时用延迟模式因为收发切换瞬间模拟链路的偏置点还在恢复中立刻测量的话噪声会偏大。做连续监测时用连续模式最省心RSSI模块自己不停更新随时读都是最新值。做协议类应用需要抓特定时隙的信号时用单次模式通过BBP或GPIO触发控制测量时刻确保RSSI对应的是目标时间窗口。如果你还在纠结怎么选我给一个无脑起步配置连续模式 8微秒窗口 weight设为8。这个组合能应付大部分早期调试场景等摸清信号特征之后再针对性调参数。3. 完整配置流程从初始化到读出第一个有效值说完了寄存器接下来进入实操。这里给出一套我从初始化到读到RSSI有效值的完整流程包含寄存器写入值、顺序和代码示例。这个流程在我的板子上验证过你拿到自己的板子后主要根据实际频率和增益配置微调RSSI相关的部分可以直接照抄。3.1 射频前端和增益模式的基础配置配置RSSI之前必须先保证接收链路处于正常工作状态。我习惯按这个顺序来先完成AD9361的完整初始化包括时钟配置、射频端口阻抗匹配、本振频率设定、收发使能然后把接收增益模式设置好最后才动RSSI寄存器。如果你用的是Linux下的IIO驱动初始化通常已经由设备树和驱动完成了你要做的只是确保RX路径是使能的# 查看当前接收通道的使能状态 cat /sys/bus/iio/devices/iio:deviceX/in_voltage0_rx_enable # 如果返回0需要先使能 echo 1 /sys/bus/iio/devices/iio:deviceX/in_voltage0_rx_enable如果你用的是no-OS风格裸机驱动初始化之后要确认RX_ENABLE引脚被拉高并且等待一小段时间让模拟前端稳定下来。我建议至少等几十微秒再做RSSI配置别初始化完立刻就去设RSSI寄存器。3.2 RSSI寄存器配置实例这里给一个具体的配置序列。假设场景是连续模式、8微秒测量窗口、weight设为8、接收增益固定为手动模式。第一步设置测量模式为连续模式窗口为8微秒。0x2A寄存器的bit[5:3]设为000bit[2:0]设为011所以写入值就是0x03spi_write(0x2A, 0x03); // 连续模式8us测量窗口第二步设置权重为8spi_write(0x2B, 0x08); // weight8中等平滑第三步触发测量。在连续模式下其实不需要额外触发RSSI模块会持续更新直接读取结果即可。但为了保险我习惯在连续模式下也先做一次写入触发操作把0x2A重新写一遍确保模块从明确的状态开始工作spi_write(0x2A, 0x03);第四步等待测量窗口结束。8微秒窗口理论上等10微秒就够但实际代码里我一般延时50微秒留足余量delay_us(50);第五步读取结果寄存器uint8_t reg2c spi_read(0x2C); uint8_t reg2d spi_read(0x2D); uint16_t rssi_code ((uint16_t)reg2c 4) | (reg2d 0x0F);如果一切正常这个rssi_code应该是一个0到4095之间的数值。没有信号输入时读数会落在底噪对应的小数值区间灌入信号后读数会随功率增大而单调上升。3.3 通过Linux IIO驱动读取RSSI用Linux IIO驱动的话读取方式更简单不需要手动操作寄存器。驱动已经把RSSI暴露成了标准通道用cat命令就能直接看# 读取原始RSSI值12位code cat /sys/bus/iio/devices/iio:deviceX/in_voltage0_rssi_raw # 如果有校准的话可以读processed值单位通常是dBm具体看驱动实现 cat /sys/bus/iio/devices/iio:deviceX/in_voltage0_rssi但是提醒一句有些驱动版本的rssi通道背后只是做了线性换算并没有做完整的功率校准所以你从sysfs读出来的“dBm”未必准。我的做法是先用raw值对一遍再拿校准表手工换算双保险。3.4 配置顺序踩坑先使能后配置还是先配置后使能这个问题我纠结了很久也试过两种顺序实测下来有一个比较稳妥的经验RSSI寄存器建议在RX链路使能之后再配置。原因在于RSSI模块需要接收来自ADC的I/Q数据流才能正常工作如果RX链路没使能ADC没有数据输出RSSI模块拿不到输入样本即使配置了寄存器读出来的结果也可能是无效值或者恒定的复位值。反过来如果你先配置了RSSI再使能RX在使能瞬间可能会捕捉到链路建立过程中的瞬态噪声导致第一次读数偏大。这个问题在连续模式下影响不大因为RSSI会持续更新但在单次模式下就麻烦了——如果你刚好在链路还没稳定的时候触发了测量那拿到的就是一个被瞬态污染的数据。我的稳定操作顺序是初始化芯片 → 配置射频参数 → 使能RX链路 → 等待链路稳定至少100微秒 → 配置RSSI模式 → 触发/读取。4. 从RSSI Code到dBm校准与换算这是整篇文章最核心的部分。RSSI code本身是一个12位的相对量要变成可用于上报的dBm绝对值必须走校准流程。这个流程不复杂但步骤必须严谨而且很多细节决定了最终精度。4.1 简单线性公式为什么不够用有人总结过一个快速换算公式rssi_dBm 20 * log10(rssi_code / 4095) max_input_dBm。其中max_input_dBm是当前增益配置下ADC满量程对应的输入功率。这个公式在中间一段区域确实能给出一个大概的估计值但问题在于第一RSSI检测器本身的响应曲线不是严格线性的。AD9361的RSSI模块在靠近满量程和靠近底噪的两个区间都有压缩效应直接用对数公式计算这两端误差特别大。第二公式依赖的max_input_dBm是估算值受温度、频率、板级走线损耗影响很大。第三不同增益配置下满量程对应的输入功率不同如果你用AGC这个值本身就是动态变化的。实测数据能直观说明问题在我常用的一个频点上用上述公式算出来的值和信号源实际功率之间中段差1-2dB靠近底噪时能差到6dB以上。这种误差对于功率检测类应用是不可接受的。4.2 建立校准查找表一步一步教你做校准说起来就是一句话用已知功率的信号源灌进去记录RSSI code建立一张code到dBm的映射表。但做的时候有几个环节必须较真。第一步准备设备。你需要一台输出功率准确的射频信号源一个和AD9361工作频率匹配的测试环境以及能实时读取RSSI code的调试手段串口打印、上位机、脚本都行。信号源的准确度直接决定校准精度如果是普通消费级信号源建议先看看它的出厂校准报告。第二步固定增益模式。校准前必须把AD9361的接收增益固定在手动模式不能开AGC。原因前面说过AGC会把RSSI code压缩到一个窄区间校准表没法覆盖大动态范围。固定增益之后记录下当前链路的总增益值后续使用时要保证和校准时一致。第三步设定频率和功率扫描范围。从略高于底噪的功率点开始比如-70dBm到接近满量程的功率点结束比如0dBm步进5dB或者3dB。每设置一个功率点等信号源输出稳定读取20次RSSI code取平均降低随机噪声影响。第四步记录数据。下面是我校准过程中记录的一组示例数据输入功率(dBm)RSSI code(平均)-7062-65110-60185-55305-50490-45730-401010-351310-301610-251900-202170-152420-102650-5286003050注意看从-70到-50这段code变化很快说明信号刚抬出底噪区从-15到0这段code变化明显变缓这就是RSSI检测器在高端的压缩效应。如果用线性公式拟合全段误差会非常明显。第五步实际使用时查表。功率落在两个校准点之间时做线性插值。比如校准表里有(-45dBm, 730)和(-40dBm, 1010)两个点如果实测code是850那对应的功率就是斜率 (1010 - 730) / ((-40) - (-45)) 280 / 5 56 code/dB850比730多了120个code对应120/56 ≈ 2.14dB所以功率 ≈ -45 2.14 ≈ -42.9dBm这个数值和信号源实际设置-43dBm非常接近说明校准表在这段是可靠的。4.3 温度、频点与板级差异的补偿校准表不是一劳永逸的。AD9361的模拟链路增益会随温度和频率漂移具体表现为同一个输入功率在不同温度或者不同频点下RSSI code会有差异。温度变化20度LNA增益漂移1-2dB并不罕见频率偏差100MHz前端匹配网络的插损差异也可能有1dB左右。所以我的建议是第一在目标工作温度范围内做至少高中低三个温度点的校准存成多张表运行时通过温度传感器查最近的那张第二在常用频点各做一次校准频点之间用插值过渡第三如果板子做了改版或者换了物料批次校准数据要重新采集旧表不能直接沿用。这一节再分享一个我自己踩过的坑第一次做RSSI校准时我用的信号源一直连着一段额外的射频线缆但没有扣除线缆插损。结果校准出来的表整体偏大2dB查了好几遍代码都没找到问题最后用功率计实测信号源输出口到AD9361天线口的链路损耗才发现。所以校准前务必确认从信号源到芯片引脚之间所有环节的插损并且把这部分补偿计入参考功率。5. 常见问题速查表症状、原因、对策以下问题全部来自我自己的调试记录和帮朋友排查过的案例专门整理成一张速查表建议大家收藏备用。5.1 读数一直是0或一直满量程症状无论有没有信号输入RSSI code都固定在一个值不随功率变化。可能原因和解决办法在这里分别说明。如果读数固定为0先确认RX链路是否真的使能再看看ADC是否有数据输出。我遇到过一次是数字接口配置错误ADC数据根本没进到基带RSSI模块自然测不到任何东西。如果读数固定接近4095大概率是接收链路饱和了输入功率太大或者增益配得太高先把增益降下来试试。还有一种常见情况是寄存器读地址写错了0x2C和0x2D的地址在部分参考代码里有偏移对照官方寄存器地图再核对一遍。5.2 读数跳动大、不稳定症状功率稳定输入RSSI code却在几十甚至上百个code的范围内来回跳。排查顺序是这样的先检查weight是否设成了00代表不平滑单次测量噪声直接呈现出来设成8左右通常就能缓解。再看测量窗口窗口太短时抗噪能力弱把0x2A的duration从短窗口调到8或16微秒试试。还要确认是否开着快速AGC快速AGC会快速调整增益导致RSSI随增益切换大幅波动做精确测量时建议固定增益或者至少用慢速AGC。5.3 读数和实际功率偏差大症状RSSI读出来的值和功率计或信号源读数对不上误差超过2dB。这种情况几乎是校准问题不要怀疑芯片。第一看校准表覆盖的范围如果输入功率超出校准表覆盖区间查表结果自然不准。第二看工作温度和校准时是否一致温差大时增益漂移会把结果拉偏。第三看频点如果实际工作频率和校准频率偏差较大前端匹配差异会直接体现在RSSI上。第四看链路插损是否被正确扣除线缆、接头、PCB走线损耗全都算进入才准确。5.4 AGC模式下RSSI“不变化”症状输入功率明显变化RSSI code却几乎不动。这不是故障是AGC在正常工作。AGC把信号电平拉回目标值后RSSI反映的是“目标电平附近的小幅波动”而不是绝对输入功率。遇到这种情况要么改成手动增益模式要么同时读取AGC增益索引把增益信息加回来才能还原输入功率。有些驱动会提供“接收信号强度 增益状态”组合查询接口优先用这种接口省得自己拼接。5.5 单次模式下读到了旧数据症状配置了单次测量模式但读出来的结果像是很久以前的值和当前输入信号完全不符。原因是触发之后没有等待测量完成就读取了结果。单次模式下RSSI模块需要等到积分窗口结束才更新结果读取太早拿到的还是上一次的旧值。解决办法是读取前检查测量完成标志位具体位位置在手册中RSSI寄存器章节有标注确定本次测量结束后再读结果。或者简单粗暴一点触发后延时大于窗口时长建议2倍以上再读也能规避这个问题。写在最后的几点经验关于AD9361的RSSI我已经把从原理到配置到校准的完整链路都讲了一遍。最后再补充几点从实际项目里带出来的体会。第一RSSI的12位code是“能干活的原始数据”但它不是最终答案。任何要上报到上层或者做闭环控制的dBm值都应该经过校准表转换别贪图省事用固定公式算。第二配置RSSI的寄存器不算复杂难的其实是对接收链路状态的理解。读RSSI之前先问自己一句现在增益是多少链路稳定了没有如果这两个问题答不上来读数出现任何诡异现象都别奇怪。第三调试RSSI问题的时候手上有一台信号源和一个功率计效率比光看寄存器翻文档高十倍。校准一次花不了半小时省下来的排查时间远远不止这个数。如果你在配置RSSI时遇到了这篇文章没提到的现象或者按我的流程走不通欢迎带着具体的寄存器配置值和实测现象来交流。这种问题往往有一个共同点——现象本身不会骗人骗人的通常是我们对芯片工作状态的理解还不够完整。