Linux内核驱动开发-005ADC

1驱动程序

/*************************************************************************
	> File Name: adc_wait.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月23日 星期二 17时20分42秒
 ************************************************************************/

#if 1
/*=========================The adc_wait driver=========================*/

/*==========头文件包含==========*/
#include <linux/init.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/irqreturn.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <mach/irqs.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/wait.h>
#include <linux/sched.h>


#define ADCCON  (0x58000000)
#define ADCDAT0 (0x5800000C)
#define CLKCON	(0x4C00000C)

/*==========全局变量声明==========*/
static u32 *regADCCON;
static u32 *regADCDAT0;
static u32 *regCLKCON;


int adc_result=0;
static wait_queue_head_t wq;
static int condition;

/*==========函数声明==========*/
/*adc配置函数声明*/
static void adc_init(void);
/*adc驱动函数声明*/
static irqreturn_t adc_interrupt(int irq,void *p);

static void ioremap_r(void);
static int __init adc_driver_init(void);

static int adc_driver_open(struct inode *node,struct file *fp);
static ssize_t adc_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset);
static ssize_t adc_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset);
static int adc_driver_close(struct inode *node, struct file *fp);

static void iounmap_r(void);
static void __exit adc_driver_exit(void);


/*******************************************************************************
* 函 数 名	: adc_interrupt
* 函数功能	: 处理中断任务
* 输    入  : 
*           irq : 中断号
*           *p  :中断处理函数传参,一般传【NULL】
* 输    出  :
*   irqreturn_t :表示中断由该设备处理,是一个枚举类型
*******************************************************************************/
static irqreturn_t adc_interrupt(int irq,void *p)
{
    adc_result=*regADCDAT0 & 0x3FF;
    condition=1;//唤醒等待队列的条件
    wake_up(&wq);//唤醒等待队列

    return IRQ_HANDLED;
}
/*******************************************************************************
* 函 数 名	: adc_driver_open
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static int adc_driver_open(struct inode *node,struct file *fp)
{
    return 0;
}
/*******************************************************************************
* 函 数 名	: adc_driver_read
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static ssize_t adc_driver_read(struct file *fp, char __user *user_buffer, size_t len, loff_t *offset)
{	
	adc_result = *regADCDAT0 & 0x3FF;
//	*regADCCON &= ~(1 << 1);
	condition = 0;
	wait_event_interruptible(wq, condition);
	copy_to_user(user_buffer, &adc_result, sizeof(adc_result));
	return sizeof(adc_result);
}
/*******************************************************************************
* 函 数 名	: adc_driver_write
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static ssize_t adc_driver_write(struct file *fp, const char __user *user_buffer, size_t len, loff_t *offset)
{
	return 0;
}
/*******************************************************************************
* 函 数 名	: adc_driver_close
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static int adc_driver_close(struct inode *node, struct file *fp)
{
	return 0;
}

/*字符设备文件操作结构体*/
static struct file_operations fops =
{
	.owner = THIS_MODULE,
	.open = adc_driver_open,
	.read = adc_driver_read,
	.write = adc_driver_write,
	.release = adc_driver_close
};

/*杂项设备结构体*/
static struct miscdevice adc_dev = 
{
	.minor = MISC_DYNAMIC_MINOR,
	.name = "adc_r",
	.fops = &fops,
};

/*******************************************************************************
* 函 数 名	: ioremap_r
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static void ioremap_r(void)
{
    regADCCON = ioremap(ADCCON, 4);
    regADCDAT0 = ioremap(ADCDAT0, 4);
    regCLKCON = ioremap(CLKCON, 4);
}
/*******************************************************************************
* 函 数 名	: adc_driver_init
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static int __init adc_driver_init(void)
{
	int ret;

    /* 1 注册杂项设备*/
    ret = misc_register(&adc_dev);
	if(ret <  0)
	{
		printk("misc_register is failed\n");
		goto misc_register_err;
	}

    /* 2 注册中断-【中断号】-【中断处理函数指针】-【中断产生的条件和系统处理中断时的行为(这里处理中断时不响应其他中断)】-【给中断名命名】-【中断服务函数传参-NULL】*/
	ret = request_irq(IRQ_ADC, adc_interrupt, IRQF_DISABLED | IRQF_TRIGGER_NONE, "adc", NULL);
	if(ret < 0)
	{
		printk("request_irq is failed\n");
		goto request_irq_err;
	}

    /* 3 初始化等待队列*/
	init_waitqueue_head(&wq);

    /* 4 寄存器映射*/
    ioremap_r();

    /* 5 开启adc时钟*/
    *regCLKCON |= (1 << 15);

    /* 6 adc配置初始化*/
    adc_init();

    return 0;

request_irq_err:
	misc_deregister(&adc_dev);
misc_register_err:
	return -1;
}
/*******************************************************************************
* 函 数 名	: iounmap_r
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static void iounmap_r(void)
{
	iounmap(regADCCON);
	iounmap(regADCDAT0);
	iounmap(regCLKCON);
}
/*******************************************************************************
* 函 数 名	: adc_driver_exit
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static void __exit adc_driver_exit(void)
{
    iounmap_r();//寄存器反映射
	disable_irq(IRQ_ADC);//禁止中断
	free_irq(IRQ_ADC, NULL);//注销中断
	misc_deregister(&adc_dev);//注销杂项设备
}

/*==========adc配置函数==========*/
/*******************************************************************************
* 函 数 名	: adc_init
* 函数功能	: 
* 输    入  : 							
* 输    出  :
*******************************************************************************/
static void adc_init(void)
{
	u32 t=0;

	t=*regADCCON;
	t&=~((0X01<<14)|(0XFF<<6)|(0X01<<1));
	t|=(0X01<<14);
	t|=(0X31<<6);
	t&=~(0X07<<3);//选择通道0
	t&=~(0X01<<2);正常工作模式
//	t&=~(0X01<<1);
    t|=(0X01<<1);//读启动方式
	*regADCCON=t;
}

#if 0
/*******************************************************************************
* 函 数 名	: adc_convert
* 函数功能	:
* 输    入  :
* 输    出  :
*******************************************************************************/
static u32 adc_convert(void)
{
	*regADCCON|=(0X01<<0);
	while((*regADCCON&(0X01<<15))==0);

	return ADCDAT0&0X3FF;
}
#endif

module_init(adc_driver_init);
module_exit(adc_driver_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("XXX");
/*=========================The adc_wait driver=========================*/
#endif

2应用程序

/*************************************************************************
	> File Name: main.c
	> Author: yas
	> Mail: rage_yas@hotmail.com
	> Created Time: 2024年04月23日 星期二 17时20分42秒
 ************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>

int main(void)
{

#if 1
/*====================adc-r====================*/    
    int fd=0;
    int n=0;

    fd=open("dev/adc_r",O_RDWR);
    if(fd<0)
    {
        printf("opening is failed\n");
        return -1;
    }

    while(1)
    {
        read(fd,&n,4);
        printf("%d\n",n);
//        sleep(1);
    }
    return 0;
/*========================================*/    
#endif
}

3关于adc驱动

(1)这里adc驱动是采用字符设备驱动中的杂项驱动方式,所以主要应用的技术有:字符设备驱动,杂项驱动,内核中断,等待队列,adc硬件驱动配置。
(2)驱动流程:
	搭建字符设备驱动框架:定义字符设备结构体变量->编写字符设备结构体成员函数->编写adc驱动初始化函数(驱动加载函数)->编写adc驱动卸载函数
	建立杂项驱动:定义杂项设备结构体变量->注册杂项设备->注销杂项设备
	建立内核中断:注册中断->编写中断服务函数
	建立等待队列:定义等待队列头和等待条件->初始化等待队列->队列等待(读时等待)->唤醒队列(中断发生时唤醒)
	建立adc裸机配置:开启adc时钟发生寄存器->adc配置(硬件初始化)
(3)注意事项:
	由于adc是一种需要上电手动开启时钟开关,所以在进行adc硬件初始化操作之前需要先配置adc的时钟开关(CLKCON)
  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值