海思HI3515按鍵中斷驅(qū)動程序
海思HI3515開發(fā)板的按鍵中斷程序分享,hi3515的核心芯片與網(wǎng)上例子較多的s3c之類的有一些區(qū)別,管腳配置方式不一樣,中斷的使用情況也不一樣。
第一步,編寫按鍵驅(qū)動程序,button.c代碼如下:
/*所有模塊都需要的頭文件*/
#include《linux/module.h》
/*聲明printk()這個內(nèi)核態(tài)的函數(shù)*/
#include《linux/kernel.h》
/*文件系統(tǒng)有關(guān)的,結(jié)構(gòu)體file_operations也在fs頭文件定義*/
#include《linux/fs.h》
/*init和exit相關(guān)宏*/
#include《linux/init.h》
#include《linux/delay.h》
#include《linux/poll.h》
/*linux中斷定義*/
#include《linux/irq.h》
/**/
#include《asm/irq.h》
/*包含與中斷相關(guān)的大部分宏及結(jié)構(gòu)體的定義,request_irq()等*/
#include《linux/interrupt.h》
/*linux中的用戶態(tài)內(nèi)存交互函數(shù),copy_from_user(),copy_to_user()等*/
#include《asm/uaccess.h》
//#include《mach/regs-gpio.h》
//#include《mach/hardware.h》
#include《linux/platform_device.h》
#include《linux/cdev.h》
/*misc混合設(shè)備注冊與注銷*/
#include《linux/miscdevice.h》
#include 《asm/io.h》
#include 《asm/system.h》
#define BUTTON_READ 0x01
#define DEVICE_NAME “BUTTON_irq”
#define REG_WRITE(addr,value) ((*(volatile unsigned int *)(addr)) = (value))
#define REG_READ(Addr) (*(volatile unsigned int *)(Addr))
static unsigned int gpio3_virtual_addr = 0;
static unsigned int reg_virtual_addr = 0;
/*數(shù)組中是否有數(shù)據(jù)標(biāo)志,0表示無數(shù)據(jù)可讀,1表示有數(shù)字可讀*/
static volatile char key;
/*定義和初始化一個等待隊列頭*/
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/*定義一個整形變量,判斷按鍵是否按下*/
static volatile int ev_press = 0;
/*
*定義結(jié)構(gòu)體類型,由它把按鈕中斷的信息綜合起來
*/
struct button_irq_desc {
int irq;/*中斷號*/
int pin;/*中斷標(biāo)志寄存器,有中斷產(chǎn)生時為1,無中斷時為0*/
int number;/*編號*/
char *name;/*名稱*/
};
static struct button_irq_desc button_irqs[]={
{8,2,1,“KEY1”},
};
static void hi3515_button_pin_cfg(void)
{
/*配置作為普通輸入*/
REG_WRITE(reg_virtual_addr + 0x08,0x1);/*reg2管腳復(fù)用配置gpio3_0,按鍵1*/
REG_WRITE(reg_virtual_addr + 0x0c,0x1);/*reg3管腳復(fù)用配置gpio3_1,按鍵1*/
REG_WRITE(reg_virtual_addr + 0x10,0x1);/*reg4管腳復(fù)用配置gpio3_2,按鍵1*/
REG_WRITE(reg_virtual_addr + 0x14,0x1);/*reg5管腳復(fù)用配置gpio3_3,按鍵2*/
/*管腳中斷配置*/
REG_WRITE(gpio3_virtual_addr + 0x0400,0x3);/*dir設(shè)置管腳為0-1:輸出,2-3:輸入*/
REG_WRITE(gpio3_virtual_addr + 0x0404,0xc);/*is邊沿觸發(fā)中斷*/
REG_WRITE(gpio3_virtual_addr + 0x040c,0x0);/*iev低電平觸發(fā)*/
REG_WRITE(gpio3_virtual_addr + 0x041c,0xff);/*ic清除中斷*/
REG_WRITE(gpio3_virtual_addr + 0x0410,0x04);/*ie啟用中斷*/
}
/*
*gpio地址映射
*/
static int virtual_addr_map(void)
{
reg_virtual_addr = (unsigned int)ioremap_nocache(0x200f0000,0x4000);
if(!reg_virtual_addr)
{
printk(“0x200f0000 ioremap addr failed !\n”);
return -1;
}
gpio3_virtual_addr = (unsigned int)ioremap_nocache(0x20180000,0x4000);
if(!gpio3_virtual_addr)
{
printk(“0x20180000 ioremap addr failed !\n”);
return -1;
}
}
/*取消地址映射*/
static void virtual_addr_unmap(void)
{
iounmap((void*)gpio3_virtual_addr);
iounmap((void*)reg_virtual_addr);
}
/*
*read調(diào)用的具體函數(shù),由它讀取鍵盤輸入的結(jié)果,
*實質(zhì)上就是讀取key_values數(shù)組的值
*完成鍵盤輸入設(shè)備的核心功能,根據(jù)標(biāo)志位ev_press判斷是否可讀
*如果可讀,則讀取數(shù)據(jù)到用戶buffer中,如果不可讀,
*則進(jìn)程進(jìn)入等待隊列等待,直到數(shù)組可讀為止
*等待隊列機(jī)制,所中斷管理中常用的機(jī)制。
*/
static int button_irq_read(struct file *filp,
char __user *buff,
size_t count,loff_t *offp)
{
unsigned long err;
#if 1
if(!ev_press) /*ev_press=0,則表示沒有數(shù)據(jù)可讀*/
{
if(filp-》f_flags & O_NONBLOCK)
return -EAGAIN;
else /*無數(shù)據(jù)可讀時,進(jìn)程休眠,放進(jìn)button_waitq等待隊列*/
wait_event_interruptible(button_waitq,ev_press);
/*
*wait_event_interruptible()函數(shù)將進(jìn)程置為可中斷的掛起狀態(tài)
*反復(fù)檢查ev_press=1是否成立,如果不成立,則繼續(xù)休眠。
*條件滿足后,即把本程序置為運行態(tài),
*/
}
/*ev_press=1之后,進(jìn)程退出等待隊列。從此處開始運行*/
ev_press = 0;/*置0標(biāo)志位,表明本次中斷已經(jīng)處理*/
err = copy_to_user(buff,&key,sizeof(key));
/*把按鍵值傳會用戶空間*/
#endif
return 0;
}
static irqreturn_t irq_interrupt(int irq,void *dev_id)
{
#if 1
/*對傳入的中斷資源進(jìn)行處理,獲得中斷控制寄存器的值(即是否有數(shù)據(jù))
取反后賦值給down,為0時說明有數(shù)據(jù),
注意按下依次按鈕有兩次中斷,
對數(shù)組可讀標(biāo)志位進(jìn)行設(shè)置,ev_press=1表示數(shù)組已經(jīng)可以讀了*/
//struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;
int down;
down = 0x0c & REG_READ(gpio3_virtual_addr + 0x0414);
REG_WRITE(gpio3_virtual_addr + 0x041c,0xff);/*ic清除按鍵中斷*/
mdelay(5);/**/
if(down != 0x0c )
{
key = (char)down;
ev_press = 1; /*置1標(biāo)志位,喚醒等待隊列進(jìn)程,在read函數(shù)中使用*/
/*
*喚醒休眠的進(jìn)程,用戶空間程序使用調(diào)用read函數(shù)時,
*如果沒有產(chǎn)生中斷,進(jìn)程就會進(jìn)入休眠狀態(tài),一直等待,直到產(chǎn)生中斷
*中斷產(chǎn)生后,通過wake_up_interruptible()函數(shù)喚醒休眠進(jìn)程
*/
wake_up_interruptible(&button_waitq);
}
#endif
REG_WRITE(gpio3_virtual_addr + 0x0410,0x0c);/*ie啟用按鍵中斷*/
return IRQ_HANDLED; //IRQ_HANDLED=1
}
/*
*poll調(diào)用的具體函數(shù),poll實質(zhì)上是select的調(diào)用函數(shù)
*如果有按鍵數(shù)據(jù),則select會立刻返回
*如果沒有按鍵數(shù)據(jù),則等待
*實質(zhì)上這是鍵盤等待輸入的機(jī)制
*poll_wait()會監(jiān)測進(jìn)程隊列button_waitq里的進(jìn)程
*例如button_irq_read所在的進(jìn)程的標(biāo)志ev_press置為1了
*那么就不再等待,這實質(zhì)上就所select函數(shù)的運行機(jī)制
*/
static unsigned int button_irq_poll(struct file *file, struct poll_table_struct *wait)
{
#if 1
/*
*poll調(diào)用的具體函數(shù),poll實質(zhì)上是select的調(diào)用函數(shù)
*如果有按鍵數(shù)據(jù),則select會立刻返回
*如果沒有按鍵數(shù)據(jù),則等待
*實質(zhì)上這是鍵盤等待輸入的機(jī)制。
*select調(diào)用是用戶程序里面使用的。
*/
unsigned int mask = 0;
poll_wait(file,&button_waitq,wait);
/*poll_wait會檢測button_waitq里的進(jìn)程*/
if(ev_press)
mask |=POLLIN | POLLRDNORM;
return mask;
#endif
}
static int button_irq_open(struct inode *inode,struct file *file)
{
#if 1
int err;/*中斷注冊返回值*/
virtual_addr_map(); /*地址映射*/
hi3515_button_pin_cfg();/*管腳配置,要先進(jìn)行地址映射*/
/*注冊中斷*/
err = request_irq(8,irq_interrupt,IRQF_SHARED,\
“KEY”,(void *)&button_irqs);
if(err)/*如果注冊中斷失敗,則釋放已經(jīng)成功注冊的中斷*/
{
return -EBUSY;
}
ev_press = 1;
#endif
return 0;
}
static int button_irq_close(struct inode *inode,struct file *file)
{
free_irq(8,(void *)&button_irqs);
virtual_addr_unmap();/*取消地址映射*/
return 0;
}
int button_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned int __user *argp = (unsigned int __user *)arg;
int value;
value = *(unsigned int *)arg;
switch (cmd)
{
case 1:
if(value == 0) /*led1亮*/
REG_WRITE(gpio3_virtual_addr +0x4,0);
else if(value == 1) /*led1滅*/
REG_WRITE(gpio3_virtual_addr +0x4,1);
break;
case 2:
if(value == 0) /*led2亮*/
REG_WRITE(gpio3_virtual_addr +0x8,0);
else if(value == 1) /*led2滅*/
REG_WRITE(gpio3_virtual_addr +0x8,2);
break;
default:
return -1;
}
return 0;
}
static struct file_operations dev_fops = {
.owner = THIS_MODULE,
.open = button_irq_open,
.release = button_irq_close,
.ioctl = button_ioctl,
.read = button_irq_read,
.poll = button_irq_poll,/*用戶程序使用select調(diào)用的時候才會用到poll*/
};
/*
*misc混合設(shè)備注冊和注銷
*/
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,/*次設(shè)備號*/
.name = DEVICE_NAME,/*設(shè)備名*/
.fops = &dev_fops,/*設(shè)備文件操作結(jié)構(gòu)體*/
};
static int __init button_init(void)
{
int ret;
ret = misc_register(&misc);
if(0 != ret)
{
printk(“register device failed! !\n”);
return -1;
}
printk(“register device success !\n”);
return 0;
}
static void __exit button_exit(void)
{
misc_deregister(&misc);
printk(“unregister device success !\n”);
}
module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“Dong”);
第二步。,編寫測試程序,test_button.c代碼如下
/*
*按鍵中斷測試程序
*按鍵被按下時,產(chǎn)生中斷
*打印按下信息,切換led顯示狀態(tài)
*/
#include 《stdio.h》
#include 《ctype.h》
#include 《sys/ioctl.h》
#include 《sys/types.h》
#include 《sys/stat.h》
#include 《fcntl.h》
#include《linux/delay.h》
int main(int argc , char* argv[])
{
int fd = -1;
unsigned int led1;
unsigned int led2; ;
char key;
fd = open(“/dev/BUTTON_irq”, 0);
if (fd《0)
{
printf(“Open BUTTON_irq dev error!\n”);
return -1;
}
for(;;)
{
int ret;
ret = read(fd,&key,sizeof(key));
if(ret《 0)
{
perror(“read button:”);
return -1;
}
if(key == 4)/*按鍵1被按下*/
{
printf(“K1 is press!\n”);
led1 = (~led1)&0x1;
ioctl(fd, 0x01, &led1); /*切換led1的狀態(tài)*/
}
if(key == 8)/*按鍵2被按下*/
{
printf(“K2 is press!\n”);
led2 = (~led2)&0x1;
ioctl(fd, 0x02, &led2); /*切換led2的狀態(tài)*/
}
//printf(“\n”);
}
close(fd);
return 0;
}
第三步,makefile文件,代碼如下:
LINUXROOT = /opt/Hi3515_SDK_V1.0.5.1/source/os/linux-2.6.24
#這是放內(nèi)核的路徑
CC = arm-hismall-linux-gcc
obj-m := button.o
default:
$(CC) -g -Wall -o test_button test_button.c
@make -C $(LINUXROOT) M=$(PWD) modules
rm -rf *.o *.mod.c *.symvers
clean:
@make -C $(LINUXROOT) M=$(PWD) clean
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%
相關(guān)閱讀:
- [電子說] 麒麟a1芯片和麒麟990的區(qū)別 2023-10-14
- [電子說] 前海思高級工程師披露:華為的秘密(4萬字) 2023-10-13
- [電子說] 如何搭建海思星閃BS25開發(fā)環(huán)境? 2023-10-07
- [電子說] 海思與比亞迪合作!麒麟芯片將上車! 2023-09-21
- [電子說] 華為海思雄起!正出貨國產(chǎn)監(jiān)控鏡頭芯片 2023-09-20
- [電子說] Q3最大變數(shù)來自海思?Q2全球智能手機(jī)SoC聯(lián)發(fā)科第一,紫光展銳增至15% 2023-09-20
- [電子說] 什么海思電導(dǎo)率,電導(dǎo)率原理解析 2023-09-15
- [電子說] 消息稱華為海思正開發(fā)麒麟8,進(jìn)一步縮小與最先進(jìn)技術(shù)的差距 2023-09-14
( 發(fā)表人:steve )