基于HI3516/HI3518/HI3559内部ADC驱动实现

提示:除了以上三种SOC,海思HI35XX其他SOC实现流程也应该类似,本篇文章以HI3516为主体进行实现。


前言

最近实际开发中需要实现海思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
  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
ADC采样校准主要有两个步骤:一是确定参考电压,二是进行偏移校准和增益校准。 1. 确定参考电压 参考电压是ADC转换电压的基准值,需要准确地测量和确定。可以通过外部参考电压源来提供参考电压,也可以使用芯片内部提供的基准电压源。在使用芯片内部基准电压源时,需要通过校准来保证其准确性。 2. 进行偏移校准和增益校准 偏移校准是为了消除ADC输出的偏移误差,即零点误差。方法是在ADC输入端接通一个已知电压源,将ADC输出与已知电压进行比较,得到偏移量,通过修改ADC的校准寄存器来进行校准。 增益校准是为了消除ADC输出的增益误差,即变换系数误差。方法是在ADC输入端接通不同幅度的已知电压源,将ADC输出与已知电压进行比较,得到增益误差,通过修改ADC的校准寄存器来进行校准。 以下是基于海思35X开发板和ADC模块的ADC采样校准代码示例: ```c #include "hi_adc.h" #define ADC_CHANNEL_NUM 1 //ADC通道数 #define REF_VOL 3300 //参考电压值(mV) #define ADC_BITS 12 //ADC位数 #define MAX_VALUE ((1 << ADC_BITS) - 1) //ADC最大值 //偏移校准 void offset_calibration(uint32_t channel) { uint32_t tmp_val = 0; uint32_t offset = 0; //使能ADC HI_ADC_Enable(); //设置ADC采样通道 HI_ADC_SetChannel(channel); //等待ADC就绪 while (!HI_ADC_IsReady()); //进行多次采样求平均值 for (int i = 0; i < 16; i++) { tmp_val += HI_ADC_GetValue(); } tmp_val >>= 4; //计算偏移量 offset = (REF_VOL * tmp_val) / MAX_VALUE; //设置偏移校准值 HI_ADC_SetOffset(channel, offset); //关闭ADC HI_ADC_Disable(); } //增益校准 void gain_calibration(uint32_t channel) { uint32_t tmp_val = 0; uint32_t gain = 0; //使能ADC HI_ADC_Enable(); //设置ADC采样通道 HI_ADC_SetChannel(channel); //等待ADC就绪 while (!HI_ADC_IsReady()); //进行多次采样求平均值 for (int i = 0; i < 16; i++) { tmp_val += HI_ADC_GetValue(); } tmp_val >>= 4; //计算增益误差 gain = (REF_VOL << ADC_BITS) / tmp_val; //设置增益校准值 HI_ADC_SetGain(channel, gain); //关闭ADC HI_ADC_Disable(); } int main() { //初始化ADC模块 HI_ADC_Init(); //进行偏移校准和增益校准 for (int i = 0; i < ADC_CHANNEL_NUM; i++) { offset_calibration(i); gain_calibration(i); } return 0; } ``` 需要注意的是,以上代码仅供参考,实际应用中需要根据具体情况进行修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小嵌同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值