ADC_驱动

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情
 
嵌入式 linux 驱动 ADC驱动
[ 2011-1-10 13:18:00 | By: Eddy ]
 

  很懒,很久没去总结学习的东西,今天就总结下linux下的AD驱动吧,AD驱动理解的难点和注意的地方其实就只有两点。

一、虚拟地址的应用,就是物理地址转换为虚拟地址,ADC驱动程序中的寄存器就是都用      到了虚拟地址了。其中最主要的转换的语句是

base_addr=ioremap(S3C2410_PA_ADC,0x20);/

ioremap()功能: 将一个IO地址空间映射到内核的虚拟地址空间上去,返回值就是虚拟地址。  物理地址和虚拟地址的转换,就是将S3C2410_PA_ADC物理地址转换为base_addr 的地址。 S3C2410_PA_ADC 为物理地址0x58000000 ,具体也不知在那个文件能找到 。base_addr 虚拟地址,应该是有系统分配的,调用ioremap()既能分配到。

而base_addr 的定义是 static void __iomem *base_addr;

使用完后需要 iounmap(base_addr);释放掉虚拟地址。

二、时钟CLK的调用,用ADC需要用到CLK时钟,主要有已下几个函数:

clk_get
clk_use()
clk_enable()

这几个 函数的使用,当然再最后也要卸载掉,其函数如下

  clk_disable(adc_clock);
  clk_put(adc_clock);
  adc_clock = NULL;
 }

还有可以参考如下网页

http://www.unixresources.net/linux/clf/driver/archive/00/00/65/81/658138.html

http://hi.baidu.com/mystreetzone/blog/item/f36fca35d373001690ef39a7.html

最后附上具体程序
#i nclude <linux/errno.h>
#i nclude <linux/kernel.h>
#i nclude <linux/module.h>
#i nclude <linux/slab.h>
#i nclude <linux/input.h>
#i nclude <linux/init.h>
#i nclude <linux/serio.h>
#i nclude <linux/delay.h>
#i nclude <linux/clk.h>
#i nclude <asm/io.h>
#i nclude <asm/irq.h>
#i nclude <asm/uaccess.h>
#i nclude <mach/regs-clock.h>
#i nclude <plat/regs-timer.h>
 
#i nclude <plat/regs-adc.h>
#i nclude <mach/regs-gpio.h>
#i nclude <linux/cdev.h>
#i nclude <linux/miscdevice.h>

#i nclude "s3c24xx-adc.h"

#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) {printk(____"(%d): ",__LINE__);printk(##x);}
#else
#define DPRINTK(x...) (void)(0)
#endif

#define DEVICE_NAME "adc"

static void __iomem *base_addr;

typedef struct {
 wait_queue_head_t wait;
 int channel;
 int prescale;
}ADC_DEV;

DECLARE_MUTEX(ADC_LOCK);
static int OwnADC = 0;

static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;

static struct clk *adc_clock;

#define ADCCON      (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON)) //ADC control
#define ADCTSC      (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC)) //ADC touch screen control
#define ADCDLY      (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY)) //ADC start or Interval Delay
#define ADCDAT0     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0)) //ADC conversion data 0
#define ADCDAT1     (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1)) //ADC conversion data 1
#define ADCUPDN     (*(volatile unsigned long *)(base_addr + 0x14)) //Stylus Up/Down interrupt status

#define PRESCALE_DIS        (0 << 14)
#define PRESCALE_EN         (1 << 14)
#define PRSCVL(x)           ((x) << 6)
#define ADC_INPUT(x)        ((x) << 3)
#define ADC_START           (1 << 0)
#define ADC_ENDCVT          (1 << 15)

#define START_ADC_AIN(ch, prescale) \
 do{ \
  ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
  ADCCON |= ADC_START; \
 }while(0)


static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
 if (OwnADC) {
  adc_data = ADCDAT0 & 0x3ff;

  ev_adc = 1;
  wake_up_interruptible(&adcdev.wait);
 }

 return IRQ_HANDLED;
}

static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
 char str[20];
 int value;
 size_t len;
 if (down_trylock(&ADC_LOCK) == 0) {
  OwnADC = 1;
  START_ADC_AIN(adcdev.channel, adcdev.prescale);
  wait_event_interruptible(adcdev.wait, ev_adc);

  ev_adc = 0;

  DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);

  value = adc_data;
  sprintf(str,"%5d", adc_data);
  copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data));

  OwnADC = 0;
  up(&ADC_LOCK);
 } else {
  value = -1;
 }

 len = sprintf(str, "%d\n", value);
 if (count >= len) {
  int r = copy_to_user(buffer, str, len);
  return r ? r : len;
 } else {
  return -EINVAL;
 }
}

static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
 init_waitqueue_head(&(adcdev.wait));

 adcdev.channel=0;
 adcdev.prescale=0xff;

 DPRINTK( "adc opened\n");
 return 0;
}

static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
 DPRINTK( "adc closed\n");
 return 0;
}


static struct file_operations dev_fops = {
 owner: THIS_MODULE,
 open: s3c2410_adc_open,
 read: s3c2410_adc_read, 
 release: s3c2410_adc_release,
};

static struct miscdevice misc = {
 .minor = MISC_DYNAMIC_MINOR,
 .name = DEVICE_NAME,
 .fops = &dev_fops,
};

static int __init dev_init(void)
{
 int ret;

 base_addr=ioremap(S3C2410_PA_ADC,0x20);//功能: 将一个IO地址空间映射到内核的虚拟地址空间上去,便于访问;
 /*
  物理地址和虚拟地址的转换,就是将S3C2410_PA_ADC物理地址转换为base_addr 的地址
  S3C2410_PA_ADC 为物理地址0x58000000 ,具体也不知在那个文件能找到
  base_addr 虚拟地址,应该是有系统分配的,调用ioremap()既能分配到
 

 

 */
 if (base_addr == NULL) {
  printk(KERN_ERR "Failed to remap register block\n");
  return -ENOMEM;
 }

 adc_clock = clk_get(NULL, "adc");
 if (!adc_clock) {
  printk(KERN_ERR "failed to get adc clock source\n");
  return -ENOENT;
 }
 clk_enable(adc_clock);
 //用AD 需要打开CLK
 //既需要这两个函数clk_get()   clk_enable(adc_clock);

 /* normal ADC */
 ADCTSC = 0;

 ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
 if (ret) {
  iounmap(base_addr);
  return ret;
 }

 ret = misc_register(&misc);

 printk (DEVICE_NAME"\tinitialized\n");
 return ret;
}

static void __exit dev_exit(void)
{
 free_irq(IRQ_ADC, &adcdev);
 iounmap(base_addr);

 if (adc_clock) {
  clk_disable(adc_clock);
  clk_put(adc_clock);
  adc_clock = NULL;
 }

 misc_deregister(&misc);
}

EXPORT_SYMBOL(ADC_LOCK);
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");

浅谈ADC驱动设计 在上一小节中,应用电路中出现单变压器和双变压器的电路,对于变压器(巴伦)本身,其自身的相位不平衡和幅度不平衡是一直存在的,由于这些不平衡的因素,变压器(巴伦)的输出端上会产生一些非线性变化,尤其是二次和三次谐波最为明显,其中影响最大的是三次谐波(相位不平衡导致的),这会直接影响到系统。,但是很遗憾,对于变压器(巴伦),相位及幅度是不平衡的,这是变压器的工艺所决定的,无法本质上消除,相位及幅度不平衡对输出信号的影响,主要体现在谐波抑制的性能上,同时相位不平衡影响是最大的,关于相位及幅度不平衡将在“浅谈。 阅读详情

相关推荐

TLC549ADC驱动的FPGA实现

1.引言与相关资料 TLC549是一款8位串行ADC,其采样速率不高,精度也只有8位,但不需要对其进行任何控制就可以自动的进行ADC的工作,需要做的只是在适当的时机按串行方式读出8位AD值就可以。 理论上这款ADC性能其实不咋地,局限性也很大,不过是我购买的FPGA开发板上自带的一款ADC,后续有个设计需要用到它进行AD采样。 相关资料百度上可以找到一篇关于TLC549中文资料。以下是链

shen_you的博客 5341

AD7888与S3C2410的SPI接口及Linux下嵌入式驱动的实现

串行外围设备接口SPI(serial peripheral interface)总线技术是Motorola公司推出的一种同步串行接口,它允许CPU与TTL移位寄存器、A/D或D/A转换器、实时时钟(RTO)、存储器以及LCD和LED显示驱动器等外围接口器件以串行方式进行通讯。   SPI总线只需3~4根数据线和控制线即可扩展具有SPI接口的各种I/O器件,其硬件功能很强,实现软件相当简单。串行A/D转换器具有电路简单、工作可靠的特点,而ARM芯片被设计用于手持设备以及普通的嵌人式应用的集成系统,将上述两种实用的芯片和SPI总线技术相结合以实现数据采集十分有效。   1 AD7888的功能

Linux ARM平台开发系列讲解(ADC) 2.9.1 ADC驱动详解

上一章我们讲解了如何编写 驱动驱动也是 驱动框架的。本节我们就来学习一下如何使用内部的 ,并且在学习巩固一下 驱动。以 内部为例。 S32G274A 中各个设备树属性的含义为下:除上述外,一些常见的芯片的adc设备树可能还包含以下属性节点:驱动入口主要是匹配设备信息,将设备信息传入和函数中 3.2 驱动入口 驱动主要是函数里注册和分配的,包括驱动注册,设备初始化和读写函数封装,具体如下: 4. 源码 下面是内部源码,可以参考分析 返回总目录............

DSMGUOGUO的博客 1669

Linux 驱动实例 (ADC/PWM/RTC)

这包括引脚的复用(即一个物理引脚可能有多种不同的功能,例如用作GPIO、用作I2C数据线,等等),以及引脚的配置(如设置为输入或输出,上拉或下拉电阻等)。Pinctrl(Pin control)则是更为底层和全面的引脚管理和控制,它主要用于配置引脚的属性和功能,例如,将某个引脚设置为GPIO、设置为其他特定功能(如UART、SPI等)、配置上拉或下拉电阻等。最后,释放资源并关闭设备。因此,更准确的说法可能是,“pinctrl接口用于管理系统中引脚的状态,包括GPIO的功能、电气属性以及复用配置等”。

a1105778208的博客 1149

嵌入式 linux 驱动 ADC驱动

很懒,很久没去总结学习的东西,今天就总结下linux下的AD驱动吧,AD驱动理解的难点和注意的地方其实就只有两点。 一、虚拟地址的应用,就是物理地址转换为虚拟地址,ADC驱动程序中的寄存器就是都用到了虚拟地址了。其中最主要的转换的语句是 base_addr=ioremap(S3C2410_PA_ADC,0x20);/ ioremap()功能: 将一个IO地址空间映射到内核的虚拟地址空间上去,

见习馒头 1245

linux下ad数模转换驱动程序设计,基于Linux-2.6.16的高速模数转换器AD7859L的应用...

1 引言在嵌入式系统中基于ARM微核的嵌入式处理器已经成为市场主流。随着ARM技术的广泛应用,建立面向ARM构架的嵌入式操作系统成为测量行业的热点问题。在LINUX操作系统中添加新的外部设备时,只需为其添加对应的驱动程序即可。介绍另一种驱动程序的编写方式,即采用MISC类设备。其实质也是一个字符设备。可将用户各种不同的驱动设备类型合成到一种类型中,共用一个主设备号,通过不同的次设备号和设备节点名来...

weixin_39901358的博客 551

Linux-ADC驱动实验

节点更为详细的信息请参考对应的绑定文档: Documentation/devicetree/bindings/iio/adc/vf610-adc.txt。接下来我们简单分析一下绑定文档,后 面我们需要根据绑定文档修改设备树,使能 ADC驱动核心文件,这个文件就是 drivers/iio/adc/vf610_adc.c。编译修改后的设备树,然后使用新的设备树启动系统。就是在上一章的应用程序上修改而来的,由于只读取一路。已经编写好了,我们只需要修改设备树即可。设备目录,查看一下都对应的是什么设备。

qq_28576837的博客 1571

STM32MP157驱动开发——Linux ADC驱动

本节介绍STM32MP157内部的ADC驱动开发,使用其读取输入电压并打印。解析了内部的ADC驱动的IIO框架使用。

weixin_45682654的博客 2476

Linux 驱动编写之ADC驱动编写配置

简介 纯粹的 ADC 驱动也是 IIO 驱动框架,如果需要自己编写ADC驱动,其实就是按照IIO的驱动框架进行相关实现。 IMX6ULL 的ADC驱动设备树配置 I.MX6ULL 有 2 个 ADC,但是对应一个 ADC 控制器。目前使用 GPIO1_IO01 这个ADC1 的通道 1 引脚来进行配置。 关 于 I.MX6ULL 的 ADC 节 点 更 为 详 细 的 信 息 请 参 考 对 应 的 绑 定 文 档 :Documentation/devicetree/bindings/iio/adc/vf6

路过的熊的博客 4937

linux 混杂设备驱动adc驱动

linux2.6.30.4中,系统已经自带有了ADC通用驱动文件---arch/arm/plat-s3c24xx/adc.c,它是以平台驱动设备模型的架构来编写的,里面是一些比较通用稳定的代码,但是linux2.6.30.4版本的ADC通用驱动文件并不完善,居然没有读函数。后来去看了linux3.8版本的ADC通用文件----arch/arm/plat-samsung/adc.c才是比较完善的。

lwj103862095的专栏 1万+

【RTT驱动框架分析07】- adc驱动框架分析+adc中断唤醒adc驱动

实现了adc注册功能,在注册函数内部初始化io口,时钟,adc使能标定实现了adc的单通道采集功能即 convert 函数实现使能函数没有做什么工作,仅仅做了个通道的有效性判定。

Car12 609

ADC 驱动分析

一,ADC原理 ADC,模数转换器,将模拟量转换成数字量,采样,保持电路与AD转换器集成在一起。AD转换器模拟输入信号是直流电压信号,0~3.3V之间。S3C2440有8路模拟输入信号,AD转换器内部有一个模拟多路选择器,某一时刻只能将一路模拟输入信号,通过模拟多路选择器接通进行AD转换,而其他路模拟输入信号被断开。 片内ADC电路 ADC转换电路 模块图 XP,XM,Y

manchestermi的博客 1360

Linux驱动---ADC驱动

ADC驱动,读取电路的电流和电压值

weixin_44254079的博客 1640

关于小梅哥ADC128S022驱动设计的思考

此篇文章,主要讲述经过视频点拨后自己动手写adc_driver代码所遇到的若干问题。 并且, 希望我能够把技术讲成故事。 开始吧。 文章目录开篇,ADC时序分析轻触开关变琴键开关想成为脉冲的conv_done信号被卡住的en_conv两个主要问题轻触开关转琴键开关 开篇,ADC时序分析 以德州仪器的ADC128S022作为ADC器件,其操作时序图如下: 稍作分析不难发现, 轻触开关变琴键开关...

up up up! 5852

STM32片上驱动 - ADC驱动

基于RT-Thread实现STM32的ADC片上驱动

dxf1971738522的博客 226

samsung ADC 通用驱动

ADC是嵌入式产品常用的设备,它的驱动并不是很难,但是如果有多个这类设备的话,就得考虑ADC中断共享的问题了,这样反而是驱动变得较复杂,且不易控制。在2.6.29内核后在arch/arm/plat-samsung目录下加入了adc.c这个代码,这是一个通用adc驱动代码。这个代码用来初始化adc设备并构建了一个客户请求列表,用来接受客户请求转换数据。 下面这个结构体用来描述adc设备

caozhongm的专栏 841

ADC前端驱动电路

输入范围调整 任何一个ADC,都有输入电压范围。当实际输入电压超出此范围,将引起ADC转换失效。而被转换的信号,并不能保证在此范围内,这就需要ADC驱动电路将其调整到合适的范围之内。 输入类型转换 原始输入信号的输出类型有两种:单端型、差分型,而ADC的输入类型有三种:单端型、全差分型和伪差分型。如果两者不一致,会影响ADC性能发挥。这就需要类型转换电路。将信号类型演变成与ADC一致的类型。...

yuechifanfan的博客 5863

LINUX下ADC按键驱动程序

ADC按键驱动 Adc键盘原理图如下,将串联电阻之间分别用按键引出来与地相连,当按键按下时端电压会发生改变。基本思想是在ADC驱动基础上,对采样电压进行判断,检测是哪一个按键按下。 1.      ADC驱动分析 在init()函数中,首先获取adc的时钟,并用clk_enable进行使能,然后使用ioremap将ADC寄存器地址映射到kernel中(内核中对ADC只能使用虚拟地址进行访

feng85016578的博客 7165

ADC驱动

转载:http://blog.csdn.net/woshixingaaa/article/details/6429002 S3C2440内部ADC结构图:  对于s3c2440来说,实现A/D转换比较简单,主要应用的是ADC控制寄存器ADCCON和ADC转换数据寄存器AD

luzq217的专栏 434
上一篇: ARM_NOR_NAND_启动
下一篇: LM75温度芯片I2C驱动
linuxarmsummary
博客等级 码龄14年 1541粉丝 163原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值