本章节介绍 GK7206 的 ADC(模数转换器)采集应用示例 —— sample_lsadc。该应用演示了通过 /dev/lsadc 设备节点读取 ADC 通道数据的功能,支持单步扫描和连续扫描两种工作模式。
应用源码位于 SDK 目录 sample/lsadc/,是一个简单的硬件外设访问示例,展示了如何通过 Linux 字符设备接口与硬件驱动交互。
| 参数 | 值 |
|---|---|
设备节点 |
/dev/lsadc |
扫描模式 |
单步扫描、连续扫描 |
采样间隔 |
1 秒(可调整) |
采集次数 |
20 次(默认) |
内存占用 |
极小 |
内核模块 |
需加载 xm_lsadc.ko |
sample/lsadc/
├── Makefile # 构建脚本
└── sample_lsadc.c # 主程序
在编译本应用之前,请确保已完成以下准备工作:
xm_lsadc.ko 模块# 进入 sample 目录
cd <SDK_PATH>/sample
# lsadc 不在顶层 objects,需单独编译
make -C lsadc clean && make -C lsadc
提示
lsadc 示例不在顶层 Makefile 的
objects列表中,需要单独编译。
# 使用 SCP 传输到开发板
scp sample/lsadc/sample_lsadc root@<板端IP>:/tmp/
# 或通过 TFTP 下载
tftp -g -r sample_lsadc <板端IP>
相关信息
由于本应用体积很小,可以直接放在
/tmp运行。
# 添加执行权限
chmod +x /tmp/sample_lsadc
# 加载内核模块(首次运行需要)
insmod /opt/ko/xm_lsadc.ko
# 运行应用(交互式)
./sample_lsadc
=============== LSADC TEST ===============
0:single step scan mode
1:continuous scan mode
please select the mode:
选择通道后:
please select the channel:
0
get value:1234,chn[0]
get value:1235,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
预期现象:
get value:<ADC值>,chn[<通道>]usleep(1000*1000))选择通道后:
please select the channel:
0
get value:1234,chn[0]
get value:1235,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
预期现象:
get value:<ADC值>,chn[<通道>]Ctrl+C 强制退出fail to open file:/dev/lsadc
原因:xm_lsadc.ko 内核模块未加载 解决:insmod /opt/ko/xm_lsadc.ko
adc model select error.
原因:模式参数无效 解决:确保输入 0 或 1
please select the mode: 0
please select the channel: 0
get value:1234,chn[0]
get value:1235,chn[0]
...
please select the mode: 1
please select the channel: 0
get value:1234,chn[0]
get value:1235,chn[0]
...
本应用采用简单的交互式架构:
int main(void)
{
int mode, chn;
// 显示菜单
printf("=============== LSADC TEST ===============\n");
printf("0:single step scan mode\n");
printf("1:continuous scan mode\n");
printf("please select the mode:\n");
// 获取用户输入
scanf("%d", &mode);
// 根据 mode 选择扫描模式
switch(mode) {
case 0:
printf("please select the channel:\n");
scanf("%d", &chn);
sample_lsadc_single_step_scan_mode(mode, chn);
break;
case 1:
printf("please select the channel:\n");
scanf("%d", &chn);
sample_lsadc_continuous_scan_mode(mode, chn);
break;
default:
printf("invalid mode\n");
break;
}
return 0;
}
单步扫描模式每次采集需要启动→获取→停止的完整流程:
xmedia_s32 sample_lsadc_single_step_scan_mode(lsadc_scan_mode mode, xmedia_s32 chn)
{
int i, value;
int fd = open(DEV_FILE, O_RDWR); // 打开 /dev/lsadc
if (fd < 0) {
fprintf(stderr, "fail to open file:%s\n", DEV_FILE);
return -1;
}
// 选择扫描模式
if(ioctl(fd, LSADC_IOC_MODEL_SEL, &mode) < 0) {
fprintf(stderr, "adc model select error.\n");
goto exit;
}
// 使能通道
if(ioctl(fd, LSADC_IOC_CHN_ENABLE, &chn) < 0) {
fprintf(stderr, "enable chn %d error.\n", chn);
goto exit;
}
// 循环采集 20 次
for(i = 0; i < 20; i++) {
// 启动 ADC
if(ioctl(fd, LSADC_IOC_START) < 0) {
fprintf(stderr, "start lsadc error.\n");
goto exit;
}
// 获取通道值
value = ioctl(fd, LSADC_IOC_GET_CHNVAL, &chn);
printf("get value:%d,chn[%d]\n", value, chn);
usleep(1000 * 1000); // 等待 1 秒
// 停止 ADC
if(ioctl(fd, LSADC_IOC_STOP) < 0) {
fprintf(stderr, "stop lsadc error.\n");
}
}
exit:
// 清理资源
if(ioctl(fd, LSADC_IOC_STOP) < 0) {
fprintf(stderr, "stop lsadc error.\n");
}
if(ioctl(fd, LSADC_IOC_CHN_DISABLE, &chn) < 0) {
fprintf(stderr, "disable chn %d error.\n", chn);
}
close(fd);
return 0;
}
连续扫描模式只需启动一次,然后持续获取数据:
xmedia_s32 sample_lsadc_continuous_scan_mode(lsadc_scan_mode mode, xmedia_s32 chn)
{
int i, value;
int fd = open(DEV_FILE, O_RDWR);
if (fd < 0) {
fprintf(stderr, "fail to open file:%s\n", DEV_FILE);
return -1;
}
// 选择扫描模式
if(ioctl(fd, LSADC_IOC_MODEL_SEL, &mode) < 0) {
fprintf(stderr, "adc model select error.\n");
goto exit;
}
// 使能通道
if(ioctl(fd, LSADC_IOC_CHN_ENABLE, &chn) < 0) {
fprintf(stderr, "enable chn %d error.\n", chn);
goto exit;
}
// 启动 ADC(只启动一次)
if(ioctl(fd, LSADC_IOC_START) < 0) {
fprintf(stderr, "start lsadc error.\n");
goto exit;
}
// 循环获取数据
for(i = 0; i < 20; i++) {
value = ioctl(fd, LSADC_IOC_GET_CHNVAL, &chn);
printf("get value:%d,chn[%d]\n", value, chn);
usleep(1000 * 1000); // 等待 1 秒
}
exit:
// 清理资源
if(ioctl(fd, LSADC_IOC_STOP) < 0) {
fprintf(stderr, "stop lsadc error.\n");
}
if(ioctl(fd, LSADC_IOC_CHN_DISABLE, &chn) < 0) {
fprintf(stderr, "disable chn %d error.\n", chn);
}
close(fd);
return 0;
}
应用使用以下 IOCTL 命令与驱动交互:
| 命令 | 功能 | 参数 |
|---|---|---|
LSADC_IOC_MODEL_SEL |
选择扫描模式 | 0=单步,1=连续 |
LSADC_IOC_CHN_ENABLE |
使能通道 | 通道号 |
LSADC_IOC_CHN_DISABLE |
禁用通道 | 通道号 |
LSADC_IOC_START |
启动 ADC | 无 |
LSADC_IOC_STOP |
停止 ADC | 无 |
LSADC_IOC_GET_CHNVAL |
获取通道值 | 通道号 |
ADC 返回的值是一个整数,范围通常在 0~4095 之间(12 位 ADC)。该值与输入电压成正比:
电压 = (ADC值 / 4095) × 参考电压
例如,如果参考电压为 3.3V,ADC 值为 2048,则输入电压约为:
电压 = (2048 / 4095) × 3.3V ≈ 1.65V
Linux 字符设备的标准操作模式:
// 打开设备
int fd = open("/dev/lsadc", O_RDWR);
// IOCTL 控制
ioctl(fd, LSADC_IOC_MODEL_SEL, &mode);
// 关闭设备
close(fd);
每个 IOCTL 调用都应检查返回值:
if(ioctl(fd, LSADC_IOC_START) < 0) {
fprintf(stderr, "start lsadc error.\n");
goto exit; // 跳转到清理代码
}
使用 goto 进行统一的资源清理:
exit:
// 禁用通道
if(ioctl(fd, LSADC_IOC_CHN_DISABLE, &chn) < 0) {
fprintf(stderr, "disable chn %d error.\n", chn);
}
// 关闭设备
close(fd);
return 0;
}
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
fail to open file:/dev/lsadc |
设备节点不存在 | 检查 xm_lsadc.ko 模块是否加载 |
adc model select error |
模式参数无效 | 检查 mode 是否为 0 或 1 |
enable chn X error |
通道号无效 | 检查通道号是否在有效范围内 |
| ADC 值始终为 0 | 输入未连接或电压过低 | 检查硬件连接 |
| ADC 值始终为 4095 | 输入电压过高或超过参考电压 | 检查输入电压范围 |