简介
纯粹的 ADC 驱动也是 IIO 驱动框架,如果需要自己编写ADC驱动,其实就是按照IIO的驱动框架进行相关实现。
IMX6ULL 的ADC驱动设备树配置
I.MX6ULL 有 2 个 ADC,但是对应一个 ADC 控制器。目前使用
GPIO1_IO01 这个ADC1 的通道 1 引脚来进行配置。
关 于 I.MX6ULL 的 ADC 节 点 更 为 详 细 的 信 息 请 参 考 对 应 的 绑 定 文 档 :Documentation/devicetree/bindings/iio/adc/vf610-adc.txt。
接下来我们简单分析一下绑定文档,后面我们需要根据绑定文档修改设备树,使能 ADC 对应的通道。
ADC 相关属性有:
- compatible: 兼容性属性,必须的,可以设置为“fsl,vf610-adc”。
- reg: ADC 控制器寄存器信息。
- interrupts: 中断属性, ADC1 和 ADC2 各对应一个中断信息。
- clocks: 时钟属性。
- clock-names: 时钟名字,可选“adc”。
- vref-supply: 此属性对应 vref 参考电压句柄。
可以看出, ADC 节点的属性还是比较少的。
1.设备树 adc1 io模式配置
&iomuxc {
pinctrl_adc1: adc1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
>;
};
};
2.设备树adc1电源字节点配置
regulators {
reg_vref_adc: regulator@2 {
compatible = "regulator-fixed";
regulator-name = "VREF_3V3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
};
3.设备树ADC补充adc1节点配置
/{
};
&adc1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_adc1>;
num-channels = <2>;
vref-supply = <®_vref_adc>;
status = "okay";
};
4. 内核编译使能ADC
使能内核里面自带的 I.MX6ULL ADC 驱动,打开 Linux 内核配置界面,配置ADC的驱动路径如下:
-> Device Drivers
-> Industrial I/O support
-> Analog to digital converters
-> <*> Freescale vf610 ADC driver //选中
配置界面如下:
adc驱动使用
编译修改后的设备树,然后使用新的设备树启动系统。进入/sys/bus/iio/devices 目录下
,此目录下就有 ADC 对应的 iio 设备: iio:deviceX。
以上是标准的 IIO 设备文件目录,但只关心 iio:deviceX中的三个文件:
in_voltage1_raw:
ADC1 通道 1 原始值文件。
in_voltage_scale:
ADC1 比例文件(分辨率),单位为 mV。实际电压值(mV)=in_voltage1_raw*in_voltage_scale
查看ADC原始值和转化的电压值:
Linux应用程序实现对ADC数据的读取
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "sys/ioctl.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <poll.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <errno.h>
/* 字符串转数字,将浮点小数字符串转换为浮点数数值 */
#define SENSOR_FLOAT_DATA_GET(ret, index, str, member)\
ret = file_data_read(file_path[index], str);\
dev->member = atof(str);\
/* 字符串转数字,将整数字符串转换为整数数值 */
#define SENSOR_INT_DATA_GET(ret, index, str, member)\
ret = file_data_read(file_path[index], str);\
dev->member = atoi(str);\
/* adc iio框架对应的文件路径 */
static char *file_path[] = {
"/sys/bus/iio/devices/iio:device0/in_voltage_scale",
"/sys/bus/iio/devices/iio:device0/in_voltage1_raw",
};
/* 文件路径索引,要和file_path里面的文件顺序对应 */
enum path_index {
IN_VOLTAGE_SCALE = 0,
IN_VOLTAGE_RAW,
};
/*
* ADC数据设备结构体
*/
struct adc_dev{
int raw;
float scale;
float act;
};
struct adc_dev imx6ulladc;
/*
* @description : 读取指定文件内容
* @param - filename : 要读取的文件路径
* @param - str : 读取到的文件字符串
* @return : 0 成功;其他 失败
*/
static int file_data_read(char *filename, char *str)
{
int ret = 0;
FILE *data_stream;
data_stream = fopen(filename, "r"); /* 只读打开 */
if(data_stream == NULL) {
printf("can't open file %s\r\n", filename);
return -1;
}
ret = fscanf(data_stream, "%s", str);
if(!ret) {
printf("file read error!\r\n");
} else if(ret == EOF) {
/* 读到文件末尾的话将文件指针重新调整到文件头 */
fseek(data_stream, 0, SEEK_SET);
}
fclose(data_stream); /* 关闭文件 */
return 0;
}
/*
* @description : 获取ADC数据
* @param - dev : 设备结构体
* @return : 0 成功;其他 失败
*/
static int adc_read(struct adc_dev *dev)
{
int ret = 0;
char str[50];
SENSOR_FLOAT_DATA_GET(ret, IN_VOLTAGE_SCALE, str, scale);
SENSOR_INT_DATA_GET(ret, IN_VOLTAGE_RAW, str, raw);
/* 转换得到实际电压值mV */
dev->act = (dev->scale * dev->raw)/1000.f;
return ret;
}
/*
* @description : main主程序
* @param - argc : argv数组元素个数
* @param - argv : 具体参数
* @return : 0 成功;其他 失败
*/
int main(int argc, char *argv[])
{
int ret = 0;
if (argc != 1) {
printf("Error Usage!\r\n");
return -1;
}
while (1) {
ret = adc_read(&imx6ulladc);
if(ret == 0) { /* 数据读取成功 */
printf("ADC原始值:%d,电压值:%.3fV\r\n", imx6ulladc.raw, imx6ulladc.act);
}
usleep(100000); /*100ms */
}
return 0;
}