6. 用户态 ADC 编程
EasyARM-iMX283A 提供了两种不同速度的 ADC 数据采集通道,一种 Low-Resolution
ADC( LRADC 低分辨率),底板引出 3 路: ADC0、 ADC1、 ADC6;另一种为 High-Speed
ADC(HSADC 高速 ADC,每秒可达 2MSPS),只有 1 路。 4 路 ADC 分别对应 EasyARMiMX283A
排母的 A0、 A1、 A6、 HSADC。
ADC0、 ADC1、 ADC6 三路通道内部含有一个除 2 模拟电路,在未开启内部除 2 电路
时,其量程为 0~1.85V,开启除 2 电路时,量程为 0~3.7V。 ADC 参考源来自内部参考电压
1.85V。另外,驱动提供了一个内部读取电池电压的接口,此通道内部有除 4 电路。 HSADC
为 2M 采样率的高速 ADC,可用于摄像头数据采集。
6.1 ADC 驱动模块的加载
EasyARM-iMX283A ADC 的驱动有两种,一种是 LRADC 对应的驱动。另一种为 HSADC
对应的驱动。下面分别对两种驱动加载方式作出介绍。
1. LRADC 对应的驱动加载
ADC0、 ADC1、 ADC6 对应的驱动是以动态加载模块的形式提供,因此在 ADC 操作之
前要先安装 lradc 驱动模块。
驱动模块在哪里?
root@EasyARM-iMX283 ~# insmod /root/lradc.ko
adc module init!
2. HSADC 对应的驱动加载
内核默认以动态加载模块方式编译 HSADC 驱动。在 EasyARM-iMX283A 光盘镜像的
linux 内核目录执行下面命令:
root@Linux-host:~/linux-2.6.35.3# make modules
就可以在“ linux-2.6.35.3/driver/misc/” 生成“ mxs-hsadc.ko” HSADC 驱动模块。加载动态
驱动模块与上面介绍的“ 安装 lradc 驱动” 方式相同。
如果需要静态加载此驱动,需要配置驱动为静态加载模式:
root@Linux-host:~/linux-2.6.35.3# make menuconfig
在内核选项里选择“ MX28 High Speed ADC”。选项路径:
Device Drivers->
[*] Misc devices --->
<> MX28 High Speed ADC
按空格键可以切换模块编译方式。选择“ *”,内核编译时会将高速 ADC 驱动以静态方
式编译。重新烧写内核后高速 ADC 驱动就会生效。
6.2 操作接口
本着简单易用原则, ADC 使用字符设备文件操作。下面分别介绍。
1. LRADC 操作接口
LRADC 操作仅使用了 ioctl 函数,读取电压操作代码如下:
...
#include "lradc.h"
#define LRADC_DEV /dev/magic-adc"
#define CMD_VOLTAGE IMX28_ADC_CH0 /* 通道 0 读取命令 */
....
int value, fd,;
fd = open(LRADC_DEV, 0); /* 打开 ADC 设备 */
....
ioctl(fd, , CMD_VOLTAGE, &value); /* 发送采集命令,采集数据保存在 value 中*/
其中, value 为读取的电压值, IMX28_ADC_CH0 读取通道 0 命令号,命令号定义位于
“ lradc.h”头文件中,通过 ioctl 系统调用后,返回值保存在 value 中,需要将这个值转换为
电压值。具体转化见文档。
2. HSADC 操作接口
当加载内核自带的驱动mxs-hsadc.ko时,将会生成内核文件/dev/mxs-hsadc0:
root@EasyARM-iMX283 /mnt/app_for_hardware# insmod mxs-hsadc.ko
root@EasyARM-iMX283 /mnt/app_for_hardware# lsmod
Module Size Used by
mxs_hsadc 4378 0
root@EasyARM-iMX283 /mnt/app_for_hardware# ls /dev/mxs-hsadc0 -l
crw-rw---- 1 root root 250, 0 Jan 1 01:22 /dev/mxs-hsadc0
手动建立一个字符设备节点:
HSADC 为字符设备,主设备号为 250,次设备号为 0,设备节点需要用户创建。创建命令如下:
root@EasyARM-iMX283A ~# mknod /dev/hsadc c 250 0
HSADC 只要通过 read 系统调用实现。驱动程序默认使用 12 位精度采集数据。下面的
示例代码实现了读取 len 个数据到 buff 中。
#define HRADC_DEV "/dev/hsadc" /* 高速设备名 */
int read_hsadc(short *buff, int len)
{
static int fd,flag = 0;
int ret,i,value;
fd = open (HRADC_DEV,0);
....
ret = read (fd ,buff,len); /* read 系统调用,返回采集数据*/
....
for(i=0;i
{
buff[i] &= 0x3ff; /* 数据低 12 位有效 */
}
}
6.3 C 程序操作示例
下面分别给出 LRADC 和 HSADC 的 C 程序操作范例。
1. C 程序操作 LRADC
程序清单 6.1 所示例程实现的功能是:读取 AP-283Demo 学习套件的电阻电压和 R32
发热电阻温度。
代码执行流程:首先获取用户需要读取数据量。然后打开设备,发送读取命令并打印返
回电压值,然后将读取的温度传感器的电压转化为温度并打印。
程序清单 6.1 ADC 操作示例
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <math.h>
-
#include <sys/ioctl.h>
-
#include "lradc.h"
-
-
#define LRADC_DEV "/dev/magic-adc" /* adc 设备文件名 */
-
#define CMD_VOLTAGE IMX28_ADC_CH0 /* 通道 0 读取命令 */
-
#define CMD_TEMPTURE IMX28_ADC_CH1 /* 通道 1 通读读取命令 */
-
#define R33 2000
-
#define V_ADC 3.3
-
#define T1 (273.15 + 25)
-
#define R1 27600
-
#define B 3435*1000
-
-
int main(int argc,char **argv)
-
{
-
short buff[100];
-
int i, fd, value_R, value_T, cmd, ret, len = 2;
-
float voltage, RT, temp,resistance;
-
fd = open (LRADC_DEV,O_RDONLY); /* 打开 ADC 设备 */
-
if (fd < 0) {
-
perror("open");
-
close(fd);
-
return 0;
-
}
-
-
while(1)
-
{
-
usleep(1000000);
-
ret = ioctl(fd, CMD_VOLTAGE, &value_R); /* 读取通道 0 */
-
if(ret != 0){
-
perror("ioctl");
-
return -1;
-
}
-
-
ret = ioctl(fd, CMD_TEMPTURE, &value_T); /* 读取通道 1 */
-
//close(fd);
-
if(ret != 0) {
-
perror("ioctl");
-
return -1;
-
}
-
-
resistance = (value_R*1.85)/4096.0; /* 计算通道 0 测量电压 */
-
voltage = (value_T*1.85)/4096.0; /* 计算通道 1 测量电压 */
-
RT = (V_ADC/voltage - 1)*R33; /* 计算热敏电阻的阻值 */
-
temp = 3435/log(10*RT) - 273.15; /* 计算热敏电阻的温度 */
-
-
printf("A10 Voltage: %fV ;A11 Temperature: %f\n", resistance, temp);
-
}
-
-
close(fd);
-
return 0;
-
}
注意,执行 adc 代码前,必须要加载 lradc.ko 模块。编译代码指令如下:
编译应用程序:
# arm-linux-gcc -o lradc_app -lm lradc_app.c
编译驱动程序:lradc.ko
root@Linux-host:/nfsroot/app_for_hardware/6th_adc/lradc/lradc_driver# make
root@Linux-host:/nfsroot/app_for_hardware/6th_adc/lradc/lradc_driver# ls
built-in.o lradc.h lradc.mod.c lradc.o modules.order README.txt
lradc.c lradc.ko lradc.mod.o Makefile Module.symvers
加载驱动:
# insmod lradc.ko
执行程序:
# ./lradc_app
可以看到打印的温度信息:
root@EasyARM-iMX283 /mnt/app_hardware/6th_adc/lradc/lradc_appTest# ./lradc_app
A10 Voltage: 0.812085V ;A11 Temperature: 16.143188
程序1:只打印一次sensor的值。
程序2:每隔一秒打印一次,一直打印。
2. C 程序操作 HSADC
程序清单 6.2 实现的功能是:读取 AP-283Demo 学习套件的发热电阻温度。
代码执行流程:首先获取用户需要读取数据量。然后打开设备,使用 read 系统调用读
取数据,然后将数据取平均值并转换为温度并打印。
程序清单 6.2 HSADC 操作示例
-
#include <stdio.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <math.h>
-
-
#define R33 2000
-
#define V_ADC 3.3
-
#define T1 (273.15 + 25)
-
#define R1 27600
-
#define B 3435*1000
-
#define HSADC "/dev/mxs-hsadc0"
-
-
int main(int argc,char **argv)
-
{
-
unsigned int buff[100];
-
int i, fd, value = 0, cmd, ret, len = 2;
-
float voltage, RT, temp,tmp;
-
int cnt;
-
-
if(argv[1] == NULL) {
-
printf("uasge: ./hsadc [data length]\n");
-
printf("data length >= 1\n");
-
return 0;
-
}
-
-
fd = open (HSADC,O_RDONLY); /* 打开 ADC 设备 */
-
if (fd < 0) {
-
perror("open");
-
close(fd);
-
return 0;
-
}
-
-
while(1)
-
{
-
usleep(1000000); // 1 second
-
-
cnt = atoi(argv[1])*2;
-
ret = read(fd, buff, cnt); /* 读取 HSADC */
-
printf("ret: %d, cnt: %d\n", ret, cnt);
-
if(ret < 0){
-
perror("ioctl");
-
return -1;
-
}
-
//close(fd);
-
-
ret >>= 1;
-
printf("ret: %d\n", ret);
-
-
for(i = 0; i < ret; i++)
-
{
-
value += (buff[i] & 0xfff);
-
}
-
-
value = value/ret;
-
voltage = (value*1.85)/4096.0; /* 计算通道 1 测量电压 */
-
RT = (V_ADC/voltage - 1)*R33; /* 计算热敏电阻的阻值 */
-
temp = 3435/log(10*RT) - 273.15; /* 计算热敏电阻的温度 */
-
printf("A11 Temperature: %f\n",temp);
-
-
}
-
-
close(fd);
-
-
return 0;
-
}
注意,执行 adc 代码前,必须要加载 mxs-hsadc.ko 模块或内核已经有静态 hsadc 驱动。
驱动路径:/drivers/misc/mxs-hsadc.ko
加载驱动
#insmod mxs-hsadc.ko
可以看到生成的设备文件为:/dev/mxs-hsadc0
编译应用程序:hsadc
# arm-linux-gcc -o hsadc hsadc.c -lm
把编译好的可执行文件 adc 下载到开发板,设置可执行权限。
root@EasyARM-iMX283 ~# chmod 777 hsadc
将 AP-283Dem 配板排针插入 EasyARM-iMX283A 排母, 并使用杜邦线将排母对应的
A1 与 HSADC 短接(就是母排J1的第17脚和第19脚短接), 执行代码。
root@EasyARM-iMX283 ~# ./hsadc 10
执行命令中,数字 10 表示需要读取 10 次采样的平均值。