从模拟到数字,一文读懂OneOS驱动ADC
-
ADC设备
1.1 简介
ADC设备是实现模拟量转换为数字量的器件,即Analog-to-Digital Converter,模拟/数字转换器。相应地,还有DAC设备,即Digital-to-Analog Converter,数字/模拟转换器,用于实现数字量向模拟量的转化。
1.2 ADC参数分析
- ADC的分辨率
指的是模数转换器所能表示的最大数是多少,即ADC的位数,如果ADC是10位ADC,那么分辨率是2的10次方,即1024的分辨率,如果模拟量是温度,测量范围是0~100度,那么可以把100度分成1024份,每一份你都能感知,当温度有100/1024度的变化时,能测量出来。
- ADC的采样率
指ADC每秒钟会进行多少次的模拟量转数字量的操作,如10K/s就是说ADC每秒钟,就采集了10K个模拟量,并将模拟量转换为数字量。
- 通道
即ADC输入引脚,通常一个ADC控制器控制多个通道,如果需要多通道的话,就得进行通道扫描了。
- ADC的转换方式
单次转换:一次只转换一个通道;
连续转换:转换完成一个通道后立即自动执行下一个通道的转换;
扫描模式:开启一次后,自动的连续读取多个通道。
- ADC的三种工作方式
阻塞模式(查询模式)、中断模式、DMA模式
- ADC设备访问和注册
2.1 ADC设备访问
用户在访问ADC设备时,会调用设备管理层的接口,如os_device_find()、os_device_open()、os_device_control()、os_device_read_nonblock()、os_device_close()等,来实现对ADC的访问。设备管理层的接口往下调用设备框架层的接口,再往下调用设备驱动层的接口,最终实现对ADC硬件的相关操作。
取“os_device_control()”函数为例。
|
函数 |
路径 |
所属层 |
由上往下执行 |
os_device_control() |
driversdevice.c |
设备管理层 (所有设备通用的函数接口) |
_adc_control() |
driversmiscadc.c |
设备框架层 (同类设备的抽象) |
|
stm32_adc_enabled() |
drivershalstdriversdrv_adc.c |
设备驱动层 (由函数接口访问具体的硬件) |
2.2 ADC设备注册
在访问ADC设备的过程中,从设备管理层往下调用至设备驱动层,那系统是如何确定要往下调用哪个接口呢?这就是ADC设备注册时指定的。设备注册的过程和设备访问的过程刚好是相反的,注册时从设备驱动层往上,直至设备管理层,如下表所示。
|
函数 |
路径 |
所属层 |
由上往下执行 |
stm32_adc_probe() |
drivershalstdriversdrv_adc.c |
设备驱动层 |
os_hw_adc_register() |
driversmiscadc.c |
设备框架层 |
|
os_device_register() |
driversdevice.c |
设备管理层 (把设备结点添加到设备链表) |
接下来对注册的过程作简单说明。
2.2.1 设备驱动层
位置:drivershalstdriversdrv_adc.c
从“stm32_adc_probe()”函数开始,下面为局部截图。
- 此函数中下面的语句确定了访问设备时调用的接口函数:
- 此函数中由下面的语句调用设备框架层的os_hw_adc_register()函数:
- 此函数中涉及的两个结构体
位置:driversbusbus.h
2.2.2 设备框架层
位置:driversmiscadc.c
由上述的设备驱动层调用下面的os_hw_adc_register()函数。
在该函数中继续往上调用设备管理层的os_device_register()接口。
2.2.3 设备管理层
位置:driversdevice.c
由上述的设备框架层调用下面的os_device_register()函数。下图为局部截图。
- 此函数中下面语句实现了把设备结点添加到系统的设备链表里:
其中相关定义:
①位置driversdevice.c
②位置kernelincludeos_list.h
③os_list_add函数的定义:
位置:kernelincludeos_list.h
④链表结点的定义:
位置:kernelincludeos_list.h
- ADC demo运行流程
demo文件位置:demosdriveradc_test.c
由上往下
由 左往右执行 |
os_device_find() (device.c) |
||
os_device_open() (device.c) |
|||
os_device_control() (device.c) |
_adc_control() (adc.c) |
stm32_adc_enabled() (drv_adc.c) |
|
os_device_read_nonblock() (device.c) |
_adc_read() (adc.c) |
os_adc_read() (adc.c) |
stm32_adc_read() (drv_adc.c) |
os_device_control() (device.c) |
_adc_control() (adc.c) |
stm32_adc_enabled() (drv_adc.c) |
|
os_device_close() (device.c) |
路径 |
① |
driversdevice.c |
② |
driversmiscadc.c |
|
③ |
drivershalstdriversdrv_adc.c |
adc_sample()函数部分运行过程分析:
adc_test.c【int adc_sample(int argc, char **argv)】 |
||
函数(由上往下执行) |
语句(由上往下执行) |
功能 |
os_device_find(argv[1]) 功能:由设备名称“argv[1]”寻找设备 位置:OneOSdriversdevice.c |
os_sem_wait(&dev_sem,OS_WAIT_FOREVER); |
信号量等待 |
for循环 |
在链表“os_device_list”中寻找该设备 |
|
os_sem_post(&dev_sem); return dev; |
找到则释放信号量并返回对应设备结构体(类型“os_device_t”) |
|
os_sem_post(&dev_sem); return OS_NULL; |
未找到设备则释放信号量并返回“OS_NULL” |
|
os_device_open(adc_dev); 条件:找到设备后可执行 功能:“打开”设备,可初始化设备 位置:OneOSdriversdevice.c |
os_sem_wait(&dev->sem, OS_WAIT_FOREVER); |
信号量等待 |
dev->ops->init(dev); |
初始化设备,但本测试中未进行。 涉及结构体:“os_device”“os_device_ops” |
|
os_sem_post(&dev->sem); |
释放信号量 |
|
os_plug_get(“device”, dev->name); return result; |
plug->ref_count++; 返回“OS_EOK” |
|
os_device_control(adc_dev, OS_ADC_CMD_ENABLE, OS_NULL); 位置:OneOSdriversdevice.c
|
switch语句 |
由输入的cmd:OS_ADC_CMD_ENABLE在switch语句中进行匹配,未匹配到对应指令 |
os_sem_wait(&dev->sem, OS_WAIT_FOREVER); |
信号量等待 |
|
dev->ops->control(dev, cmd, arg); |
进入“_adc_control()” |
|
os_sem_post(&dev->sem); return ret; |
释放信号量; 返回“_adc_control()”的返回结果 |
|
_adc_control(struct os_device *dev, int cmd, void *args) 由os_device_control()函数进入 位置:OneOSdriversmiscadc.c |
switch语句 |
由输入的cmd:OS_ADC_CMD_ENABLE在switch语句中进行匹配 |
adc->ops->adc_enabled(adc, OS_TRUE); return result; |
执行stm32_adc_enabled()然后返回其执行结果 |
|
stm32_adc_enabled() 由_adc_control()函数进入 位置:OneOSdrivershalstdriversdrv_adc.c |
/ |
使能设备,返回OS_EOK |
os_device_read_nonblock(adc_dev, adc_channel, &adc_databuf, sizeof(adc_databuf)); 位置:OneOSdriversdevice.c |
dev->ops->read(dev, pos, buffer, size); |
进入“_adc_read()”函数 涉及结构体:
|
return count; |
返回“_adc_read()”执行结果 |
|
_adc_read(struct os_device *dev, os_off_t pos, void *buffer, os_size_t size) |
for循环 |
|
|
return i; |
返回执行os_adc_read()的次数 |