RIOT 中 MAX313xx RTC 驱动测试应用全解析:从 shell 命令到源码级验证
【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT
本指南围绕 RIOT 仓库中的 tests/drivers/max313xx/README.md 展开,系统讲解如何构建、烧录并运行 Analog Devices MAX313xx 系列实时时钟(RTC)的驱动测试应用,覆盖 MAX31331 与 MAX31343 两种器件变体、全部 shell 命令的用法与参数,并结合 drivers/include/max313xx.h 与 drivers/max313xx/max313xx.c 源码,说明每条命令背后的寄存器操作与底层原理。读完本文,你将掌握 MAX313xx 驱动的验证流程、硬件参数配置方法,以及如何在应用中复用其时间、闹钟、温度、方波输出与涓流充电等功能。
测试应用概述
tests/drivers/max313xx是 RIOT 中针对 MAX313xx 系列 I2C 实时时钟的驱动测试应用。该应用不依赖额外的 Python 测试脚本,而是直接通过RIOT shell提供一组命令,用于配置与控制 RTC:
- 读写当前时间;
- 设置与读取闹钟(仅 ALARM1);
- 使能/禁止闹钟中断;
- 读取片内温度(仅 MAX31343);
- 配置 SQW 方波输出频率(仅 MAX31343);
- 配置涓流充电器(trickle charger);
- 配置温度自动转换模式与采样间隔(仅 MAX31343);
- 开关振荡器(timekeeping);
- 运行内置自检(self-test)。
从 main.c 可以看到,应用启动后首先调用max313xx_init()初始化设备,然后进入shell_run()等待用户输入命令。
当前实现状态
根据 README 及 drivers/include/max313xx.h 中的说明,该驱动当前存在以下限制:
- 不支持中断:驱动本身不处理 RTC 产生的中断,应用需要在外部自行用
gpio_init_int配置对应引脚并提供回调; - 不支持 User RAM:器件内置的用户存储空间(User Storage Memory)尚未实现;
- 仅支持 ALARM1:ALARM2 能力受限,暂未支持;Countdown Timer 也尚未实现;
- 只需配置 I2C 总线:参数中仅需选定 RTC 所连接的 I2C 总线。
从 max313xx_internal.h 还可以看到,MAX31331与MAX31343两个变体同一时刻只能启用一个,同时启用会在编译期报错(#error "Only one driver variant can be used at a time!")。
支持器件与变体选择
驱动目前支持两款器件:
| 器件 | 特性差异 |
|---|---|
| MAX31331 | 基础 RTC,支持时间、闹钟、涓流充电 |
| MAX31343 | 在 MAX31331 基础上增加片内温度传感器、SQW 方波输出、温度自动转换(AUTOMODE) |
选型方式有两种:
- 在 Makefile 中修改:默认
DRIVER ?= max31331,如需 MAX31343,取消#DRIVER ?= max31343一行的注释; - 在命令行用
DRIVER环境变量指定(README 推荐的用法,优先级高于 Makefile 内的?=赋值):
DRIVER=max31331 make -C tests/drivers/max313xx/ flash termflash term表示编译并烧录后立即打开串口终端进入 shell。切换为 MAX31343 时同理:
DRIVER=max31343 make -C tests/drivers/max313xx/ flash termUSEMODULE += $(DRIVER)(Makefile)会把对应变体作为伪模块引入;而max31331/max31343这两个伪模块在 drivers/max313xx/Makefile.include 中声明。此外测试应用还依赖ztimer_sec、shell与shell_cmds_default(Makefile)。
硬件依赖与板卡约束
驱动层面要求目标板提供periph_i2c外设,并依赖rtc_utils工具模块,见 drivers/max313xx/Makefile.dep。由于测试应用体积较大,Makefile.ci 将arduino-duemilanove、arduino-uno、atmega328p、nucleo-l011k4、samd10-xmini、stk3200等内存较小的板卡列入BOARD_INSUFFICIENT_MEMORY,这些板卡无法运行本测试。
硬件参数配置
驱动初始化只需要知道器件挂在哪条 I2C 总线上。默认参数定义在 drivers/max313xx/include/max313xx_params.h:
#ifndef MAX313XX_PARAM_I2C # define MAX313XX_PARAM_I2C I2C_DEV(0) /**< Default I2C bus */ #endif #ifndef MAX313XX_PARAMS # define MAX313XX_PARAMS { \ .i2c = MAX313XX_PARAM_I2C, \ } #endif static const max313xx_params_t max313xx_params[] = { MAX313XX_PARAMS };也就是说,器件默认挂接在I2C_DEV(0)上。若你的板卡把 RTC 接到其他 I2C 总线,可在板级配置或应用构建参数中覆盖MAX313XX_PARAM_I2C(例如定义为I2C_DEV(1))。
测试应用在main()中使用max313xx_params[0]作为参数(main.c),max313xx_init()会把参数中的 I2C 总线存入设备描述符(max313xx.c)。
器件在总线上的7 位 I2C 地址固定为0x68(写地址 0xD0),定义于 max313xx_internal.h。
初始化与振荡器停止标志
max313xx_init()会读取状态寄存器(MAX313XX_REG_STATUS)并检查Oscillator Stop Flag(OSF)。OSF 在以下情况被置位:上电复位、电池耗尽或振荡器曾停止运行——此时芯片内的时间无效。
对应返回值(drivers/include/max313xx.h):
| 返回值 | 含义 |
|---|---|
0 | 初始化成功,时间有效 |
-EINVAL | 参数为空指针 |
-EIO | I2C 通信错误 |
-ENODATA | 振荡器曾停止,时间无效,需先调用max313xx_set_time()设置时间 |
测试应用对-ENODATA的处理是打印警告warning: oscillator was stopped; time is invalid – please set it(main.c)。当时间寄存器被写入后,OSF 标志会自动清除(max313xx_internal.h),因此首次上电后应先执行time_set。
Shell 命令详解
以下所有命令均在 RIOT shell 中直接输入执行。时间参数统一使用 ISO 8601 风格字符串YYYY-MM-DDTHH:mm:ss(共 19 个字符),解析逻辑见 main.c,输出格式为YYYY-MM-DDTHH:mm:ss。
time_get —— 读取当前时间
time_get调用max313xx_get_time()从器件读取 7 个时间寄存器(秒、分、时、星期、日、月、年)并解析为struct tm后打印,例如:
current time: 2026-01-09T00:00:00实现上,时间寄存器以BCD 编码存储(max313xx.c),其中星期映射关系为芯片 1..7 →tm_wday0..6,世纪位(CENTURY,月寄存器 bit7)决定年份落在 1900 还是 2000 年代。
time_set —— 设置当前时间
time_set 2026-01-09T00:00:00调用max313xx_set_time()写入时间寄存器。注意:数据手册规定,写入的时间要到下一个内部 1 Hz 时钟沿才会被锁存,因此写入后立即读回可能得到旧值(drivers/include/max313xx.h)。驱动在写寄存器前会校验时间合法性,年份仅支持2000–2099,非法输入返回-ERANGE(max313xx.c)。
alarm_set / alarm_get —— 设置与读取闹钟
alarm_set 2026-01-09T00:00:30 alarm_getalarm_set调用max313xx_set_alarm()写入 ALARM1 的 6 个寄存器(max313xx.c)。根据数据手册要求,驱动在写闹钟寄存器前会自动先关闭闹钟中断(A1IE);alarm_get则读取已配置的闹钟时间,若从未设置过会返回-ENOENT并打印no alarm set(main.c)。
注意两点:
- 使能闹钟中断前,必须等待至少 1 秒(见
set_alarm_int说明),这是数据手册的硬性要求(drivers/include/max313xx.h); alarm_get不会检查掩码位(masking bits),若掩码位被设置,RTC 实际匹配闹钟时可能不会考虑全部时间字段(drivers/include/max313xx.h)。
set_alarm_int —— 使能/禁止闹钟中断
set_alarm_int 0|1控制中断使能寄存器中的 A1IE 位(max313xx.c)。禁止闹钟(传0)的同时会清除闹钟标志 A1F。如前所述,调用alarm_set后若要使能中断,必须先等待至少 1 秒再执行set_alarm_int 1。
temp —— 读取温度(仅 MAX31343)
temp调用max313xx_get_temp()读取温度寄存器(0x1A/0x1B)。返回值单位为百分之一摄氏度(centi-degC),例如8475表示 84.75°C(drivers/include/max313xx.h)。驱动将原始 16 位值右移 6 位后乘以 25 得到 centi-degC(max313xx.c)。测试应用格式化输出为temperature: 26.50°C。
在 MAX31331 上该命令不编译(通过IS_USED(MODULE_MAX31343)条件编译保护,见 main.c)。
sqw —— 设置 SQW 方波输出频率(仅 MAX31343)
sqw 0-5可选频率(对应max313xx_sqw_freq_t枚举,见 drivers/include/max313xx.h):
| 参数 | 频率 |
|---|---|
| 0 | 1 Hz |
| 1 | 2 Hz |
| 2 | 4 Hz |
| 3 | 8 Hz |
| 4 | 16 Hz |
| 5 | 32 Hz |
调用max313xx_set_sqw()写入 RTC_CFG2 寄存器的 SQW 频率字段(max313xx.c);在 MAX31331 上调用会返回-ENOTSUP。
trickle —— 配置涓流充电器
涓流充电器用于缓慢为连接在 VBAT 上的超级电容或可充电备份电池充电,充电电流满足I = (VCC - V_diode - V_BAT) / R。
启用充电:
trickle <diode 0|1> <res 0|2|3>diode:0= 仅肖特基二极管,1= 二极管 + 肖特基;res:0= 3 kΩ,2= 6 kΩ,3= 11 kΩ(对应max313xx_trickle_res_t,见 drivers/include/max313xx.h)。
禁用充电:
trickle 0驱动针对两款器件写入的寄存器字段不同:MAX31331 使用 TRICKLE 寄存器的使能位 + 电阻选择字段,MAX31343 使用 TCHE 字段(仅0x5能真正使能涓流充电)与 D_TRICKLE 字段(max313xx.c)。
automode —— 温度自动转换模式(仅 MAX31343)
automode <0|1> <ttsint 0-7>- 第一个参数:
1开启 AUTOMODE,0关闭; ttsint:自动温度转换间隔,写入 TS_Config 寄存器的TTSINT字段(TS_Config[5:3],对应 drivers/include/max313xx.h):
| ttsint | 间隔 |
|---|---|
| 0 | 1 s |
| 1 | 2 s |
| 2 | 4 s |
| 3 | 8 s |
| 4 | 16 s |
| 5 | 32 s |
| 6 | 64 s |
| 7 | 128 s |
调用max313xx_temp_set_automode()完成写寄存器(max313xx.c)。
power —— 振荡器开关
power 0|1power 1:使能振荡器(设置 RTC_CFG1 的 ENOSC 位),继续计时(max313xx_poweron());power 0:关闭振荡器,停止计时(max313xx_poweroff())。
ENOSC 位在 MAX31331 与 MAX31343 中位于 RTC_CFG1 的不同 bit(bit0 vs bit1,见 max313xx_internal.h),驱动在源码中已分别处理。
test —— 内置自检
testtest命令串行执行一组自动化检查(main.c),是验证驱动与硬件工作是否正常的快捷方式:
- 写参考时间并读回:写入
_ref_time(2026-01-09 00:00:00,星期四)后ztimer_sleep2 秒,等待 1 Hz 锁存边界,再读回并与参考时间比对,允许 [+0, +3s] 的窗口误差; - 时间推进检查:再等待 2 秒,确认读回时间严格大于参考时间,证明振荡器在走时;
- 闹钟写入/读回:把闹钟设为当前时间 +2 秒,写入后再读回,允许 ±1 秒误差;
- 闹钟清除:调用
max313xx_set_alarm_int(false)关闭闹钟中断并清除标志; - 温度读取(仅 MAX31343):读取温度并打印。
全部通过输出[test] all tests PASSED。该自检对开发板调试非常实用,可用于确认 I2C 连线、器件变体选择和时间走时是否正常。
驱动源码要点:寄存器级实现
整个驱动通过i2c_read_regs/i2c_write_regs访问 7 位地址0x68的器件(max313xx.c),寄存器映射定义在 max313xx_internal.h:
- 共享寄存器:Status(
0x00)、Interrupt Enable(0x01)、RTC_CFG1(0x03)、RTC_CFG2(0x04)等; - 时间寄存器:MAX31331 起始于
0x08,MAX31343 起始于0x06(两器件寄存器布局不同,驱动用#if IS_USED(MODULE_...)分别定义); - 状态标志:A1F(bit0,闹钟1标志)、A2F(bit1)、OSF(bit6,振荡器停止标志);
- 中断使能:A1IE(bit0)、A2IE(bit1)。
值得注意的设计细节:
max313xx_set_time()在写入时强制置位月寄存器的世纪位(MAX313XX_MONTH_CENTURY,max313xx.c),因此通过本驱动设置的时间年份总是落在 2000 年代;max313xx_set_alarm()写寄存器前自动关闭 A1IE(max313xx.c),防止写入中途闹钟触发;- 温度转换采用 14 位有效数据(右移 6 位)并乘以 25,精度为 0.25°C 的整数倍,最终以 centi-degC 返回。
在应用中使用驱动与 walltime 集成
除了本测试应用,MAX313xx 驱动还可以直接用于业务应用。在应用的 Makefile 中加入:
USEMODULE += max31331 # 或 max31343并在板级配置中指定 I2C 总线后,即可调用 drivers/include/max313xx.h 中导出的 API:max313xx_init、max313xx_get_time、max313xx_set_time、max313xx_set_alarm、max313xx_get_alarm、max313xx_set_alarm_int、max313xx_poweron、max313xx_poweroff、max313xx_trickle_charge_enable/disable,以及仅 MAX31343 支持的max313xx_set_sqw、max313xx_get_temp、max313xx_temp_set_automode。
若希望把 MAX313xx 接入 RIOT 的walltime抽象,可在 Makefile 中添加(drivers/include/max313xx.h):
USEMODULE += walltime_impl_max31331 # 或 walltime_impl_max31343此时 max313xx.c 中的walltime_impl_init/walltime_impl_get/walltime_impl_set会被编译,将 RTC 桥接到 walltime 框架,上层应用即可用统一的 walltime 接口读写时间。
快速上手流程总结
- 接线:将 MAX313xx 的 SDA/SCL 连接到板卡空闲 I2C 总线(默认
I2C_DEV(0)),注意器件地址固定为0x68; - 选型:确认器件型号是 MAX31331 还是 MAX31343,在 Makefile 中设置或通过
DRIVER环境变量传入; - 编译烧录:
DRIVER=max31331 make -C tests/drivers/max313xx/ flash term(MAX31343 同理改为DRIVER=max31343;flash term会烧录并打开串口终端)
- 初始化检查:启动后若提示
oscillator was stopped,先执行time_set写入有效时间; - 功能验证:依次执行
time_get、time_set、alarm_set、alarm_get、power、trickle,MAX31343 还可执行temp、sqw、automode; - 整体回归:执行
test运行内置自检,输出[test] all tests PASSED即代表驱动与硬件工作正常。
通过上述命令与源码对照,即可完整掌握 RIOT 中 MAX313xx RTC 驱动的使用方式、寄存器级实现细节以及器件变体间的差异,为在产品应用中集成 MAX31331/MAX31343 提供可靠的验证基础。
【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考