ST7102电源芯片驱动移植RK3568平台全解析
上个月刚把一块老板卡上的 ST7102 驱动从旧平台移植到 RK3568 新平台这个过程几乎把所有常用的驱动调试手段都过了一遍。ST7102 是一颗 I2C 接口的多路电源管理芯片在板卡上负责核心供电和上电时序。刚开始我以为把代码搬过去改改编译就能过结果实际跑起来才发现驱动移植的核心不在于代码能不能编译而在于芯片能不能在新平台上按预期工作。这篇文章是我这次移植全过程的复盘包括设备树、regmap、电压表设计、中断处理以及从寄存器检测到波形抓取的完整调试链路希望能给正在做电源类驱动移植的朋友一个参考。如果你正要做类似的 I2C 控制芯片适配这篇文章应该能帮你少走不少弯路。我会尽量写细一点把当时为什么这么想、为什么这么改都交代清楚而不是只丢一段能跑通的代码出来。1. 项目背景ST7102 是干什么的为什么非移不可1.1 先弄清芯片在板卡上管什么ST7102 这个型号的芯片在电源管理芯片里算是很常见的定位——封装不大引脚不多通过 I2C 总线配置寄存器控制两到三路的 DC-DC 或 LDO 输出。它一般不会直接给 CPU 大电流供电更多是用来做外围电路的电源DDR 的 VTT、PHY 的 AVDD、或者模组的 IO 电平顺便管管上电时序。老板卡上ST7102 负责三路输出VOUT1 给 DDR 参考电压VOUT2 给以太网 PHY 供电VOUT3 给 SDIO 接口电平转换。三路输出之间还有严格的时序要求要求 VOUT1 先起来、延迟 2ms 后 VOUT2 再起、再延迟 1ms 后 VOUT3 跟上不然芯片端就会锁存或者电平不稳。之所以新平台也要保留这颗芯片是因为它在产线上跑了很多年那套电压配置和时序已经验证得很稳定直接沿用是最稳妥的方案。提示移植前一定要先读一遍原理图和芯片手册里的上电时序图power-up sequence。很多驱动问题根本不是软件问题是时序没对上导致芯片根本没进入正常工作状态。1.2 新旧平台的差异是移植的主要工作量旧平台上跑的是 Linux 3.14 内核驱动写法还是早期风格手动构造 i2c_msg用 i2c_transfer() 一条条发设备通过板级文件里的 i2c_board_info 挂载没有设备树。新平台换成了 RK3568 Linux 5.10驱动模型全面转向 device tree probe 流程I2C 子系统的 API 也换了一轮。具体差在哪我整理成了一张表格项目旧平台Linux 3.14新平台Linux 5.10 / RK3568设备挂载方式i2c_board_info在板级 C 文件里注册device tree 节点自动生成 i2c_client通信接口手动 i2c_transfer i2c_msgregmap API 封装读写寄存器更直观中断请求request_irqdevm_request_threaded_irq / devicetree interrupt 属性电源依赖regulator_get 手动管理设备树 fixed-regulator supply 属性调试接口printk 老一套dynamic_debug / tracefs这几个差异几乎每一个都在我这次移植中踩了坑。后面我会逐个展开尤其是 regmap 和设备树部分稍不注意就会踩进看起来很诡异的坑里。1.3 移植前把调试工具备齐驱动移植不是一上来就写代码。在动代码之前我先把调试环境备齐了万用表、示波器、逻辑分析仪这几样硬件工具是必须的软件侧准备了一根 USB 转串口线配合串口调试助手看内核日志板子支持有线网络的话还可以通过网口把日志转发出来或者用网络调试助手做远程串口透传这样调试的时候不用一直守在开发板旁边。这里多提一句USB 转串口在电源芯片调试时有特殊价值内核崩溃、休眠唤醒这类场景网络和 USB 都可能断开只有串口能稳定输出最后一段日志。我见过不少同事嫌串口线麻烦全凭网络调试结果板子一进 suspend 就两眼一抹黑完全不记得最后发生了什么。2. 驱动代码移植从老 API 到新框架2.1 全面转向 regmap 的底气老驱动里到处是这种代码struct i2c_msg msg[2]; msg[0].addr client-addr; msg[0].flags 0; msg[0].len 1; msg[0].buf reg_addr; msg[1].addr client-addr; msg[1].flags I2C_M_RD; msg[1].len 1; msg[1].buf reg_val; i2c_transfer(client-adapter, msg, 2);每次读写寄存器都要手动构造 i2c_msg代码又长又容易错。在新内核里同样的功能用 regmap 三行搞定regmap devm_regmap_init_i2c(client, st7102_regmap_config); regmap_write(regmap, ST7102_REG_VOUT1, 0x28); regmap_read(regmap, ST7102_REG_DEV_ID, val);regmap 是内核专门为这一类寄存器式设备设计的抽象层它把 I2C、SPI、MMIO 等各种总线封装成了统一接口驱动代码里不用关心底层总线是啥。这不是为了写起来省事而是为了少犯错regmap 内部会帮你处理多字节传输的字节序、缓存、时钟访问互斥这些都是手动写 i2c_msg 时最容易翻车的地方。2.2 老驱动里几个必要改写的接口内核版本跳了 6 个大版本好多老 API 已经找不到了。我在移植过程中遇到最典型的几个第一个是i2c_new_device。老驱动在板级文件里用这个函数创建设备新内核改成了i2c_new_client_device参数和注册流程都有变化。如果你是在设备树模式下做适配其实根本不用手动创建——设备树节点会被of_i2c_register_devices()自动解析成 i2c_client然后触发驱动匹配。这里我第一次移植时走了弯路想着把老代码里的i2c_new_device照搬过来结果设备树节点和手动创建的 client 冲突probe 被调用两次寄存器被重复初始化。第二个是中断注册。老代码用的是request_irq新平台我改成了devm_request_threaded_irq。电源芯片的中断处理里经常要读状态寄存器、清标志位这些操作如果放在硬中断上下文里会很危险——I2C 读写在硬中断里可能睡搞不好就 panic。线程化中断的作用就是把中断处理放到内核线程里允许在 handler 里做 I2C 访问这是电源管理芯片驱动的标准姿势。第三个是电源依赖的管理方式。旧代码里用regulator_get拿一个固定的 regulator新平台上这些依赖可以通过设备树里的vcc-supply属性描述内核会在该 supply 可用之前自动延迟 probe。这个机制很方便但也带来了一个常见问题如果 supply 节点没配对probe 就会一直返回-EPROBE_DEFER看起来像驱动没加载实际是在等一个永远等不到的资源。2.3 寄存器映射和电压表的建立ST7102 的寄存器不多核心就十几条但每一条的含义都要对着手册确认。我这次用到的关键寄存器整理如下具体偏移以读者手里的芯片手册为准不同批次可能不一样寄存器偏移作用备注DEV_ID0x10器件 ID用来确认 I2C 通信是否正常CTRL0x11全局控制软复位、使能位VOUT10x20VOUT1 输出电压配置0.8V~3.6V步进 50mVVOUT20x21VOUT2 输出电压配置同上VOUT30x22VOUT3 输出电压配置同上SEQ_CFG0x30上电时序配置每路延迟时间INT_FLAG0x40中断标志写 1 清除PROTECT0x50保护配置过流、过温阈值这里有个很容易被忽略的点电压配置寄存器和实际输出电压不是线性对应而是二进制权重的编码。比如 VOUT1 要配 1.8V手册给的计算公式是code (Vout - 0.8) / 0.05算出十进制 20写进寄存器就是 0x14。如果不看手册想当然地写regmap_write(regmap, 0x20, 0x1A)实际输出就是 2.1VDDR 端立刻就可能出问题。注意电源芯片的输出电压配置务必按手册给的公式计算后写入。建议在驱动里维护一张电压表{output_uv, reg_code}把平台上可能用到的电压档位都列出来用查表的方式映射避免每次都在代码里做浮点运算也方便出问题时快速核对。2.4 设备树匹配compatible 不是随便写的设备树节点的 compatible 字符串就是驱动和设备匹配的暗号。旧平台上老驱动没有这个概念所以新平台上必须补上static const struct of_device_id st7102_of_match[] { { .compatible st,st7102 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, st7102_of_match); static struct i2c_driver st7102_driver { .probe st7102_probe, .id_table st7102_id_table, .driver { .name st7102, .of_match_table st7102_of_match, }, };st7102_of_match里的compatible名称必须和设备树节点完全一致大小写、连字符都不能差。如果驱动加载后发现 probe 没被调用先用grep st7102 /sys/bus/i2c/drivers/或者dmesg | grep st7102看看匹配到了没有。这一步我浪费过小半天后来发现只是设备树里把 compatible 写成了st,st7102驱动里写的却是st7102少了前缀死活匹配不上。3. 实操流程设备树、probe 和编译加载3.1 设备树节点的写法新平台上设备树是驱动和硬件之间的接线图。ST7102 的设备树节点我放在了 I2C4 总线上i2c4 { status okay; clock-frequency 400000; st7102: pmic4e { compatible st,st7102; reg 0x4e; interrupt-parent gpio3; interrupts RK_PA5 IRQ_TYPE_LEVEL_LOW; vout1-microvolt 1800000; vout2-microvolt 3300000; vout3-microvolt 1800000; vcc-supply vcc5v0_sys; status okay; }; };这里的细节比较多逐个说。reg 0x4e是芯片的 I2C 地址这个地址由芯片地址脚的电平决定原理图上是多少就填多少不是随手写的。interrupt-parent和interrupts指定了芯片的 INT 引脚接到哪个 GPIO 和触发方式。vout1-microvolt这类属性是我给驱动自定义的加载后从设备树中读取就可以灵活适配不同板卡上相同芯片的不同电压需求。这种硬件参数走设备树的设计在上游 Linux 里很常见也是移植驱动的核心思想之一——代码只写逻辑具体参数交给设备树去配。3.2 probe 流程的关键顺序最核心的 probe 函数是我这次移植中改动最大的部分。新内核里probe 相当于驱动初始化的总指挥顺序基本是固定的。我的执行顺序如下static int st7102_probe(struct i2c_client *client) { struct st7102_dev *dev; struct device *devm client-dev; unsigned int val; int ret; dev devm_kzalloc(devm, sizeof(*dev), GFP_KERNEL); dev-client client; /* 1. 初始化 regmap */ dev-regmap devm_regmap_init_i2c(client, st7102_regmap_config); if (IS_ERR(dev-regmap)) return PTR_ERR(dev-regmap); /* 2. 先读设备 ID确认通信正常 */ ret regmap_read(dev-regmap, ST7102_REG_DEV_ID, val); if (ret) { dev_err(devm, failed to read device id: %d\n, ret); return ret; } dev_info(devm, ST7102 id 0x%02x\n, val); /* 3. 读取设备树参数配置输出电压 */ ret device_property_read_u32(devm, vout1-microvolt, dev-vout1); if (ret) dev-vout1 1800000; /* 默认 1.8V */ /* 4. 查电压表写入寄存器 */ ret st7102_set_voltage(dev, ST7102_REG_VOUT1, dev-vout1); if (ret) dev_warn(devm, set vout1 failed\n); /* 5. 申请中断 */ ret devm_request_threaded_irq(devm, client-irq, NULL, st7102_irq_handler, IRQF_ONESHOT, st7102, dev); if (ret) dev_warn(devm, request irq failed: %d\n, ret); /* 6. 注册 regulator 接口 */ ret st7102_register_regulator(dev); if (ret) return ret; dev_info(devm, ST7102 probe success\n); return 0; }顺序为什么重要第一regmap 必须最先初始化它是后面所有寄存器操作的基础。第二第一次读设备 ID 必须在配置电压之前这一步相当于握手——如果 ID 读不到说明 I2C 地址、总线、硬件上电有问题这时候继续往下配置电压纯属白费力气还可能在硬件没准备好的状态下写入错误数据。第三中断注册放在最后避免中断回调里访问一个还没初始化的寄存器缓存。还有个很容易踩的坑client-irq在设备树里如果没配interrupt-parent这个值就是 0直接devm_request_threaded_irq会返回 -EINVAL。我在这次移植中就遇到过gpio 编号写错了导致中断号无效最终排查到设备树节点的interrupts属性。调试时可以先用cat /proc/interrupts看看中断有没有注册上。3.3 电压配置的计算与实测验证这里把电压配置这个环节单独拎出来讲因为它最直观也最容易出错。ST7102 的输出电压编码公式我从手册上抄下来是Vout(mV) 800 code * 50反过来给定目标电压求 codecode (Vout_mV - 800) / 50比如配 3.3Vcode (3300 - 800) / 50 50 0x32我在驱动里写了一个查表函数把常用的几档电压预先算好static const struct { int uv; u8 code; } st7102_volt_table[] { { 800000, 0x00 }, { 1000000, 0x04 }, { 1200000, 0x08 }, { 1500000, 0x0e }, { 1800000, 0x14 }, { 2500000, 0x22 }, { 3300000, 0x32 }, { 3600000, 0x38 }, }; static int st7102_set_voltage(struct st7102_dev *dev, u8 reg, int uv) { int i; u8 code 0; for (i 0; i ARRAY_SIZE(st7102_volt_table); i) { if (st7102_volt_table[i].uv uv) { code st7102_volt_table[i].code; break; } } if (i ARRAY_SIZE(st7102_volt_table)) return -EINVAL; return regmap_write(dev-regmap, reg, code); }写完之后务必用万用表实测一下输出引脚对地电压是不是和目标一致。这一步不能省寄存器写对不代表硬件电路一定对——比如原理图上两个邻近引脚画反、电感选型不对、滤波电容容量不够都可能导致实测电压偏离。我这次测 VOUT2 时发现实际是 3.2V比设置值 3.3V 低了一点点起初以为是寄存器没写对用万用表查了半天最后发现是芯片手册上本身的调整率就有 ±2% 的容差这个值完全正常。3.4 编译成模块并确认挂载驱动我按内核模块方式编译。在源码目录里添加对应的 Kconfig 和 Makefile 条目obj-$(CONFIG_PMIC_ST7102) st7102.o然后make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- menuconfig # 进入 Device Drivers - Power Supply Class - ST7102 PMIC support启用编译 make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- modules make ARCHarm64 CROSS_COMPILEaarch64-linux-gnu- INSTALL_MOD_PATH/path/to/rootfs modules_install把生成的 st7102.ko 拷贝到目标板的文件系统手动加载时先modprobe st7102然后立刻看dmesg输出。加载成功的前提下能在 /sys/bus/i2c/devices/4-004e/ 下看到结构目录里面除了 driver 符号链接之外驱动通过 sysfs 导出的属性也会出现在这里。可以顺便验证一下cat /sys/bus/i2c/drivers/st7102/4-004e/name能输出 st7102 就说明匹配正常了。提示如果驱动编进内核而不是模块probe 的时机在系统启动早期此时 I2C 控制器可能还没初始化容易遇到 -EPROBE_DEFER。这类问题别急着改驱动确认一下设备树里的 I2C 控制器 status 是否 okay、时序是否就绪再用deferred_probe_timeout这类内核参数辅助排查。4. 调试实录从探总线到看波形4.1 探总线i2cdetect 是第一步新板子第一次上电软件驱动我还没加载之前第一件事就是用 i2c-tools 探一遍总线确认芯片在不在、地址是多少rootrk3568:~# i2cdetect -y 4 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- 4e -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --我在 I2C4 总线上看到了 0x4e 地址的设备说明芯片的地址就是 0x4eI2C 物理链路也通了。这一步如果看不到地址问题大概率在硬件芯片没上电、I2C 上拉电阻没焊、地址脚电平不对这三项排查完还看不到就得用示波器看波形了。提示i2cdetect 输出里的 UU 表示地址被某个驱动占用了可能驱动已经加载成功。如果你期望看到地址却看到 UU说明驱动 probe 虽然报错但 i2c 核心仍认为设备被绑定这时优先查驱动日志而不是硬件。4.2 寄存器读写i2cget/i2cset 的用法i2cdetect 确认设备在线后下一步就是寄存器级验证。先读设备 IDrootrk3568:~# i2cget -y 4 0x4e 0x10 0x71返回 0x71和芯片手册上的 ID 一致握手完成。然后写一个电压配置再读回来确认rootrk3568:~# i2cset -y 4 0x4e 0x20 0x14 rootrk3568:~# i2cget -y 4 0x4e 0x20 0x14写入 0x14读回来还是 0x14寄存器可以正常读写。这套 i2cget/i2cset 工具相当于硬件调试里的手电筒不需要依赖驱动代码就能验证芯片行为。如果驱动代码有 bug通过 i2c-tools 先确认硬件侧寄存器是正常的就能把问题范围缩小到软件层效率高很多。我当时还习惯把所有关键寄存器的值 dump 出来做成一份日志存档。用一条命令就能搞定for reg in 0x10 0x11 0x20 0x21 0x22 0x30 0x40 0x50; do echo REG $reg $(i2cget -y 4 0x4e $reg) done这样做的意义在于后续每次改动代码后对比寄存器状态能非常快地定位哪一步开始写错了。4.3 动态调试打印与日志保存驱动里我用 dev_dbg 打了不少关键节点日志但直接打印在内核默认级别下往往不输出。这时就用 dynamic_debug不用重编驱动直接在运行时把调试输出打开# 挂载 debugfs 后 echo file st7102.c p /sys/kernel/debug/dynamic_debug/control dmesg -w打开之后probe 函数里每一句 dev_dbg 都会实时打到串口上。比如下面这类输出[ 123.456789] st7102 4-004e: VOUT1 set to 1800000uV, code 0x14 [ 123.456891] st7102 4-004e: VOUT2 set to 3300000uV, code 0x32如果板子离电脑远可以把 dmesg 输出通过串口调试助手或者网络调试助手重定向到远程终端这样不用物理走到板子旁边也能随时看日志。需要保存日志到文件时用dmesg -w /tmp/st7102_dbg.log 21再加个 nohup 就行后面排查问题可以慢慢翻不用守在屏幕前刷新。4.4 逻辑分析仪抓 I2C 波形软件层面的寄存器读写验证完接下来要做的是硬件层面的验证逻辑分析仪把 I2C 的 SCL、SDA 两根线分别夹到采样通道上。采样率我习惯设 20MHz触发条件设为 SCL 下降沿。然后加载驱动启动时观察初始化过程里往 ST7102 发的那几个 ACK/NACK 和数据字节。抓出来的波形能直接看清三件事地址是否正确、读写方向对不对、寄存器偏移和数据的字节数有没有错。一次典型的 I2C 写序列帧结构大概是启动信号 - 设备地址写位 - ACK - 寄存器偏移 - ACK - 数据字节 - ACK - 停止信号。如果抓到的波形里 ACK 位变成了 NACK说明这个地址上没有设备应答或者芯片正在忙。实际调试中我在新板子上就遇到过一种情况I2C 读操作抓到的数据总是 0xff但寄存器读却有返回。反复对比后才发现我把 regmap_config 里的reg_bits设成了 16 位而芯片实际是 8 位寄存器地址导致每次读的偏移都对不上。注意如果在示波器或者逻辑分析仪上看到 I2C 波形频繁出现毛刺、电平没有完全拉到轨先检查总线上拉电阻的阻值。常见做法是 I2C 总线上拉 4.7kΩ总线电容大的可以降到 2.2kΩ但不能太小否则功耗会增加还可能影响高速模式下的信号边沿。4.5 用户态工具 GDB/Keil 查看结构体内核侧调试到一定程度后我还会写一个用户态的小工具直接通过 /dev/i2c-x 来访问 ST7102。这个工具在调试寄存器映射和电压表逻辑时特别高效而且能用 GDB 断点观察结构体变量排查代码逻辑问题比改内核模块快得多。#include linux/i2c-dev.h #include fcntl.h #include stdio.h #include unistd.h #include sys/ioctl.h struct st7102_dev { int fd; unsigned int vout1; unsigned int vout2; unsigned int vout3; u8 code1, code2, code3; }; int main(void) { struct st7102_dev dev; dev.fd open(/dev/i2c-4, O_RDWR); ioctl(dev.fd, I2C_SLAVE, 0x4e); dev.vout1 1800000; dev.vout2 3300000; dev.vout3 1800000; set_voltages(dev); return 0; }用交叉编译工具链编好后拷贝到板子上。调试时在主机上gdb ./st7102_test用 gdbserver 连到板子在 set_voltages 那一行下断点(gdb) break set_voltages (gdb) continue Breakpoint 1, set_voltages (dev0x... (gdb) print *dev $1 {fd 3, vout1 1800000, vout2 3300000, vout3 1800000, code1 0, code2 0, code3 0} (gdb) next (gdb) print dev-code1 $2 20GDB 支持直接展开结构体每个字段的值看得清清楚楚。如果你是从单片机开发转过来的可以把它理解成 Keil 调试模式里 Watch 窗口的用法——在 Keil 的 Debug 界面里输入结构体变量名右侧就能像树状列表一样展开所有成员的值GDB 里的print *dev效果完全一样而且还能通过set print pretty on让输出按成员换行显示嵌套结构体也能一目了然。4.6 把日志保存成可回看的文件调试串口输出一直开着很占地方但偶尔又需要翻历史日志怎么办我建议在任何长时间调试之前先把日志落到文件。板子上可以用dmesg -w /tmp/st7102_dbg.log 然后在远程主机上配合网络调试助手把文件拉出来分析。尤其是那种跑了一个小时才随机出现一次的问题不多开几个日志通道根本追不到现场。顺带一提串口调试助手支持把接收区内容自动保存成文件我一般把发送和接收都开上时间戳记录这样日志里哪一行对应哪个时间点就非常清楚。5. 踩坑记录与排查速查表5.1 这次移植中遇到的典型问题我这次 ST7102 移植前前后后花了大约一周其中一半时间在排查各类问题。把典型问题整理成一张速查表方便大家遇到类似情况时对号入座现象可能原因排查方法解决手段加载驱动后无 probe 日志compatible 字符串不匹配查 /sys/bus/i2c/drivers/st7102 是否存在修正设备树 compatible与 of_match_table 一致i2cdetect 扫不到地址硬件没上电/地址脚配置错误万用表测供电核对原理图地址补焊电阻调整地址脚电平读 ID 寄存器返回 0xff寄存器偏移写错或 regmap 配置错误用 i2cget 手动读同一地址修正 reg_bits 为 8并核实偏移值电压输出与期望不符电压编码公式算错实测万用表查寄存器当前值用电压表函数查表配置probe 报 -EPROBE_DEFER依赖的 regulator 未就绪dmesg 查 deferred 列表等待依赖驱动加载或检查设备树 supply中断一直触发中断标志没清干净读 INT_FLAG 寄存器在 handler 末尾写 1 清除标志位5.2 排查思路层面的三条建议除了上面这些具体问题我还想聊三个方法论层面的东西。第一个是分层排查。驱动报错的时候先分清问题在哪一层是设备树匹配层还是总线通信层还是寄存器配置层还是电源输出层。每一层都有专门的验证手段匹配层看 sysfs通信层用 i2c-tools寄存器层用逻辑分析仪电源层用万用表示波器。按这个顺序逐层往下查比瞎猜高效得多。第二个是对比验证。如果你手上有块能正常工作的旧板卡把它当成金标准。同一份操作流程在旧板卡上读寄存器再在新板卡上读同样的寄存器对比差异问题点通常就在分歧处。比如我这次排查时发现新板卡的 CTRL 寄存器比旧板卡多了一个 bit查手册才发现平台启动引导阶段往芯片写了一个额外配置把这个配置对齐之后问题就消失了。第三个是先硬件后软件。驱动移植过程中凡是怀疑到硬件问题先停下来用万用表量电压、量导通、看波形别急着改软件。我见过太多同事明明芯片供电都没有还在那里对着设备树改了一个下午。硬件排除了再回来看软件思路会清晰很多。5.3 给新入坑驱动开发的朋友几句实在话最后说几句实在话。驱动移植看着是个技术活其实更多是耐心活。芯片手册来回翻个十遍八遍是常态原理图一定要对着实物看不要让缩写和丝印误导。调试工具不用追求多贵万用表加逻辑分析仪加串口调试助手就足够解决绝大多数问题。调试记录的习惯也值得养成。每改一次配置就记一笔改成什么、为什么改、现象是什么。这次 ST7102 移植的日志我存了满满几个文件后面复现问题或者做方案评审时都是第一手材料。驱动开发里记性好不如烂笔头这话绝对不虚。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →