依托Linux内核原生VF610通用ADC驱动,基于IIO工业IO子系统完成I.MX6ULL片内ADC采集,无需从零编写寄存器级驱动代码,开发核心集中在设备树硬件配置、内核功能裁剪、用户态sysfs应用开发三部分,承接上一章ICM20608的IIO驱动知识点巩固练习。
硬件层面,I.MX6ULL集成一组ADC控制器引出两路ADC通道,本次选用GPIO1_IO01复用为ADC1_CH1作为采集引脚,硬件输入电压必须限定在0~3.3V,超压会永久损坏芯片,采集时通过杜邦线接入待测模拟电压即可。
内核 imx6ull.dtsi 已经预设adc1基础节点,包含寄存器物理地址、中断号、时钟、最大通道数等硬件固有资源,默认 status 为禁用状态,且绑定兼容属性 fsl,imx6ul-adc 与 fsl,vf610-adc ,匹配内核 drivers/iio/adc/vf610_adc.c 驱动文件,配套官方设备树绑定文档可查阅完整属性说明。
设备树修改是实验核心配置环节,首先在板级设备树的regulators节点下新增固定3.3V稳压源子节点,采用regulator-fixed类型定义ADC转换所需的参考电压,设定最小、最大电压均为3300000微伏并设置常开启;其次改写&adc1节点,填入引脚复用组、绑定刚刚定义的参考电源、将状态修改为okay使能控制器;最后在iomuxc引脚配置组中添加pinctrl_adc1配置项,把GPIO1_IO01引脚硬件功能切换为ADC1通道1模式,彻底脱离GPIO输入输出功能。
内核驱动主体为vf610_adc.c,采用platform驱动总线搭配IIO框架搭建,自定义vf610_adc结构体作为私有数据载体,封装寄存器虚拟地址、时钟、参考电压、转换结果缓存、同步量、中断资源等全部运行参数。驱动入口probe函数会依次完成IIO设备内存申请、硬件物理资源映射、中断注册、时钟与参考电源获取使能,再初始化IIO描述结构体、绑定通道数组与读写回调函数,执行ADC硬件寄存器初始化后向内核注册IIO设备,最终在sysfs文件系统生成对应设备节点。
IIO操作集里的read_raw是用户读取ADC数据的核心回调函数,当用户读取in_voltage1_raw文件时触发执行。函数内部先上锁保护临界资源,重置completion同步变量,写入寄存器启动ADC硬件转换,随后阻塞等待中断唤醒;ADC转换完成后硬件自动触发中断服务函数,读取硬件数据寄存器的采样值存入私有结构体value变量,调用completion唤醒阻塞的read_raw函数,向外返回原始数值。
除此之外,read_raw还可读取缩放系数、采样频率参数,缩放系数配合原始值通过公式 实际电压(V)=原始值×缩放系数÷1000 计算真实电压,I.MX6ULL ADC默认12位精度,满量程4095对应3.3V参考电压。
使用前需执行make menuconfig配置内核,在Industrial I/O support的模数转换器分类下勾选Freescale vf610 ADC驱动,可编译进内核或编译为模块,保存配置后重新编译内核镜像与设备树dtb文件烧录开发板。
用户态编写adcApp.c测试程序实现循环采集,核心包含三个基础函数,file_data_read通用读取sysfs文本文件内容,通过fopen打开节点读取字符串数据;adc_read函数调用宏定义分别读取in_voltage1_raw原始值与in_voltage_scale缩放系数,运算得到实际电压;main主函数开启无限循环,每隔100毫秒调用采集函数打印数据。由于程序包含浮点运算,交叉编译时必须添加硬件浮点编译参数适配Cortex-A7内核的浮点单元,编译生成可执行文件后拷贝至开发板运行。
实操运行时,引脚接3.3V原始值趋近4095、接GND原始值趋近0,数值符合理论设计;杜邦线移动过程中出现的中间跳变电压,是模拟引脚悬空、接触断续带来的物理现象,不属于驱动或ADC硬件故障,偶尔出现的异常超大电压值是浮空采样误触发,重新稳固接线即可解决。
常见故障排查要点:找不到iio:device0节点,检查设备树adc1使能状态、引脚复用配置、内核驱动是否勾选、参考电源是否正确绑定;原始值固定为0无变化,排查引脚仍占用GPIO功能、硬件接线虚焊、参考电压未正常上电;电压计算偏差过大,核对缩放系数读取结果与换算公式;程序提示文件打开失败,代表驱动未成功加载,使用dmesg | grep adc查看内核打印日志定位问题。
整体学习要点总结,本次实验复用成熟的内核IIO架构与原厂ADC驱动,开发重心从寄存器编写转向设备树硬件资源描述,体现Linux驱动分层开发思想;驱动采用中断加completion同步的异步设计,解决硬件转换耗时的阻塞读取问题,是嵌入式外设开发通用设计思路;同时再次强化IIO子系统统一硬件抽象、sysfs标准化交互的设计优势,和陀螺仪IIO驱动实现逻辑互通。