基于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
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用STM32F1系列单片机驱动MS5837数字式压力传感器的代码示例: ```c #include "stm32f1xx_hal.h" #define MS5837_ADDR 0xEC // MS5837默认I2C地址 I2C_HandleTypeDef hi2c; // I2C总线句柄 // MS5837命令定义 #define MS5837_CMD_RESET 0x1E // 复位命令 #define MS5837_CMD_CONVERT_D1_OSR_256 0x40 // 水压转换命令,采样率256 #define MS5837_CMD_CONVERT_D2_OSR_256 0x50 // 温度转换命令,采样率256 #define MS5837_CMD_ADC_READ 0x00 // 读取ADC命令 // MS5837校准系数 uint16_t ms5837_c[8]; // MS5837初始化 void MS5837_Init(void) { uint8_t data[2]; // 发送复位命令 data[0] = MS5837_CMD_RESET; HAL_I2C_Master_Transmit(&hi2c, MS5837_ADDR, data, 1, 100); // 读取校准系数 data[0] = MS5837_CMD_ADC_READ; for (int i = 0; i < 8; i++) { data[1] = 0xA0 + i * 2; HAL_I2C_Master_Transmit(&hi2c, MS5837_ADDR, data, 2, 100); HAL_I2C_Master_Receive(&hi2c, MS5837_ADDR, data, 2, 100); ms5837_c[i] = (data[0] << 8) | data[1]; } } // 读取温度和压力 void MS5837_Read_Temp_Press(float *temp, float *press) { uint8_t data[3]; int32_t dT, off, sens, P; // 发送水压转换命令 data[0] = MS5837_CMD_CONVERT_D1_OSR_256; HAL_I2C_Master_Transmit(&hi2c, MS5837_ADDR, data, 1, 100); // 延时等待转换完成 HAL_Delay(10); // 读取ADC值 data[0] = MS5837_CMD_ADC_READ; data[1] = 0x00; HAL_I2C_Master_Transmit(&hi2c, MS5837_ADDR, data, 2, 100); HAL_I2C_Master_Receive(&hi2c, MS5837_ADDR, data, 3, 100); P = (data[0] << 16) | (data[1] << 8) | data[2]; // 发送温度转换命令 data[0] = MS5837_CMD_CONVERT_D2_OSR_256; HAL_I2C_Master_Transmit(&hi2c, MS5837_ADDR, data, 1, 100); // 延时等待转换完成 HAL_Delay(10); // 读取ADC值 data[0] = MS5837_CMD_ADC_READ; data[1] = 0x00; HAL_I2C_Master_Transmit(&hi2c, MS5837_ADDR, data, 2, 100); HAL_I2C_Master_Receive(&hi2c, MS5837_ADDR, data, 3, 100); dT = (data[0] << 16) | (data[1] << 8) | data[2]; // 计算温度和压力 int64_t T = 2000 + ((int64_t)dT * ms5837_c[5]) / 8388608; off = ((int64_t)ms5837_c[2] << 16) + ((int64_t)ms5837_c[4] * dT) / 128; sens = ((int64_t)ms5837_c[1] << 15) + ((int64_t)ms5837_c[3] * dT) / 256; if (T < 2000) { int64_t T2 = (dT * dT) / 2147483648; int64_t off2 = 5 * (T - 2000) * (T - 2000) / 2; int64_t sens2 = 5 * (T - 2000) * (T - 2000) / 4; if (T < -1500) { off2 += 7 * (T + 1500) * (T + 1500); sens2 += 11 * (T + 1500) * (T + 1500) / 2; } T -= T2; off -= off2; sens -= sens2; } P = ((P * sens) / 2097152 - off) / 32768; *temp = T / 100.0; *press = P / 100.0; } ``` 注意:该代码仅供参考,具体实现可能需要根据具体硬件平台及I2C库函数进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小嵌同学

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

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

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

打赏作者

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

抵扣说明:

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

余额充值