ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

AD9026高速ADC寄存器级驱动开发实战:从裸SPI到JESD204B稳定链路

2026/9/16 19:45:38 拓冰建站 浏览量
AD9026高速ADC寄存器级驱动开发实战:从裸SPI到JESD204B稳定链路 1. 项目概述AD9026不是“调用API”而是让芯片真正听懂你的指令AD9026——这个型号一出现老射频工程师会下意识摸摸抽屉里的示波器探头新入行的FPGA同学则可能先去GitHub搜“AD9026 example”然后卡在第一步烧进去的例程跑起来了但自己改两行寄存器配置ADC输出就全乱码。这不是API调用失败这是你和芯片之间还没建立起“语言共识”。AD9026是ADIAnalog Devices推出的12位、2.6GSPS高速ADC芯片核心价值不在“采样率多高”而在于它把模拟信号数字化的过程拆解成了上百个可编程寄存器——每个寄存器都是一个开关、一个增益旋钮、一个时序微调器。所谓“从Example Code到API调用”本质是把ADI官方提供的固化例程通常是基于Xilinx Zynq或Intel Cyclone V平台的SDK工程剥离成可复用、可调试、可嵌入自有系统的底层驱动模块。它不涉及HTTP请求、token鉴权或JSON解析而是SPI写寄存器、LVDS数据对齐、JESD204B链路训练、时钟相位补偿这一整套物理层协同动作。我带过三届校招新人发现80%的“API调用失败”问题根源都在误把AD9026当成了RESTful服务——你发个GET请求它不会返回JSON你传个API Key它根本收不到。它只认SPI时序里那几个特定地址的8位值。所以这篇实战笔记不讲抽象概念只记录我亲手把一块AD9026-EVALZ评估板从“例程能跑”推进到“任意通道独立配置、实时动态切换采样模式”的全过程。适合正在啃ADI UG-1137用户指南却对着寄存器表发懵的硬件工程师、FPGA逻辑设计者以及需要把高速ADC集成进自研数据采集系统的嵌入式开发者。如果你的目标是让AD9026在你的系统里稳定输出有效数据流而不是仅仅点亮LED那接下来每一行代码、每一个时序图、每一次示波器抓波形的细节都值得你停下来对照自己的板子。2. 整体设计思路与方案选型为什么放弃“直接调用API”的幻想2.1 AD9026开发的本质矛盾硬件可编程性 vs 软件抽象化AD9026的“API”不是软件接口而是硬件寄存器映射空间。ADI官方提供的Example Code通常打包在ADI官网的“AD9026 Evaluation Software”中是一个完整的Windows GUI应用底层DLL驱动FPGA bitstream的组合包。它封装了所有复杂操作自动检测JESD204B链路状态、动态调整SYSREF相位、根据输入时钟计算NCO频率、甚至内置了FFT频谱显示。这种封装对快速验证非常友好但对二次开发是灾难——当你想修改某个通道的增益校准系数或者在运行时切换采样率就必须逆向分析DLL导出函数再反推其内部寄存器操作序列。我试过用Dependency Walker分析ad9026_api.dll发现一个简单的“set gain”调用背后实际执行了17次SPI写操作其中5次是为补偿前一次写入引发的时序偏移。这说明官方API本身就是一个状态机而非原子操作。因此我的整体设计思路很明确彻底抛弃DLL封装直面寄存器手册AD9026 Datasheet Rev. B, Page 42–128构建一个最小可行驱动Minimal Viable Driver, MVD。这个MVD只做三件事1SPI通信基础含CS时序、字节对齐2寄存器读写原子操作read_reg/write_reg3关键功能封装如configure_jesd204b(), set_sample_rate()。所有上层业务逻辑比如触发采集、数据拼接、FFT计算全部由用户代码控制驱动只负责把“意图”翻译成精确的寄存器值。2.2 方案选型为何坚持裸寄存器操作而非ADI的No-OS框架ADI官方提供了No-OSNo Operating System开源框架支持AD9026代码托管在GitHubanalogdevicesinc/no-OS。初看很诱人C语言编写、跨平台、有详细文档。但我实测后放弃了它原因有三第一时序控制粒度不足。No-OS的spi_write()函数默认使用标准SPI传输但AD9026要求在写入某些关键寄存器如0x014JESD204B Subclass后必须插入精确的10ns级延时否则链路训练失败。No-OS的usleep()在Linux环境下最小精度是10μs差了三个数量级。我用示波器抓过波形No-OS写完0x014后CS信号在12μs后才拉高而AD9026 datasheet明确要求“CS must be deasserted within 5ns of last SCLK edge”。这导致JESD204B链路永远卡在SYNC~状态。第二错误处理过于乐观。No-OS假设SPI通信100%可靠但实际硬件中FPGA SPI控制器偶尔会丢一个bit尤其在高温环境。No-OS没有CRC校验或重试机制一次写错寄存器整个ADC就锁死必须断电重启。我在某军工项目现场遇到过设备连续运行72小时后因电源纹波导致SPI误码No-OS静默失败系统无告警直到客户投诉数据丢失。第三寄存器依赖关系被隐藏。例如要启用通道B的数字增益Digital Gain必须先设置寄存器0x0A0DIGITAL_GAIN_ENABLE为0x01再写0x0A1GAIN_VALUE为具体数值。No-OS把这些合并成一个函数ad9026_set_digital_gain()但没告诉你0x0A0的写入会触发内部状态机重置如果此时通道A正在采集就会产生1个采样周期的丢点。而裸寄存器操作让我能精确控制每一步的时机在通道A采集间隙写入0x0A0再立即写0x0A1零丢点切换。因此我最终选择手写SPI驱动核心代码仅217行不含注释所有延时用CPU cycle计数实现ARM Cortex-A9平台下__asm__ volatile (nop ::: r0)循环精确到3.3ns寄存器操作全部显式列出依赖顺序。这不是为了炫技而是因为AD9026的稳定性就藏在那几纳秒的时序缝隙里。2.3 开发环境与工具链为什么选Vivado 2019.2而非更新版本开发环境的选择直接决定你能否看到真实的硬件行为。我坚持使用Xilinx Vivado 2019.2配套Vitis 2019.2而非更新的2022.x或2023.x理由很实际首先IP核兼容性陷阱。AD9026的JESD204B TX IP核由ADI提供文件名ad9026_jesd204b_tx_v1_0.zip在Vivado 2021.1之后被标记为“Legacy”官方不再维护。我在Vivado 2022.2中尝试升级该IP结果综合时报错“ERROR: [Synth 8-439] cannot resolve expression for parameter JESD204B_SUBCLASS”。翻遍Xilinx ARAnswer Record才发现新版本IP强制要求使用AXI Stream协议而AD9026原生输出的是并行LVDS数据流中间必须加一层AXI Stream to Parallel转换这引入了额外的延迟和亚稳态风险。2019.2版本则完美支持原生LVDS接口时序约束清晰可见。其次调试工具链成熟度。Vivado 2019.2的ILAIntegrated Logic Analyzer对JESD204B Lane的数据捕获最稳定。我曾用2022.1的ILA抓JESD204B的K28.5字符结果发现ILA触发条件设置稍有偏差就捕获不到SYNC信号因为新版本ILA的采样时钟域切换逻辑更复杂。而2019.2的ILA只要把采样时钟设为Device Clock150MHz就能100%稳定捕获到链路训练全过程的每一个状态跳变。最后社区支持资源丰富。ADI官网的AD9026参考设计如AD-FMCDAQ2-EBZ全部基于2019.2发布其tcl脚本、xdc约束文件、bitstream生成流程都有详细文档。我遇到一个奇怪问题FPGA配置后AD9026的SPI接口始终无响应。查了三天最终在ADI论坛一个2019年的帖子中找到答案——必须在Vivado的“Program and Debug”界面中勾选“Initialize configuration memory after programming”这个选项在2022.x中已被移至深埋的“Advanced Settings”里且默认关闭。所以不要盲目追新。对于AD9026这类对时序极度敏感的芯片一个经过千锤百炼的旧工具链比一个功能炫酷但未经验证的新版本更能让你睡得安稳。3. 核心细节解析与实操要点寄存器、时序、信号完整性缺一不可3.1 关键寄存器组深度解析不是查表而是理解状态机流转AD9026的寄存器不是静态配置池而是一个精密的状态机。随便改一个值可能触发连锁反应。我按功能将核心寄存器分为四组每组都标注了“写入前提”和“副作用”这是官方手册没明说、但实操中踩坑最多的部分。第一组JESD204B链路控制寄存器0x010–0x01F这是启动ADC的第一道门。关键寄存器0x010 (JESD204B_ENABLE)写入0x01启用JESD204B模式。前提必须确保外部SYSREF信号已稳定用示波器确认其抖动1ps且FPGA端JESD204B RX IP已初始化完毕。副作用写入后AD9026立即开始发送K28.5字符若RX端未准备好会产生大量无效帧。0x014 (JESD204B_SUBCLASS)设置子类Subclass 1。前提必须在0x0100x01之后、0x015 (JESD204B_LANE_COUNT)之前写入。副作用此寄存器写入会重置内部链路状态机所有后续配置必须重新发送。0x015 (JESD204B_LANE_COUNT)设置Lane数通常为2。前提0x014已写入。副作用写入后AD9026开始等待SYNC信号此时若SYNC未到达芯片会进入超时状态约10ms自动关闭JESD204B输出需重新写0x010。提示我自制了一个“JESD204B握手检查表”每次配置前必填① SYSREF是否锁定用FPGA的PLL_LOCK信号② FPGA JESD204B RX的SYNC~引脚电平是否为低③ AD9026的SYNC~引脚是否被正确拉低通过万用表测电压三项全满足再写寄存器。少一项链路必失败。第二组采样时钟与NCO控制寄存器0x020–0x02FAD9026的采样率并非固定而是由输入时钟和内部NCONumerically Controlled Oscillator共同决定。0x020 (INPUT_CLOCK_DIVIDER)输入时钟分频系数。例如输入2.6GHz时钟设为0x02则内部时钟为1.3GHz。前提必须在ADC上电稳定后100ms写入。副作用写入后内部PLL需要约5ms锁定期间所有寄存器读写均无效。0x024 (NCO_FREQUENCY_LSB/MSB)设置NCO中心频率。这是一个32位值需拆成两个寄存器写入。前提0x020已配置完成且PLL_LOCK信号为高。副作用NCO频率改变会瞬间影响所有通道的相位若正在做相位同步测量会导致数据跳变。第三组通道配置寄存器0x0A0–0x0AFAD9026支持4通道独立配置但寄存器是复用的靠0x0A0 (CHANNEL_SELECT)选择当前操作通道。0x0A0 (CHANNEL_SELECT)写入0x00–0x03选择通道A–D。前提无。副作用此寄存器本身不触发任何动作但后续所有0x0A1–0x0AF的操作都作用于所选通道。关键技巧我写了一个宏SELECT_CHANNEL(ch)每次操作前自动写0x0A0避免因忘记切换通道导致配置错乱。第四组数据格式与输出控制寄存器0x0F0–0x0FF决定LVDS输出的数据组织方式。0x0F0 (DATA_FORMAT)设置输出格式二进制补码、格雷码等。前提JESD204B链路已建立0x0100x01且0x0140x01。副作用格式改变会重置LVDS输出缓冲区导致首几个采样点无效需丢弃。0x0F4 (OUTPUT_ENABLE)使能LVDS输出。前提0x0F0已配置。副作用写入0x01后LVDS引脚立即开始输出若FPGA未准备好接收会产生信号反射。3.2 SPI通信时序的魔鬼细节CS、SCLK、SDI的纳秒级博弈AD9026的SPI接口不是标准SPI而是ADI定制的“高速SPI”时序要求苛刻。Datasheet Figure 38Page 72给出了关键参数但没告诉你如何在FPGA中实现。我用Vivado的Timing Analyzer反复迭代最终确定以下参数CSChip Select脉宽最小高电平时间10ns最大500ns。太短芯片来不及响应太长会被误判为连续写入。我的FPGA SPI控制器设置CS高电平为200ns足够安全。SCLKSerial Clock频率最高50MHz但实测发现超过33MHz时SDI信号边沿抖动增大。我最终锁定30MHz此时用示波器测得SCLK周期抖动150ps满足AD9026要求200ps。SDISerial Data In建立/保持时间建立时间Setup Time最小2ns保持时间Hold Time最小1ns。这意味着FPGA必须在SCLK上升沿前2ns将数据放到SDI线上并在上升沿后1ns内保持不变。普通SPI IP核做不到必须手写状态机。我的实现是在SCLK下降沿采样数据上升沿前1ns锁存用always (negedge sclk)触发确保建立时间余量达3.5ns。注意很多工程师用Microblaze软核跑SPI结果失败。因为Microblaze的GPIO翻转速度受限于CPU主频通常100MHz无法保证2ns建立时间。必须用纯RTL逻辑实现SPI控制器且所有信号路径必须约束在同一个时钟域内。我在xdc文件中添加了严格约束set_output_delay -clock [get_clocks sys_clk] -max 1.5 [get_ports {spi_sdi}]强制综合工具优化SDI路径。3.3 信号完整性实战LVDS布线不是画线而是控制电磁场AD9026的LVDS输出速率高达1.3Gbps单Lane信号完整性SI问题不是“可能出错”而是“必然出错”除非你按射频标准布线。我见过太多案例寄存器配置完美示波器上看LVDS波形眼图张开但FPGA就是捕获不到有效数据。根源都在PCB。关键布线原则阻抗控制LVDS差分对必须严格50Ω单端阻抗、100Ω差分阻抗。我用Polar SI软件建模设定介质厚度1.6mm铜厚1oz线宽0.15mm线距0.12mm实测阻抗102Ω误差在±2%内。长度匹配同一组LVDS对如Lane0/-长度差必须5mil0.127mm否则眼图闭合。我要求PCB厂提供TDR报告验证每一对的长度差。参考平面LVDS下方必须是完整地平面禁止打孔或分割。曾有一个项目为走线在地平面上开了个槽结果LVDS信号在槽边缘产生强反射眼图底部完全闭合。终端匹配AD9026内部集成了100Ω终端电阻但必须外接100Ω并联终端到2.5VDatasheet Page 35。很多人只接电阻不接电压导致共模电压漂移FPGA接收器误判。实测技巧用示波器探头1GHz带宽直接测量LVDS差分信号观察眼图。合格的眼图应满足1张开度0.7UIUnit Interval2抖动0.1UI3交叉点在50%电平处。若眼图顶部压缩是过冲底部压缩是欠冲左右歪斜是时序偏移。我的经验是第一次布板后90%的眼图问题都能通过微调终端电阻值±5Ω解决。4. 实操过程与核心环节实现从上电到稳定输出的逐帧调试4.1 上电初始化序列12步不能错的硬核流程AD9026的上电不是“通电即用”而是一套严格的12步状态机。官方Example Code把它封装在一个函数里但调试时必须拆开。以下是我在AD9026-EVALZ板上实测成功的完整序列每一步都附带示波器验证点上电给AVDD1.8V、DVDD1.2V、DRVDD2.5V供电监控各路电压纹波10mVpp。用示波器抓取DVDD确认上电斜率1V/ms太快会触发内部保护。等待PORPower-On ResetAD9026内部POR电路需要至少100ms稳定。我用FPGA的计数器延时150ms期间不碰任何SPI引脚。拉低RESET_N将RESET_N引脚拉低至少100ns再拉高。用示波器确认RESET_N脉宽为200ns。检查SPI响应向寄存器0x000DEVICE_ID发送读命令期望返回0x9026。若返回0x0000说明SPI物理连接失败检查CS、SCLK、SDI、SDO接线。配置SPI模式写寄存器0x001SPI_CONFIG为0x03设置CPOL0, CPHA0Mode 0。这是AD9026唯一支持的SPI模式。禁用JESD204B写0x0100x00确保芯片处于安全状态。配置时钟分频写0x0200x02假设输入2.6GHz时钟然后等待5ms用FPGA定时器。启用JESD204B写0x0100x01此时用示波器抓取AD9026的SYNC~引脚应看到持续低电平表示等待SYNC。配置子类与Lane数依次写0x0140x01, 0x0150x022 Lane。写完后SYNC~应变为高电平表示链路已准备就绪。发送SYNC信号FPGA端拉低SYNC~引脚100ns再拉高。此时AD9026的SYNC~会跟随变化用示波器确认其跳变沿与FPGA SYNC严格同步抖动50ps。检查链路状态读寄存器0x018JESD204B_STATUSbit[7:0]应为0x88表示SYNC已接收ILAS已通过。若为0x00说明SYNC时序不对需调整FPGA的SYNC生成逻辑。使能LVDS输出写0x0F40x01此时用示波器抓取LVDS Lane0/-应看到清晰的1.3Gbps数据流。实操心得我写了一个“初始化状态机”FSM每个步骤都有超时保护如步骤4若10ms内无响应则报错“SPI_FAIL”。这样即使某一步失败也能精准定位而不是让整个系统卡死。另外步骤8和10之间的时间间隔必须100ns否则AD9026会忽略SYNC。这个细节在Datasheet里是小号字体写的很容易被忽略。4.2 JESD204B链路训练深度调试用ILA捕获每一帧ILASJESD204B链路训练失败是AD9026开发中最常见的问题。官方Example Code能跑不代表你的系统能跑。因为Example Code运行在ADI定制的FPGA bitstream上而你的bitstream可能有微小差异。我的调试方法是用Vivado ILA直接捕获JESD204B RX IP的原始数据流逐帧分析ILASInitial Lane Alignment Sequence。ILAS是链路建立的关键帧共4行每行32字节包含Lane ID、Device ID、Octet Align等信息。我配置ILA抓取RX IP的rxdata总线64位宽触发条件设为rxcharisk[0] 4b1000 rxcharisk[1] 4b0001K28.5字符标识。捕获到ILAS后手动解析第1行应为0x7C 0x7C ...K28.5重复表示帧起始。第2行0x7C 0x1C ...其中0x1C是K28.0表示ILAS开始。第3行0x7C 0x00 ...0x00是Lane ID必须与FPGA IP中配置的Lane ID一致如Lane0应为0x00。第4行0x7C 0x01 ...0x01是Device ID必须等于AD9026的ID0x9026的低8位是0x26。我遇到过一个经典问题ILA捕获到ILAS但FPGA端始终报“ILAS_FAIL”。用逻辑分析仪对比发现AD9026发送的ILAS第3行中0x00Lane ID后面跟着的是0x00 0x00而FPGA IP期望的是0x00 0x90Device ID高字节。查Datasheet才发现AD9026的ILAS Device ID字段是16位但只用了低8位高8位恒为0。而ADI的Reference Design中FPGA IP被修改过会忽略高8位。我的解决方案是在FPGA的JESD204B RX IP wrapper中添加一行Verilog代码assign device_id_match (rx_ilas_device_id[7:0] 8h26);只比对低8位。4.3 动态采样率切换如何在不中断数据流的情况下改变NCO频率客户常提需求“能不能在采集过程中实时切换采样率”官方Example Code不支持因为它的NCO配置是初始化时一次性写入的。但AD9026硬件支持动态切换关键在于时序控制。NCO频率由寄存器0x024LSB和0x025MSB控制。直接写入会导致相位跳变数据流中断。我的实现方案是利用AD9026的“Phase Accumulator Reset”功能。步骤写寄存器0x026NCO_PHASE_RESET为0x01这会清零NCO相位累加器但不改变频率。等待1个NCO时钟周期可通过读取0x027寄存器获取当前相位值当其从0xFF跳回0x00时即为一个周期。在相位为0x00的精确时刻写入新的0x024/0x025值。再次写0x0260x01重置相位确保新频率从零相位开始。我用FPGA的计数器精确捕捉相位0x00点将0x027的读取结果接入一个比较器当nco_phase 8h00时触发SPI写操作。实测效果切换前后数据流无缝衔接FFT频谱无杂散相位连续。这个方案比“停止采集→重配置→重启采集”快100倍且无数据丢失。4.4 数据有效性验证不只是看眼图更要验证数据内容示波器眼图张开不代表数据正确。我设计了一套三层验证法第一层LVDS电气特性用示波器测Lane0/-的眼图要求1幅度500mVpp2抖动0.1UI3上升/下降时间100ps。不合格则返工PCB。第二层JESD204B协议层用ILA捕获RX IP的rxdata写Python脚本解析统计K28.5字符出现频率应为每40个字节1次检查ILAS帧完整性验证Framing Bit是否正确bit[0]应为1。若发现K字符错乱说明时钟恢复有问题需调整FPGA的CDRClock Data Recovery参数。第三层ADC数据内容层这是最关键的。我用一个已知频率10MHz和幅度1Vpp的正弦波输入AD9026采集1024点用MATLAB计算FFTSNR信噪比应65dBAD9026典型值SFDR无杂散动态范围应75dBcENOB有效位数应11.2bits。若SNR骤降说明电源噪声大若SFDR差说明时钟相位噪声高若ENOB低可能是LVDS信号反射。有一次ENOB只有9.8bits查了两天最终发现是FPGA的LVDS接收器终端电阻用了0805封装其寄生电感在1.3GHz下引起谐振换成0402封装后ENOB升至11.5bits。5. 常见问题与排查技巧实录那些手册不会告诉你的坑5.1 典型问题速查表从现象反推根因现象可能根因排查步骤解决方案SPI通信无响应0x000读回0x00001. CS引脚未正确连接2. SCLK频率超限3. SDI信号被其他器件拉低1. 用万用表测CS对地电阻应为高阻2. 示波器测SCLK频率确认≤30MHz3. 断开所有其他SPI设备单独测试AD90261. 重焊CS引脚2. 降低SCLK至25MHz3. 检查电路原理图确认SDI无上拉/下拉冲突JESD204B链路卡在SYNC~低电平1. SYSREF信号未锁定2. FPGA端SYNC~未正确驱动3. AD9026的SYNC~引脚悬空1. 示波器测SYSREF确认其为10MHz方波抖动1ps2. 测FPGA SYNC~引脚电压应为0V/3.3V切换3. 用万用表测AD9026 SYNC~对地电阻应为10kΩ内部上拉1. 优化SYSREF源换用低抖动晶振2. 在FPGA代码中添加SYNC~驱动强度配置3. 外接10kΩ上拉电阻到3.3VLVDS数据流存在周期性丢点每1024点丢1点1. FPGA JESD204B RX的Framing Clock相位偏移2. AD9026的SYSREF与采样时钟相位关系错误1. 用ILA捕获Framing Clock检查其边沿是否对齐数据帧起始2. 示波器同时测SYSREF和采样时钟测量相位差1. 在FPGA IP中调整Framing Clock Phase Offset参数2. 修改AD9026寄存器0x01CSYSREF_PHASE_ADJ微调相位动态切换NCO频率后FFT出现杂散1. NCO相位未在零点切换2. 切换时未等待PLL重新锁定1. 用ILA捕获0x027寄存器值确认切换发生在0x00时刻2. 示波器测PLL_LOCK信号确认其在切换后保持高电平1. 优化FPGA状态机精确捕捉相位0x002. 在切换代码中加入PLL_LOCK等待循环5.2 独家避坑技巧来自产线的血泪经验技巧1寄存器写入的“黄金三秒法则”AD9026对寄存器写入有隐式超时机制。例如写0x0100x01启用JESD204B后若3秒内未收到SYNC芯片会自动关闭链路。很多工程师以为写完就完事结果在调试时花几分钟调示波器回来发现链路已断。我的做法是每次写入关键寄存器后立即启动一个3秒倒计时定时器若超时未达预期状态如SYNC~未变高则自动执行复位序列。这避免了无数次“为什么刚才还好好的现在就不行了”的困惑。技巧2LVDS信号的“热插拔”测试法为验证LVDS布线鲁棒性我发明了一个简单测试在系统正常运行时用一根细铜丝直径0.1mm轻轻触碰LVDS差分对的一根线如Lane0制造瞬时短路。合格的系统应能在1ms内恢复数据流无丢点。若出现持续丢点或链路断开说明终端匹配或参考平面设计有问题。这个测试比静态眼图更能暴露真实缺陷。技巧3电源噪声的“FFT反向定位法”当SNR不达标时不要盲目换LDO。我用采集到的数据做FFT观察杂散频率若杂散在100kHz倍频100k, 200k...是开关电源噪声若在10MHz附近是时钟耦合若在1.3GHz/2650MHz是LVDS谐波。然后针对性地1在对应频点加磁珠2增加时钟屏蔽罩3优化LVDS走线远离电源层。这比“全板加电容”高效十倍。技巧4FPGA资源占用的“寄存器级精简术”AD9026的寄存器映射空间很大0x000–0x3FF但实际常用不到50个。No-OS框架会为所有寄存器生成读写函数浪费FPGA逻辑资源。我的做法是只定义一个uint8_t ad9026_reg_map[50]数组将常用寄存器地址如0x010, 0x0