您好,歡迎來(lái)電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>電子百科>語(yǔ)音視頻>安防監(jiān)控>

海思HI3515按鍵中斷驅(qū)動(dòng)程序

2017年12月26日 18:08 網(wǎng)絡(luò)整理 作者:佚名 用戶評(píng)論(0
關(guān)鍵字:海思(114074)Hi3515(17473)

  海思HI3515開發(fā)板的按鍵中斷程序分享,hi3515的核心芯片與網(wǎng)上例子較多的s3c之類的有一些區(qū)別,管腳配置方式不一樣,中斷的使用情況也不一樣。

  第一步,編寫按鍵驅(qū)動(dòng)程序,button.c代碼如下:

  /*所有模塊都需要的頭文件*/

  #include《linux/module.h》

  /*聲明printk()這個(gè)內(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è)備注冊(cè)與注銷*/

  #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表示無(wú)數(shù)據(jù)可讀,1表示有數(shù)字可讀*/

  static volatile char key;

  /*定義和初始化一個(gè)等待隊(duì)列頭*/

  static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  /*定義一個(gè)整形變量,判斷按鍵是否按下*/

  static volatile int ev_press = 0;

  /*

  *定義結(jié)構(gòu)體類型,由它把按鈕中斷的信息綜合起來(lái)

  */

  struct button_irq_desc {

  int irq;/*中斷號(hào)*/

  int pin;/*中斷標(biāo)志寄存器,有中斷產(chǎn)生時(shí)為1,無(wú)中斷時(shí)為0*/

  int number;/*編號(hào)*/

  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é)果,

  *實(shí)質(zhì)上就是讀取key_values數(shù)組的值

  *完成鍵盤輸入設(shè)備的核心功能,根據(jù)標(biāo)志位ev_press判斷是否可讀

  *如果可讀,則讀取數(shù)據(jù)到用戶buffer中,如果不可讀,

  *則進(jìn)程進(jìn)入等待隊(duì)列等待,直到數(shù)組可讀為止

  *等待隊(duì)列機(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 /*無(wú)數(shù)據(jù)可讀時(shí),進(jìn)程休眠,放進(jìn)button_waitq等待隊(duì)列*/

  wait_event_interruptible(button_waitq,ev_press);

  /*

  *wait_event_interruptible()函數(shù)將進(jìn)程置為可中斷的掛起狀態(tài)

  *反復(fù)檢查ev_press=1是否成立,如果不成立,則繼續(xù)休眠。

  *條件滿足后,即把本程序置為運(yùn)行態(tài),

  */

  }

  /*ev_press=1之后,進(jìn)程退出等待隊(duì)列。從此處開始運(yùn)行*/

  ev_press = 0;/*置0標(biāo)志位,表明本次中斷已經(jīng)處理*/

  err = copy_to_user(buff,&key,sizeof(key));

  /*把按鍵值傳會(huì)用戶空間*/

  #endif

  return 0;

  }

  static irqreturn_t irq_interrupt(int irq,void *dev_id)

  {

  #if 1

  /*對(duì)傳入的中斷資源進(jìn)行處理,獲得中斷控制寄存器的值(即是否有數(shù)據(jù))

  取反后賦值給down,為0時(shí)說(shuō)明有數(shù)據(jù),

  注意按下依次按鈕有兩次中斷,

  對(duì)數(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)志位,喚醒等待隊(duì)列進(jìn)程,在read函數(shù)中使用*/

  /*

  *喚醒休眠的進(jìn)程,用戶空間程序使用調(diào)用read函數(shù)時(shí),

  *如果沒有產(chǎn)生中斷,進(jìn)程就會(huì)進(jìn)入休眠狀態(tài),一直等待,直到產(chǎn)生中斷

  *中斷產(chǎn)生后,通過(guò)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實(shí)質(zhì)上是select的調(diào)用函數(shù)

  *如果有按鍵數(shù)據(jù),則select會(huì)立刻返回

  *如果沒有按鍵數(shù)據(jù),則等待

  *實(shí)質(zhì)上這是鍵盤等待輸入的機(jī)制

  *poll_wait()會(huì)監(jiān)測(cè)進(jìn)程隊(duì)列button_waitq里的進(jìn)程

  *例如button_irq_read所在的進(jìn)程的標(biāo)志ev_press置為1了

  *那么就不再等待,這實(shí)質(zhì)上就所select函數(shù)的運(yùn)行機(jī)制

  */

  static unsigned int button_irq_poll(struct file *file, struct poll_table_struct *wait)

  {

  #if 1

  /*

  *poll調(diào)用的具體函數(shù),poll實(shí)質(zhì)上是select的調(diào)用函數(shù)

  *如果有按鍵數(shù)據(jù),則select會(huì)立刻返回

  *如果沒有按鍵數(shù)據(jù),則等待

  *實(shí)質(zhì)上這是鍵盤等待輸入的機(jī)制。

  *select調(diào)用是用戶程序里面使用的。

  */

  unsigned int mask = 0;

  poll_wait(file,&button_waitq,wait);

  /*poll_wait會(huì)檢測(cè)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;/*中斷注冊(cè)返回值*/

  virtual_addr_map(); /*地址映射*/

  hi3515_button_pin_cfg();/*管腳配置,要先進(jìn)行地址映射*/

  /*注冊(cè)中斷*/

  err = request_irq(8,irq_interrupt,IRQF_SHARED,\

  “KEY”,(void *)&button_irqs);

  if(err)/*如果注冊(cè)中斷失敗,則釋放已經(jīng)成功注冊(cè)的中斷*/

  {

  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)用的時(shí)候才會(huì)用到poll*/

  };

  /*

  *misc混合設(shè)備注冊(cè)和注銷

  */

  static struct miscdevice misc = {

  .minor = MISC_DYNAMIC_MINOR,/*次設(shè)備號(hào)*/

  .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”);

  第二步。,編寫測(cè)試程序,test_button.c代碼如下

  /*

  *按鍵中斷測(cè)試程序

  *按鍵被按下時(shí),產(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%

不好我反對(duì)

(0) 0%

( 發(fā)表人:steve )

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?