[RK3399][Android7.1] 调试笔记 AM1805调试

平台 内核版本 安卓版本
RK3399 Linux4.4 Android7.1

AM1805介绍

AM1805是集RTCWatchdogAlarmCountdown四大功能于一身,功能齐全的实时时钟芯片,包含片上振荡器以提供最低的功耗,完整的RTC功能,包括电池备份,可编程计数器和定时器和看门狗功能的报警,以及用于与主机控制器通信的I2CSPI串行接口。 集成电源开关和具有计数器,定时器,闹钟和中断功能的复杂系统睡眠管理器使AM18X5可用作基于主机微控制器系统的监控组件。
SDK中默认没有该IC的驱动支持,所以里面的驱动是根据规格书编写的。

原理图

在这里插入图片描述
硬件上的特性:
硬件原理图上的中断输入WDI没有接,中断输出接的有nRSTPSW/nIRQ2,其他中断引脚nTIRQCLKOUT/nIRQ3FOUT/nIRQ。目前软件Watchdog中断输出走的是nRST,其他AlarmCountdown走的是nIRQ2中断脚。功能总述为下图中红色的走线,CDTAlarm到或门控制输出到nIRQ2WDT到或门输出到nRST
在这里插入图片描述

驱动步骤

  • 调通I2C,能通过I2C读写寄存器(或使用I2C探针测试)
  • 做调试工具,驱动里面写一个sys控制寄存器,实现读写单个寄存器和打印全部寄存器。然后通过串口命令行用catecho直接去读写寄存器,并在调RTC,ALARM,COUNTDOWN,WATCHDOG之前,先用读写寄存器命令验证功能。
  • 根据规格书提供的寄存器资料,开始通过直接读写寄存器,去先检验 RTCAlarmWatchdogCountdown功能,确认用寄存器能调试没问题后,在驱动里面把相关代码写好。
  • 调完后,写一个用户空间的程序,通过IOCTL来测试驱动。
  • 校正RTC外部晶振

调试

前期调试:
由于硬件上VCC直接上电,所以不用去控制IO上电。
AM1805规格书I2C地址是0x8c/0x8d,这个地址包含读写位,bit0是读写位,所以bit1~7是实际的I2C地址,0x8c/0x8d>>1可以算出I2C地址是0x69I2C实际挂载为i2c ao,不是原理图的i2c b
dts中加上RTC的配置编译烧录了dtb后,在驱动的probe函数中加读取chip id并打印,看到I2C通了。
在这里插入图片描述

由于验证功能需要频繁读写寄存器,所以注册了一个class直接操作寄存器。目前调试或者查问题都可以通过命令行直接操作class读写寄存器,方便快速定位问题。
驱动里面通过class_create来创建一个设备的逻辑类:

class_register(&rtc_am1805_class)

然后创建三个功能的属性:读单个寄存器,写单个寄存器,读所有寄存器。这三个属性目前基本能满足这个芯片的调试。

在这里插入图片描述
使用示例:

  • 这里举例在命令行直接设置一个闹钟Alarm 关闭AIE使能,设置IM为电平模式
echo "0x12 0xe0">/sys/class/rtc_am1805/write_reg
  • 清除ALM Status
echo "0x0f 0x00">/sys/class/rtc_am1805/write_reg
  • 设置为 IRQ2中断
echo "0x11 0x0c">/sys/class/rtc_am1805/write_reg
  • 设置时间
echo "0x08 0x01">/sys/class/rtc_am1805/write_reg
echo "0x09 0x01">/sys/class/rtc_am1805/write_reg
echo "0x0a 0x50">/sys/class/rtc_am1805/write_reg
echo "0x0b 0x00">/sys/class/rtc_am1805/write_reg
echo "0x0c 0x02">/sys/class/rtc_am1805/write_reg
echo "0x0e 0x01">/sys/class/rtc_am1805/write_reg
  • 一年一次
echo "0x18 0xc6">/sys/class/rtc_am1805/write_reg
  • 启动
echo "0x12 0xe4">/sys/class/rtc_am1805/write_reg

RTC驱动

RTC时间调试

RTC可给系统提供时间,当系统关机后,RTC芯片由于有电池供电,时间就不会停止,这样下次设备开机后就知道时间。RTC时间由于只需要读写时间相关的寄存器,直接在命令行用echo设置一下相关寄存器,可直接设置时间,然后在驱动里面实现RTC驱动提供的接口。寄存器:
在这里插入图片描述
驱动主要工作是填充rtc_class_ops结构体,结构体描述了RTC芯片能够提供的所有操作接口函数:

	struct rtc_class_ops {
    int (*open)(struct device *);
    void (*release)(struct device *);
    int (*ioctl)(struct device *, unsigned int, unsigned long);
    int (*read_time)(struct device *, struct rtc_time *);
    int (*set_time)(struct device *, struct rtc_time *);
    int (*read_alarm)(struct device *, struct rtc_wkalrm *);
    int (*set_alarm)(struct device *, struct rtc_wkalrm *);
    int (*proc)(struct device *, struct seq_file *);
    int (*set_mmss)(struct device *, unsigned long secs);
    int (*read_callback)(struct device *, int data);
    int (*alarm_irq_enable)(struct device *, unsigned int enabled);
	};

具体实现:

	static const struct rtc_class_ops rtc_am1805_ops = {
	.open       = rtc_am1805_open,
	.read_time = rtc_am1805_read_time,
	.set_time = rtc_am1805_write_time,
	.read_alarm = rtc_am1805_read_alarm,
	.set_alarm = rtc_am1805_set_alarm,
	.set_cdt_time = rtc_am1805_set_timer,
	.read_cdt_time = rtc_am1805_read_timer,
	.ioctl      = rtc_am1805_ioctl,
	};

注册设备:

rtc_device_register(name, dev, &test_rtc_ops, THIS_MODULE);

watchdog调试

看门狗是用来定期监控系统的运行情况,一旦系统死机,看门狗就发出重启电路的信号。用途上比如广告机,我们需要它一直播放广告,如果突然死机了怎么办,所以我们就通过看门狗来解决,死机后看门狗自动重启设备,然后继续播放广告。
由于原理图上没有WDI中断输入,所以需要驱动模拟实现。模拟喂狗驱动上用一个计时器和一个工作队列来实现。计时器每隔一定时间发出一个需要喂狗的工作,工作队列对看门狗倒计时的寄存器重新填值。
目前我在驱动上设计喂狗的时间为2秒,超时的时间4秒。也就是4秒内没有喂狗,看门狗就产生一个中断到nRST引脚复位设备。
目前驱动里面计时器所做的内容就是添加一个工作到队列里:
在这里插入图片描述

在这里插入图片描述
工作的内容就是喂狗:
在这里插入图片描述
在这里插入图片描述
工作流程:第一次add_timer的时候会启动一次计时器,计时器会添加一个工作到工作队列,工作队列填完值后,mod_timer会改动计时器的启动时间,也就是2秒,2秒后会再次进入计时器函数,然后计时器又添加一个工作到工作队列,如此循环。也就是不停的喂狗。
假如kernel跑飞了,这时驱动不会去喂狗了,这时看门狗的计时器会自动减到0,进而出发电平中断到nRST引脚,设备就会复位。

发布了270 篇原创文章 · 获赞 95 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_33487044/article/details/104427077