Linux ARM9260 ADC驱动编程
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/arch/gpio.h>
#include <asm/arch/at91_tc.h>
#include <linux/time.h>
#include <linux/suspend.h>
#define ADC_CR 0x00 //Control Register Offset
#define ADC_MR 0x04 //Mode Register Offset
#define ADC_CHER 0x10 //Channel Enable Register Offset
#define ADC_CHDR 0x14 //Channel Disable Register Offset
#define ADC_CHSR 0x18 //Channel Status Register Offset
#define ADC_SR 0x1C //Status Register Offset
#define ADC_LCDR 0x20 //Last Converted Data Register Offset
#define ADC_IER 0x24 //Interrupt Enable Register Offset
#define ADC_IDR 0x28 //Interrupt Disable Register Offset
#define ADC_IMR 0x2C //Interrupt Mask Register Offset
#define ADC_CDR0 0x30 //Channel Data Register 0 Offset
#define ADC_CDR1 0x34 //Channel Data Register 1 Offset
#define ADC_CDR2 0x38 //Channel Data Register 2 Offset
#define ADC_CDR3 0x3C //Channel Data Register 3 Offset
#define CH_EN 0x03 //Channels to Enable
#define CH_DIS 0x0C //Channels to Disable
#define TRGEN 0x00 //Trigger Enable
#define TRGSEL 0x00 //Trigger Select
#define LOWRES 0x01 //Resolution
#define SLEEP_MODE 0x00 //Sleep Mode
#define PRESCAL 0x9 //Prescaler Rate Selection
#define STARTUP 0x7 //Start Up Time
#define SHTIM 0x3 //Sample and Hold Time
#define ADC_MAJOR 33 //Major Number
#define ADC_NAME "at91adc_output" //Device Name
void __iomem *adc_base;
struct clk *adc_clk;
static int my_adc_read(struct file *file, char __iomem buf, ssize_t count, loff_t *f_ops)
struct file_operations adc_file = {
.owner = THIS_MODULE,
.read = my_adc_read,
};
static int my_adc_read(struct file *filp, char __iomem buf, ssize_t count, loff_t *f_ops)
{
int data, tmp[2];
memset(tmp, 0, sizeof(tmp));
data = __raw_readl(adc_base + ADC_CDR0);
data &= 0x3ff;
data = (data * 660) / 1024;
tmp[0] = data;
printk("Channel0: %d\n", data);
data = __raw_readl(adc_base + ADC_CDR1);
data &= 0x3ff;
data = (data * 660) / 1024;
tmp[1] = data;
printk("Channel1: %d\n", data);
if (copy_to_user(buf, tmp, sizeof(tmp)))
{
printk("copy to user failed\n");
return 0;
}
return sizeof(tmp);
}
static int __init my_adc_init(void)
{
int result;
adc_clk = clk_get(NULL, "adc_clk"); //open adc clock
clk_enable(adc_clk); //trun on adc clock
设置PC0为外设A,adc采样,'0':is'nt use pullup
设置PC1为外设A,adc采样
将物理地映射到虚拟内存地址
将控制寄存器清零
模式控制寄存器,包括adc采样的频率
__raw_writel(0x03, adc_base + ADC_CHER); //enable channel 0, 1
__raw_writel(0x0c, adc_base + ADC_CHDR); //disable channel 2, 3
注册设备
if (result < 0)
{
printk("Register ADC failed\n");
return 0;
}
启动ADC采样
return 0;
}
static void __exit my_adc_exit()
{
释放 ADC设备
iounmap(adc_base);
clk_disable(adc_clk); //turne off ADC clock
clk_put(adc_clk); //close ADC clock
}
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MIKE CHEN");
module_init(my_adc_init);
module_exit(my_adc_exit);
应用程序:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char **argv)
{
int fd, data[2], ret;
memset((char *)data, 0, 8);
fd = open("/dev/at91adc_output", O_RDWR);
if (fd < 0)
{
printf("open adc failed\n");
return 0;
}
while (1)
{
sleep(3);
memset((char *)data, 0, 8);
ret = read(fd, data, sizeof(data));
if (ret < 0)
{
printf("read failed\n");
return 0;
}
printf("Channel0: %d, channel1: %d\n", data[0], data[1]);
}
return ret;
}
测试结果: