当前位置: 首页 > news >正文

字符设备驱动实例(ADC驱动)


四、ADC驱动


        ADC是将模拟信号转换为数字信号的转换器,在 Exynos4412 上有一个ADC,其主要的特性如下。
(1)量程为0~1.8V。
(2)精度有 10bit 和 12bit 可选。
(3)采样时钟最高为5MHz,转换速率最高为1MSPS
(4)具有四路模拟输入,同一时刻只有一路进行转换
(5) 转换完成后可以产生中断。

下面是ADC的控制寄存器

下面是延时和数据寄存器 

 下面是中断清除和通道多路复用寄存器

 根据上面的寄存器描述,我们大致可以设计出这个ADC 驱动实现的主要步骤。

(1)初始化 ADC,包括选择精度、设置分频值、设置 ADC 为正常工作模式、设置转换启动方式。
(2)注册ADC中断处理函数。
(3)在上层需要ADC数据时,选择好ADC 通道,启动转换,然后等待一个完成量

(4)转换结束后产生中断,在中断处理函数中获取转换结果值,向 CLRINTADC 寄存器写任意值清除中断,然后唤醒等待完成量的进程。
(5)进程被唤醒,返回转换结果值给上层。
接下来就是要编写ADC的设备树节点,代码如下。

adc@126C0000 {compatible = "fs4412,fsadc";reg = <0x126C0000 32>;interrupt-parent = <&combiner>;interrupts = <10 3>;
};


        reg 属性可以查阅芯片手册得到其寄存器地址。在这里比较麻烦的是中断属性的设置。在 Exynos4412中有的中断是直接接入 GIC 中断控制器的,有的中断则是先通过中断组合器(Combiner)将多个中断复合后再接入 GIC 中断控制器的,连接图如图所示。

而ADC中断属于INTG10这一组中断,手册上的描述如图所示


这一组共用一根中断线,中断号如图 所示。

        查阅Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt内核文档可知:对于这种中断的描述,combiner 是其父中断控制器,所以,interrupt-parent 的值为<&combiner>。interrupts 属性的第一个 cell是中断在组合器中的组号,第二个cell是中断在该组中的序号。

        在FS4412日标板上有一个电位器的抽头接在了AIN3通道上原理图如图所示
图ADC电路图


        接下来就是驱动的实现,主要代码如下
 

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>#include <linux/fs.h>
#include <linux/cdev.h>#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/uaccess.h>#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>#include <linux/of.h>
#include <linux/interrupt.h>#include "fsadc.h"#define FSADC_MAJOR	256
#define FSADC_MINOR	6
#define FSADC_DEV_NAME	"fsadc"struct fsadc_dev {unsigned int __iomem *adccon;unsigned int __iomem *adcdat;unsigned int __iomem *clrint;unsigned int __iomem *adcmux;unsigned int adcval;struct completion completion;atomic_t available;unsigned int irq;struct cdev cdev;
};static int fsadc_open(struct inode *inode, struct file *filp)
{struct fsadc_dev *fsadc = container_of(inode->i_cdev, struct fsadc_dev, cdev);filp->private_data = fsadc;if (atomic_dec_and_test(&fsadc->available))return 0;else {atomic_inc(&fsadc->available);return -EBUSY;}
}static int fsadc_release(struct inode *inode, struct file *filp)
{struct fsadc_dev *fsadc = filp->private_data;atomic_inc(&fsadc->available);return 0;
}static long fsadc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{struct fsadc_dev *fsadc = filp->private_data;union chan_val cv;if (_IOC_TYPE(cmd) != FSADC_MAGIC)return -ENOTTY;switch (cmd) {case FSADC_GET_VAL:if (copy_from_user(&cv, (union chan_val __user *)arg, sizeof(union chan_val)))return -EFAULT;if (cv.chan > AIN3)return -ENOTTY;writel(cv.chan, fsadc->adcmux);writel(readl(fsadc->adccon) | 1, fsadc->adccon);if (wait_for_completion_interruptible(&fsadc->completion))return -ERESTARTSYS;cv.val = fsadc->adcval & 0xFFF;if (copy_to_user( (union chan_val __user *)arg, &cv, sizeof(union chan_val)))return -EFAULT;break;default:return -ENOTTY;}return 0;
}static irqreturn_t fsadc_isr(int irq, void *dev_id)
{struct fsadc_dev *fsadc = dev_id;fsadc->adcval = readl(fsadc->adcdat);writel(1, fsadc->clrint);complete(&fsadc->completion);return IRQ_HANDLED;
}static struct file_operations fsadc_ops = {.owner = THIS_MODULE,.open = fsadc_open,.release = fsadc_release,.unlocked_ioctl = fsadc_ioctl,
};static int fsadc_probe(struct platform_device *pdev)
{int ret;dev_t dev;struct fsadc_dev *fsadc;struct resource *res;dev = MKDEV(FSADC_MAJOR, FSADC_MINOR);ret = register_chrdev_region(dev, 1, FSADC_DEV_NAME);if (ret)goto reg_err;fsadc = kzalloc(sizeof(struct fsadc_dev), GFP_KERNEL);if (!fsadc) {ret = -ENOMEM;goto mem_err;}platform_set_drvdata(pdev, fsadc);cdev_init(&fsadc->cdev, &fsadc_ops);fsadc->cdev.owner = THIS_MODULE;ret = cdev_add(&fsadc->cdev, dev, 1);if (ret)goto add_err;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (!res) {ret = -ENOENT;goto res_err;}fsadc->adccon = ioremap(res->start, resource_size(res));if (!fsadc->adccon) {ret = -EBUSY;goto map_err;}fsadc->adcdat = fsadc->adccon + 3;fsadc->clrint = fsadc->adccon + 6;fsadc->adcmux = fsadc->adccon + 7;fsadc->irq = platform_get_irq(pdev, 0);if (fsadc->irq < 0) {ret = fsadc->irq;goto irq_err;}ret = request_irq(fsadc->irq, fsadc_isr, 0, "adc", fsadc);if (ret)goto irq_err;writel((1 << 16) | (1 << 14) | (19 << 6), fsadc->adccon);init_completion(&fsadc->completion);atomic_set(&fsadc->available, 1);return 0;
irq_err:iounmap(fsadc->adccon);
map_err:
res_err:cdev_del(&fsadc->cdev);
add_err:kfree(fsadc);
mem_err:unregister_chrdev_region(dev, 1);
reg_err:return ret;
}static int fsadc_remove(struct platform_device *pdev)
{dev_t dev;struct fsadc_dev *fsadc = platform_get_drvdata(pdev);dev = MKDEV(FSADC_MAJOR, FSADC_MINOR);writel((readl(fsadc->adccon) & ~(1 << 16)) | (1 << 2), fsadc->adccon);free_irq(fsadc->irq, fsadc);iounmap(fsadc->adccon);cdev_del(&fsadc->cdev);kfree(fsadc);unregister_chrdev_region(dev, 1);return 0;
}static const struct of_device_id fsadc_of_matches[] = {{ .compatible = "fs4412,fsadc", },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, fsadc_of_matches);struct platform_driver fsadc_drv = { .driver = { .name    = "fsadc",.owner   = THIS_MODULE,.of_match_table = of_match_ptr(fsadc_of_matches),},  .probe   = fsadc_probe,.remove  = fsadc_remove,
};module_platform_driver(fsadc_drv);MODULE_LICENSE("GPL");
MODULE_AUTHOR("name <e-mail>");
MODULE_DESCRIPTION("ADC driver");

 

#ifndef _FSADC_H
#define _FSADC_H#define FSADC_MAGIC	'f'union chan_val {unsigned int chan;unsigned int val;
};#define FSADC_GET_VAL	_IOWR(FSADC_MAGIC, 0, union chan_val)#define AIN0	0
#define AIN1	1
#define AIN2	2
#define AIN3	3#endif


        代码第 26 行至第 29 行是各寄存器的指针。代码第 32 行是用于保存采样(转换)结果的变量。代码第32 行是用于同步采结束的完成量。
        在fsadc_probe 函数中,与字符设备相关的代码和前面基本一样,接下来就是资源的获取、IO 内存的映射、中断的获取和中断处理函数的注册。然后就是初始化 ADC,将ADCCON 寄存器的第 16 位和第 14 位置 1,表示采样精度为 12位,使能预分频。并且预分配值设为19,即为20分频,这是因为在 U-Boot 中,我们将 APB 的时钟设为了100MHz。最后没有设置读启动位,也就意味着,采样的启动是靠 ADCCON 寄存器的比特0来控制的。
        fsadc_ioctl 函数是处理采样的关键函数,这里用到了自定义的一个联合体 unionchan_val,它的定义如下。

union chan_val {unsigned int chan;unsigned int val;
};


        有两个成员分别是 chan 和 val。命令 FSADC_GET_VAL 是读写类型的,在应用层往驱动层的传递过程中传递的是要使用的ADC通道chan,在驱动层往应用层传递的过程中传递的是得到的采样值 val。代码第 69 行至第72行先从应用层得到通道号,然后代码第73行将通道号写入到ADCMUX 寄存器中,接下来将ADCCON 寄存器的比特0置1启动采样,最后就调用wait_for_completion_interruptible 来等待完成量。当采样完成时,中断处理函数自动被调用,代码第 92 行先读取了转换结果值寄存器 ADCDAT,然后将 1写入 CLRINT 寄存器中,清除中断,最后唤醒等待完成量的进程。进程被唤醒后,代码第77行和第78 行得到采样值,并返回给上层。
        测试代码如下。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>#include "fsadc.h"int main(int argc, char *argv[])
{int fd;int ret;union chan_val cv;fd = open("/dev/adc", O_RDWR);if (fd == -1)goto fail;while (1) {cv.chan = 3;ret = ioctl(fd, FSADC_GET_VAL, &cv);if (ret == -1)goto fail;printf("current volatage is: %.2fV\n", 1.8 * cv.val / 4095.0);sleep(1);}
fail:perror("adc test");exit(EXIT_FAILURE);
}


将数字值转换为对应的模拟值使用了下面的表达式

1.8 * cv.val  /  4095.0


        1.8 是满量程的电压,4095.0 是满量程时对应的数字值(因为是 12位),cv.val 是采样得到的数字,用1.8 乘以采样值和满量程数字值之比就能得到当前的电压编译和测试的命令如下,旋转电位器旋钮可以看到电压变化。

 

新网线就是丝滑,之前还会突然断开。 

相关文章:

字符设备驱动实例(ADC驱动)

四、ADC驱动 ADC是将模拟信号转换为数字信号的转换器&#xff0c;在 Exynos4412 上有一个ADC&#xff0c;其主要的特性如下。 (1)量程为0~1.8V。 (2)精度有 10bit 和 12bit 可选。 (3)采样时钟最高为5MHz&#xff0c;转换速率最高为1MSPS (4)具有四路模拟输入&#xff0c;同一时…...

python基础5——正则、数据库操作

文章目录 一、数据库编程1.1 connect()函数1.2 命令参数1.3 常用语句 二、正则表达式2.1 匹配方式2.2 字符匹配2.3 数量匹配2.4 边界匹配2.5 分组匹配2.6 贪婪模式&非贪婪模式2.7 标志位 一、数据库编程 可以使用python脚本对数据库进行操作&#xff0c;比如获取数据库数据…...

SpringAOP原理:手写动态代理实现

0、基础知识 AOP我们知道&#xff0c;是在不修改源代码的情况下&#xff0c;为代码添加一些新功能的技术。通过动态代理&#xff0c;可以在不修改原始类代码的前提下&#xff0c;对方法进行拦截和增强。 动态代理常用于在不改变原有业务逻辑的情况下&#xff0c;对方法…...

【旅游度假】Axure酒店在线预订APP原型图 旅游度假子模块原型模板

作品概况 页面数量&#xff1a;共 10 页 兼容软件&#xff1a;Axure RP 9/10&#xff0c;不支持低版本 应用领域&#xff1a;旅游度假&#xff0c;生活服务 作品申明&#xff1a;页面内容仅用于功能演示&#xff0c;无实际功能 作品特色 本作品为「酒店在线预订」的移动端…...

Android JNI系列详解之CMake和ndk-build编译工具介绍

一、前提 CMake和ndk-build只是编译工具&#xff0c;本次主要介绍ndk-build和CMake的区别&#xff0c;下节课介绍他们的使用。 二、CMake工具介绍 CMake&#xff1a;cross platform make&#xff0c;是跨平台的编译工具 CMake是在AndroidStudio2.2之后引入&#xff08;目前默认…...

【Linux取经路】解析环境变量,提升系统控制力

文章目录 一、进程优先级1.1 什么是优先级&#xff1f;1.2 为什么会有优先级&#xff1f;1.3 小结 二、Linux系统中的优先级2.1 查看进程优先级2.2 PRI and NI2.3 修改进程优先级2.4 进程优先级的实现原理2.5 一些名词解释 三、环境变量3.1 基本概念3.2 PATH&#xff1a;Linux系…...

TCP编程流程(补充)

目录 1、listen&#xff1a; 2、listen、tcp三次握手 3、 发送缓冲区和接收缓冲区&#xff1a; 4、tcp编程启用多线程 1、listen&#xff1a; 执行listen会创建一个监听队列 listen(sockfd,5) 2、listen、tcp三次握手 三次握手 3、 发送缓冲区和接收缓冲区&#xff1a;…...

每天一道leetcode:433. 最小基因变化(图论中等广度优先遍历)

今日份题目&#xff1a; 基因序列可以表示为一条由 8 个字符组成的字符串&#xff0c;其中每个字符都是 A、C、G 和 T 之一。 假设我们需要调查从基因序列 start 变为 end 所发生的基因变化。一次基因变化就意味着这个基因序列中的一个字符发生了变化。 例如&#xff0c;&quo…...

【C++】做一个飞机空战小游戏(十)——子弹击落炮弹、炮弹与飞机相撞

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动【C】做一个飞机空战小游戏(三)——getch()函数控制任意造型飞机图标移动 【C】做一个飞…...

去除UI切图边缘上多余的线条

最近接到UI切图&#xff0c;放进项目&#xff0c;显示边缘有多余线条&#xff0c;影响UI美观。开始以为切图没切好&#xff0c;实则不是。如图&#xff1a; ->解决&#xff1a; 将该图片资源WrapMode改为Clamp...

Spring高手之路13——BeanFactoryPostProcessor与BeanDefinitionRegistryPostProcessor解析

文章目录 1. BeanFactoryPostProcessor 概览1.1 解读 BeanFactoryPostProcessor1.2. 如何使用 BeanFactoryPostProcessor 2. BeanDefinitionRegistryPostProcessor 深入探究2.1 解读 BeanDefinitionRegistryPostProcessor2.2 BeanDefinitionRegistryPostProcessor 的执行时机2.…...

【LeetCode动态规划】详解买卖票I~IV,经典dp题型买

给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…...

【深入探究人工智能】:常见机器学习算法总结

文章目录 1、前言1.1 机器学习算法的两步骤1.2 机器学习算法分类 2、逻辑回归算法2.1 逻辑函数2.2 逻辑回归可以用于多类分类2.3 逻辑回归中的系数 3、线性回归算法3.1 线性回归的假设3.2 确定线性回归模型的拟合优度3.3线性回归中的异常值处理 4、支持向量机&#xff08;SVM&a…...

设计模式之解释器模式详解及实例

1、解释器设计模式概述&#xff1a; 解释器模式&#xff08;Interpreter Pattern&#xff09;是一种设计模式&#xff0c;它主要用于描述如何构建一个解释器以解释特定的语言或表达式。该模式定义了一个文法表示和解释器的类结构&#xff0c;用于解释符合该文法规则的语句。解…...

Nodejs沙箱逃逸--总结

一、沙箱逃逸概念 JavaScript和Nodejs之间有什么区别&#xff1a;JavaScript用在浏览器前端&#xff0c;后来将Chrome中的v8引擎单独拿出来为JavaScript单独开发了一个运行环境&#xff0c;因此JavaScript也可以作为一门后端语言&#xff0c;写在后端&#xff08;服务端&#…...

No115.精选前端面试题,享受每天的挑战和学习

文章目录 变量提升和函数提升的顺序Event Loop封装 FetchAPI&#xff0c;要求超时报错的同时&#xff0c;取消执行的 promise&#xff08;即不继续执行&#xff09;强缓存和协商缓存的区别token可以放在cookie里吗&#xff1f; 变量提升和函数提升的顺序 在JavaScript中&#…...

Elasticsearch:语义搜索 - Semantic Search in python

当 OpenAI 于 2022 年 11 月发布 ChatGPT 时&#xff0c;引发了人们对人工智能和机器学习的新一波兴趣。 尽管必要的技术创新已经出现了近十年&#xff0c;而且基本原理的历史甚至更早&#xff0c;但这种巨大的转变引发了各种发展的“寒武纪大爆炸”&#xff0c;特别是在大型语…...

Flink学习笔记(一)

流处理 批处理应用于有界数据流的处理&#xff0c;流处理则应用于无界数据流的处理。 有界数据流&#xff1a;输入数据有明确的开始和结束。 无界数据流&#xff1a;输入数据没有明确的开始和结束&#xff0c;或者说数据是无限的&#xff0c;数据通常会随着时间变化而更新。 在…...

[Raspberry Pi]如何用VNC遠端控制樹莓派(Ubuntu desktop 23.04)?

之前曾利用VMware探索CentOS&#xff0c;熟悉Linux操作系統的指令和配置運作方式&#xff0c;後來在樹莓派價格飛漲的時期&#xff0c;遇到貴人贈送Raspberry Pi 4 model B / 8GB&#xff0c;這下工具到位了&#xff0c;索性跳過樹莓派官方系統(Raspberry Pi OS)&#xff0c;直…...

17.HPA和rancher

文章目录 HPA部署 metrics-server部署HPA Rancher部署Rancherrancher添加集群仪表盘创建 namespace仪表盘创建 Deployments仪表盘创建 service 总结 HPA HPA&#xff08;Horizontal Pod Autoscaling&#xff09;Pod 水平自动伸缩&#xff0c;Kubernetes 有一个 HPA 的资源&…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

STM32标准库-DMA直接存储器存取

文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...