基于HI3516/HI3518/HI3559内部ADC驱动实现
提示:除了以上三种SOC,海思HI35XX其他SOC实现流程也应该类似,本篇文章以HI3516为主体进行实现。
文章目录
- 前言
- 一、相关资料
- 二、实现原理及步骤
- 1.原理
- 2.步骤
- 三、代码实现
前言
最近实际开发中需要实现海思SOC内部自带的一个ADC的驱动,但海思SDK中并未提供相应的软件驱动支持,故需要自己去实现,整体流程也比较简单,不过对于第一次接触海思开发的人来说有一点困难
一、相关资料
(1)开发板配套的海思官方SDK:Hi3516CV500R001C02SPC021.rar,将其解压开来
(2)SOC引脚信息表:00.hardware\chip\Hi3516DV300\Hi3516DV300_PINOUT_CN.xlsx
(3)SOC开发手册:00.hardware\chip\Hi3516DV300\Hi3516DV300专业型Smart IP Camera SoC用户指南.pdf
海思SOC中外设模块的相关寄存器配置在(3)数据手册中可以找到,但是关于GPIO引脚的配置
寄存器一部分在(2)中的excel表格,一部分在(3)中的数据手册
二、实现原理及步骤
1.原理
参考:Hi3516DV300专业型Smart IP Camera SoC用户指南.pdf 12.9章节
LSADC(Low Speed ADC)实现对外部模拟信号转换成一定比例的数字值,从而实现对模拟信号的测量,可应用于电量检测,按键检测等。芯片提供 1 个LSADC, 2 个独立通道;
LSADC 具有以下特点:
电源电压 3.3V/1.8V;
扫描频率不能高于 200K/s;
10bit 采样精度, 2 个独立通道;
支持单次扫描和连续扫描模式;
扫描完成自动上报中断。
2.步骤
(1)单次扫描处理流程
在单次读取模式(LSADC_CTRL0 [model_sel]=0), CPU 配置扫描通道号(仅且只能配置一个通道)、扫描模式、键值映射表信息,启动 LSADC 完成一次通道扫描。通道扫描完成后,通过中断通知系统扫描完成, CPU 可以获取转换结果。
(2)连续扫描处理流程
在连续读取模式(LSADC_CTRL0 [model_sel]=1), CPU 根据应用场景设置连续扫描的时间间隔 Tscan、毛刺宽度(Tglitch)、有效通道号(ch_vld),启动 LSADC。
LSADC 在一个时间间隔 Tscan 内完成一个有效通道(配置 LSADC_CTRL0 通道是否有效指示位为有效) 的扫描。在下一个扫描时刻到来时,启动对下一个有效通道的扫描。待完成对所有有效通道的扫描后,启动下一轮对有效通道的扫描, 各通道的轮询如图 12-58 所示。
以使能通道 0、 1 为例, 连续扫描模式下通道轮询扫描示意图如图 12-58 所示。
(3)细节设置
1、滤毛刺流程
滤毛刺电路采用多数判决算法。在滤毛刺窗口 Tglitch 中,如果出现多数次的 ADC 采
样值 value,且 value 不为空按键时 ADC 采样值,则认为 value 为一次有效的按键值,
否则认为是一个毛刺信号。
在单次读取模式,不进行滤毛刺操作。
在连续扫描模式下,使能虑毛刺功能,需要设置合适的虑毛刺时间窗口 Tglitch。
请参考 LSADC_CTRL1 寄存器的描述。
2、采样精度设置
通过 LSADC_CTRL9 [9:0]可以设置采样精度,可以根据应用需要设置对应的采样精
度。
当采样精度设置成 10bit 时,采样结果 10bit 全部有效。
当采样精度设置小于 10bit 时,对应的采样结果高位有效,例如:当采样精度设
置成 8bit 时,采样结果的高 8bit 才有效。
注意:当你读取 存储ADC转换结果的寄存器 LSADC_CTRL11的0-9位的值时,不论你设置的精度是什么,每次读出的值都是一样的,需要通过软件的方法进行处理,得到不同精度的结果,详情如上(2、采样精度设置 )所述。
三、代码实现
1、使用通道0/1,以连续扫描的方式进行工作。
2、根据(二、实现原理及步骤)中的流程图进行开发;
3、需要进行LSADC相关寄存器的配置,这两个ADC通道(0/1)对应的GPIO引脚进行配置(ADC模式),开启LSADC时钟配置(这个是最关键的,否则其他都配置正确,ADC也无法工作),此外需找到ADC对应的中断源。
4、软件实现
注意:对于所使用的中断源不可以直接传入中断号给request_irq函数进行申请,在使用了
设备树机制的新版本的内核中,内部会通过传入的物理中断号分配一个虚拟中断号,如
果直接传入数据手册中找到的物理中断号是无法工作的,需通过platform_get_irq获取。
adc_irq = platform_get_irq(dev, 0);
if (0 > adc_irq)
{
ERROR("platform get irq failed !");
goto ERR_2;
}
ret = request_threaded_irq(adc_irq, NULL, adc_irq_handler, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "hisi_adc", NULL);
if (ret)
{
ERROR("request threaded irq failed !");
goto ERR_2;
}
对于驱动硬件信息大家可以使用设备树传入获取,也可自己实现一个platform device,
注册到内核,我这里使用了设备树,需要修改内核源码中的设备树文件,添加ADC节点
hisi_adc {
compatible = "hisi_adc";
interrupt-parent = <&gic>;
interrupts = <0 65 4>;
};
65 + 32 = 97(开发手册中找到的物理中断号),对于设备树关于中断的描述相关知识大家
自行了解,我就不多说了。
该ADC驱动已有开源代码,我把链接提供给大家,大家可在这个基础上进行二次开发,实现自己的功能,我也是基于这个进行开发的(经过验证可用):
https://github.com/Tvirus/hisi_adc_driver