Hi3518EV200平台ADC多通道采样流程
Hi3518EV200 ADC
本文针对Hi3518EV200平台处理器,通过ADC单次采样方式,实现对多通道(1~4通道)ADC进行采样控制。本文仅仅是对Hi3518EV200芯片ADC的用法的介绍,不涉及ADC具体的工作原理、转换原理等细节内容。废话不多说,直入正题!
Hi3518EV200芯片ADC模块简介:
特性:
电源电压:3.3V
扫描频率不能高于200K/s
独立通道:4路
特点:
支持单次启动,每次扫描一个通道,不滤毛刺,提供中断以及查询。
支持连续扫描功能:
根据ch_vld自动轮询各通道
根据Tscan(扫描间隔)启动连续查询
根据Tglitch进行滤毛刺,完成对毛刺的有效判定
上报LSADC转换结果、对应的通道号
上报中断:有按键中断,按键有变化中断(此部分不太明白,是笔误写成了按键还是另有深意,不太清楚)
以上特性和特点摘自Hi3518EV200芯片手册,文章还会摘取Hi3518EV200芯片手册的部分寄存器截图以作介绍。
ADC的实现方法简述:
Hi3518EV200平台的ADC模块支持4个通道,分两种模式采样:
第一种是单次扫描模式,支持多通道扫描;
第二种是连续Scan扫描模式,支持多通道扫描(测试验证未成功,在此处就不多说了)
单次扫描模式的工作实现方法
- 打开ADC时钟
- 各个控制寄存器配置(参考手册流程配置,含采样值位数,通道使能,单次扫描,不支持powerdown等)
- 使用request_irq注册ADC中断,中断号19
以上配置封装成Init函数,模块加载时初始化ADC模块使用
ADC开始采样
具体操作函数封装为ADC_Start(),包含以下工作:
- 判断需要采样的通道和上次工作的通道是否为同一个通道(为什么要这么做,在下面内容会有说明)
- Disable中断,停止ADC,清空所有通道中断,清空通道使能,使能需要采样的通道,备份该通道等下次采样判断
- 如果1中的判断是同一个通道,就忽略2中操作
- 开始ADC采样,使能ADC中断
- 备份本次采样的通道号,以备下次采样时在1中进行判断
中断处理函数的工作
- 判断使能的是哪个通道
- 判断该使能的通道的中断标志是否置位(即该通道转换是否完成,一般都会完成)
- 获取该通道转换后的值
- 如果注册了其他对该数据操作的函数,就执行
- 清空该通道的中断标志位(此处需要小心操作,不然会引起不可知现象,详细见下文说明)
注:
需要在中断处理函数中设置ADC转换状态,在调用开始ADC转换的地方,判断ADC采样是否正在进行,如果ADC正在使用(即ADC转换已经开始,转换完成中断还未发生),就延时等待,直到该中断完成之后再开启ADC转换。
ADC采样具体实现:
通过配置ADC模块的相关配置寄存器使ADC正常工作。
ADC时钟:
打开ADC时钟:
ADC时钟配置在PERI_CRG31寄存器(参考下图),要打开ADC的时钟,需要将[1]置1。
ADC软复位:
这里的ADC软复位是指SAR_ADC的软复位请求,在PERI_CRG31寄存将[2]置1表示复位,置0表示撤销复位。
ADC参数配置:
ADC参数配置部分需要设置LSADC_CTRL0配置寄存器。
在初始化ADC时需要将ADC复位(为何要先复位,不太清楚,感觉这样做对设备来说更安全),设置ADC进入复位状态需要设置配置寄存器,把[15]置1即可。
ADC时钟撤销复位:将时钟寄存器PERI_CRG3的[2]置0,通上述打开ADC时钟。
ADC退出复位状态:将LSADC_CTRL0配置寄存器的[15]置0。
ADC通道使能,选择需要使用的ADC通道使能,将相应的位置1相应通道有效,置0则相应通道无效。
0通道 [8]置1
1通道 [9]置1
2通道 [10]置1
3通道 [11]置1
ADC转换精度设置:
[31:24] 设为0xFF 表示8bit精度,即采样范围:0~255
ADC扫描模式选择:
[13] 0 单次扫描模式
ADC的PowerDown支持选择:
[14] 0 不支持
到这里,ADC的复位和初始化工作完成,具体的初始化操作ADC单次采样流程可以参考下图流程。每次复位都需要重新设置初始化参数。
ADC中断设置
需要注册ADC中断,在ADC采样完成时发出中断,开始记录采样值。中断流程和别的中断处理类似(比如按键中断),ADC的中断号是19。具体中断细节此处省略。
开始ADC采样:
开始ADC采样的一些操作步骤:
- 先要判断ADC当前的采样通道和要采样的通道是否相同,如果ADC当前的采样通道和要采样的通道不相同,需要进行一些操作使ADC通道切换到需要采样的通道。(这一步不是必须,如果要多路采样,建议加上该部分,具体原因下文介绍)
- 将ADC的中断使能关闭,即将中断使能寄存器LSADC_CTRL4的[0]置0
- 停止ADC采样,即将Stop配置寄存器LSADC_CTRL8的[31:0]写入任意值就可以实现停止ADC采样,比如写入1
- 将ADC要采样的通道的中断清除,设置中断清除寄存器LSADC_CTRL6的[3:0]位,将通道号相对应的位置1
- 关闭ADC各通道使能,在配置寄存器LSADC_CTRL0的[11:8]位全部清零
- 单独使能要进行采样的通道,设置配置寄存器LSADC_CTRL0的[11:8]位将相应通道使能,如将[8]置1使能A通道
- 备份本次采样通道号,用来在开始工作时判断通道是否相同时(第1步)使用
- 如果ADC当前的采样通道号和要采样的通道相同,就可以跳过第2.3.4.5.6.7直接启动ADC采样
- 启动ADC采样,设置Start配置寄存器LSADC_CTRL7的[31:0]位,写入任意值就可以启动ADC采样,比如写入1
- 最后要使能ADC采样中断,采样完成后发出中断,将中断使能寄存器LSADC_CTRL4的[0]位置1
以上的ADC采样操作可以用简单的方法,只需第2.3.4.5.6.9.10步即可,如果只使用单通道采样,只需要将这几步操作放到ADC初始化操作中执行一次就可以,不用每次开始ADC采样都设置。至于为什么比较麻烦,是为了应对多路采样时,有的通道采样时间间隔比较小,有的通道采样时间间隔比较大,造成的重复无意义的操作。
举例说明:ADC要采样的是光照、温度数据,在采样时间间隔不多的时候,比如光敏一秒一次,温度三秒一次,这样的情况是没有什么差别的,但是如果时间间隔差的很多,比如光敏一秒一次,温度30秒一次,这样的情况,在两次温度采样间隔内的30秒,光敏要采样30次,就要初始化30次,这是没有必要的。所以就需要加上第1步的判断逻辑,如果需要采样的通道和上次采样的通道是同一个通道,就免去了重复初始化同一个通道的操作,减轻处理负担。
ADC中断处理函数:
在中断发生时需要做的工作:
- 逐个判断各通道是否有效,也可以获取配置寄存器LSADC_CTRL0的[11:8]位来确定当前采样通道。
因为使用的是单个通道逐个采样的方法,所以同一时刻只有一个通道在工作,通过在中断函数中检测哪个通道被使能可以得到是由哪个通道采样发生的中断。 - 检查中断状态寄存器,判断相应通道的扫描值是否有效
检查中断状态寄存器LSADC_CTRL5的[3:0]位是否被置1,置1则相应通道的扫描值有效,否则无效。 - 如果中断状态有效,就可以读取ADC采样值
直接读取数据保持寄存器LSADC_CTRL3:
[7:0] 通道A扫描值
[15:8] 通道B扫描值
[23:16] 通道C扫描值
[31:24] 通道D扫描值 - 清除中断状态标志
设置中断清除寄存器LSADC_CTRL6的[3:0]位,将相应的位置1,清除相应通道的中断 - 需要添加保险机制,在中断发生后即第1步之后,如果2、3步判断失败,就没法进行4步的清中断,这将导致ADC采样卡死(不采样也不运行中断)
此时的解决方法就是复位ADC,但是这样做有点粗暴,比较好的方法还是避免出现这种卡死现象,比如添加第5步的保险机制,即判断中断都没有执行时就清除4步寄存器中的对应通道中断,或者清除所有通道中断。
之后就是对获取到的ADC采样值进行处理了,略。
总结
至此,ADC通过单次采样的方式对多通道采样的方法介绍完毕,通过这种方法就能通过单次采样的方式对多个通道的数据进行轮流采样了,采样获取到的数据是在前边设置的采样精度范围内,根据实际需要进行处理。有必要提醒下,实时采样得到的数据会存在一些漂移,可以通过硬件滤波使数据稳定,或者在软件中添加滤波算法,对采样得到的数据进行滤波处理。如果朋友们有更好的实现方法,还请指教一二,欢迎相互交流心得。
附:数据手册上的ADC相关配置寄存器截图
附:ADC采样支持连续扫描处理
连续扫描处理过程在验证时没有得到想要的效果,在这里不便多说,下面仅列出文档中连续扫描处理流程参考。