zoukankan      html  css  js  c++  java
  • LINUX内核中断(ioremap,内部watchdog中断,外部中断)

    一:ioremap

        在内核中有关与物理地址到虚拟地址的映射全都是有mmu,统一开启,而物理地址到虚拟地址的映射关系全都存在一张对应的表格里面,这张表,在开启mmu的时候一起建好,比如在建表的时候是将物理地址0x11111111映射到44444444,那么问题就是: 比如以后我们如果要将0x11111111的地址映射到66666666地址怎么办?在内核中,通过特定的物理地址到虚拟地址的自动对应映射通过ioremap()函数来实现

        

      1 #include <linux/init.h>
      2 #include <linux/thread_info.h>
      3 #include <linux/module.h>
      4 #include <linux/sched.h>
      5 #include <linux/errno.h>
      6 #include <linux/kernel.h>
      7 #include <linux/module.h>
      8 #include <linux/slab.h>
      9 #include <linux/input.h>
     10 #include <linux/init.h>
     11 #include <linux/serio.h>
     12 #include <linux/delay.h>
     13 #include <linux/clk.h>
     14 #include <linux/miscdevice.h>
     15 #include <linux/io.h>
     16 #include <linux/ioport.h>
     17 #include <asm/uaccess.h>
     18 
     19 #include <linux/gpio.h>
     20 #include <mach/gpio.h>
     21 #include <plat/gpio-cfg.h>
     22 
     23 
     24 MODULE_LICENSE("GPL");
     25 MODULE_AUTHOR("bunfly");
     26 
     27 unsigned long gpio_virt = 0;
     28 
     29 int test_init()
     30 {
     31     void __iomem *p;
     32 
     33     p = request_mem_region(0x11000000,SZ_4K,"gpio");//注册内存的映射信息
     34     if(p==NULL)
     35     {
     36         printk("request error!
    ");
     37         return 1;
     38     }
     39 
     40     gpio_virt = ioremap(0x11000000,SZ_4K);
     41     //ioremap物理内存到虚拟内存映射
     42     *(unsigned long *)(gpio_virt  + 0x2e0)  =1;
     43     *(unsigned long *)(gpio_virt  + 0x2e4)  =0;
     44     printk("hello led!
    ");
     45 
     46     printk("phys: %p
    ",virt_to_phys(gpio_virt));
     47 
     48 return 0;
     49 }
     50 
     51 void test_exit()
     52 {
     53     printk("bye bye!
    ");
     54     iounmap(gpio_virt);
     55     release_mem_region(0x11000000,SZ_4K);
     56     //退出的时候将映射的虚拟内存取消
     57 }
     58 
     59 module_init(test_init);
     60 module_exit(test_exit);
     61 
     62 
     63 
     64 

       以上是通过映射的方法,把物理内存映射到虚拟内存,然后通过操作虚拟内存来点灯

    内核在分配的时候,注册分配的名字,其中的注册信息可以在板子的目录下面查看:

      cat  /proc/iomem

      

    注意:

      在模块运行之前,为了消除内核中自带的LED模块的影响,需要将自带的LED模块:

          在linux_3 下make  menuconfig

      


         在保存退出之后,重新make成zImage文件,下载到板子,运行。

    二:内部watch看门狗中断

       内核中的狗中断和裸板的狗中断原理都差不多,只是把物理地址映射到虚拟地址而已,下面是通过狗中断来操作蜂鸣器,而且定时打印一句话,在操作之前,需要线把内核自带的watch dog模块裁剪掉,要不然会出现错误!

      

    1 #include <linux/init.h>
      2 #include <linux/thread_info.h>
      3 #include <linux/module.h>
      4 #include <linux/sched.h>
      5 #include <linux/errno.h>
      6 #include <linux/kernel.h>
      7 #include <linux/module.h>
      8 #include <linux/slab.h>
      9 #include <linux/input.h>
     10 #include <linux/init.h>
     11 #include <linux/serio.h>
     12 #include <linux/delay.h>
     13 #include <linux/clk.h>
     14 #include <linux/miscdevice.h>
     15 #include <linux/io.h>
     16 #include <linux/ioport.h>
     17 #include <asm/uaccess.h>
     18 
     19 #include <linux/gpio.h>
     20 #include <mach/gpio.h>
     21 #include <plat/gpio-cfg.h>
     22 
     23 MODULE_LICENSE("GPL");
     24 MODULE_AUTHOR("bunfly");
     25 
     26 void led_on(void);
     27 void led_off(void);
     28 void pwm_on(void);
     29 void pwm_off(void);
     30 
     31 irqreturn_t do_irq(int irq, void *data);
     32 
     33 unsigned long wdt_virt;
     34 unsigned long gpiobase_led;
     35 unsigned long gpiobase_pwm;
     36 unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
     37 unsigned long *GPMCON, *GPMDAT;
     38 unsigned long *GPD0CON, *GPD0DAT;
     39 struct clk *k;
     40 
     41 int test_init()
     42 {
     43     int ret = 0;
     44     ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "bunflydog", 0x1111);
     45     //注册中断       中断号    处理中断函数回调函数, 
     46     if(ret < 0){
     47         printk("request_irq
    ");
     48         return 1;
     49     }
     50 
     51     k = clk_get(NULL, "watchdog");
     52     clk_enable(k);
     53     //频率
     54 
     55     wdt_virt = ioremap(0x10060000, SZ_4K);
     56     wtcon = wdt_virt + 0x00;
     57     wtdat = wdt_virt + 0x04;
     58     wtcnt = wdt_virt + 0x08;
     59     wtclrint = wdt_virt + 0x0c;
     60     //映射物理地址到虚拟地址
     61 
     62     gpiobase_pwm = ioremap(0x11400000, SZ_4K);
     63     GPD0CON = (gpiobase_pwm + 0x00a0);
     64     GPD0DAT = (gpiobase_pwm + 0x00a4);
     65     //映射蜂鸣器的物理地址
     66 
     67     gpiobase_led = ioremap(0x11000000, SZ_4K);
     68     GPMCON = (gpiobase_led + 0x02e0);
     69     GPMDAT = (gpiobase_led + 0x02e4);
     70     //映射LED的物理地址
     71 
     72     *wtcon = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (50 << 8);
     73     *wtdat = 0x8000;
     74     *wtcnt = 0x8000;
     75     //配置寄存器,将狗打开
     76 
     77     return 0;
     78 }
     79 
     80 void pwm_on(void)
     81 {
     82     //*GPD0CON &= ~0xffff;
     83     *GPD0CON = 0x1;//配置寄存器为2
     84     *GPD0DAT = 0x1;//date=0xf
     85 }
     86 
     87 void pwm_off(void)
     88 {
     89     //*GPD0CON &= ~0xffff;
    90     *GPD0CON = 0x0;
     91 }
     92 
     93 void led_on(void)
     94 {
     95     *GPMCON &= ~0xffff;
     96     *GPMCON |= 0x1111;//配置寄存器3-0-----3-3全为1111,全为输出模式
     97     *GPMDAT &= ~0x1;//打开置0-4位为0000
     98 }
     99 void led_off(void)
    100 {
    101     *GPMCON &= ~0xffff;//清零
    102     *GPMCON |= 0x0000;//0---3位清零
    103     *GPMDAT |= 0x0;//date=0xf关闭置一
    104 }
    105 void test_exit()
    106 {
    107     printk("exit
    ");
    108 }
    109 
    110 module_init(test_init);
    111 module_exit(test_exit);
    112 
    113 irqreturn_t do_irq(int irq, void *data)
    114 {
    115     printk("wang wang wang
    ");
    116     static int flag=1;
    117     if(flag)
    118     {
    119         pwm_on();
    120         led_on();
    121         flag=0;
    122     }
    123     else if(flag == 0)
    124     {
    125         pwm_off();
    126         led_off();
    127         flag=1;
    128     }
    129 
    130     *wtclrint = 250;
    131     //消除中断
    132     return IRQ_HANDLED;
    133     //返回处理的中断标志
    134 }

          通过在板子下  cat /pro/interrupt  文件可以看到目前的中断信息:可以看到,在文件中注册的 bunfly dog 定时狗中断:

                  

    三 内核外部中断:

        在内核中,外部中断与裸板的外部中断处理差不多,但是与狗中断处理不同的是,开始的时候不需要提前获得中断号,而在外部中断处理之后,系统自动清中断,以下是内核中断代码:

        

     1 #include <linux/init.h>
      2 #include <linux/thread_info.h>
      3 #include <linux/module.h>
      4 #include <linux/sched.h>
      5 #include <linux/errno.h>
      6 #include <linux/kernel.h>
      7 #include <linux/module.h>
      8 #include <linux/slab.h>
      9 #include <linux/input.h>
     10 #include <linux/init.h>
     11 #include <linux/serio.h>
     12 #include <linux/delay.h>
     13 #include <linux/clk.h>
     14 #include <linux/miscdevice.h>
     15 #include <linux/io.h>
     16 #include <linux/ioport.h>
     17 #include <asm/uaccess.h>
     18 
     19 #include <linux/gpio.h>
     20 #include <mach/gpio.h>
     21 #include <plat/gpio-cfg.h>
     22 #include <linux/irq.h>
     23 #include <linux/interrupt.h>
     24 
     25 #include <asm/irq.h>
     26 #include <asm/ptrace.h>
     27 #include <asm/irq_regs.h>
     28 
     29 MODULE_LICENSE("GPL");
     30 MODULE_AUTHOR("bunfly");
     31 
     32 void led_on(void);
     33 void led_off(void);
     34 void pwm_on(void);
     35 void pwm_off(void);
     36 
     37 irqreturn_t do_irq(int irq, void *data);
     38 
     39 unsigned long wdt_virt;
     40 unsigned long gpiobase_led;
     41 unsigned long gpiobase_pwm;
     42 unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
     43 unsigned long *GPMCON, *GPMDAT;
     44 unsigned long *GPD0CON, *GPD0DAT;
     45 struct clk *k;
     46 
     47 int test_init()
     48 {
     49     int extern_irq=gpio_to_irq(EXYNOS4_GPX3(2));
     50     //获得外部中断号码  
     51     int ret = 0;
     52     //ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "bunflydog", 0x1111);
     53     ret = request_irq(extern_irq, do_irq,IRQ_TYPE_EDGE_FALLING, "exter_interrupt", 0x1111);
     54     //注册中断       中断号    处理中断函数回调函数, 
     55     if(ret < 0){
     56         printk("request_irq
    ");
     57         return 1;
     58     }
     59 
     60     //k = clk_get(NULL, "watchdog");
     61     //clk_enable(k);
     62     //wdt_virt = ioremap(0x10060000, SZ_4K);
     63     //wtcon = wdt_virt + 0x00;
     64     //wtdat = wdt_virt + 0x04;
     65     //wtcnt = wdt_virt + 0x08;
     66     //wtclrint = wdt_virt + 0x0c;
     67     ////映射物理地址到虚拟地址
     68 
     69     gpiobase_pwm = ioremap(0x11400000, SZ_4K);
     70     GPD0CON = (gpiobase_pwm + 0x00a0);
     71     GPD0DAT = (gpiobase_pwm + 0x00a4);
     72     //映射蜂鸣器的物理地址
     73 
     74     gpiobase_led = ioremap(0x11000000, SZ_4K);
     75     GPMCON = (gpiobase_led + 0x02e0);
     76     GPMDAT = (gpiobase_led + 0x02e4);
     77     //映射LED的物理地址
     78 
     79 //  *wtcon = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (50 << 8);
     80 //  *wtdat = 0x8000;
     81 //  *wtcnt = 0x8000;
     82 //  //配置寄存器,将狗打开
     83 
     84     return 0;
     85 }
     86 
     87 void pwm_on(void)
     88 {
     89     //*GPD0CON &= ~0xffff;
     90     *GPD0CON = 0x1;//配置寄存器为2
     91     *GPD0DAT = 0x1;//date=0xf
    92 }
     93 
     94 void pwm_off(void)
     95 {
     96     //*GPD0CON &= ~0xffff;
     97     *GPD0CON = 0x0;
     98 }
     99 
    100 void led_on(void)
    101 {
    102     *GPMCON &= ~0xffff;
    103     *GPMCON |= 0x1111;//配置寄存器3-0-----3-3全为1111,全为输出模式
    104     *GPMDAT &= ~0x1;//打开置0-4位为0000
    105 }
    106 void led_off(void)
    107 {
    108     *GPMCON &= ~0xffff;//清零
    109     *GPMCON |= 0x0000;//0---3位清零
    110     *GPMDAT |= 0x0;//date=0xf关闭置一
    111 }
    112 void test_exit()
    113 {
    114     printk("exit
    ");
    115 }
    116 
    117 module_init(test_init);
    118 module_exit(test_exit);
    119 
    120 irqreturn_t do_irq(int irq, void *data)
    121 {
    122     printk("irq is %d
    ",irq);
    123     printk("extern!
    ");
    124     static int flag=1;
    125     if(flag)
    126     {
    127         pwm_on();
    128         led_on();
    129         flag=0;
    130     }
    131     else if(flag == 0)
    132     {
    133         pwm_off();
    134         led_off();
    135         flag=1;
    136     }
    137 
    138     //*wtclrint = 250;
    139     ////消除中断
    140     //return IRQ_HANDLED;
    141     //返回处理的中断标志
    142 }
    143 
    144 
    145 
    146 
                                                                                                                                                                        

      运行成功后,可以看到中断号:

          

        以下是自己选做的作业,通过外部中断控制内部狗中断实现点灯和蜂鸣器驱动:

        

     1 #include <linux/init.h>
      2 #include <linux/thread_info.h>
      3 #include <linux/module.h>
      4 #include <linux/sched.h>
      5 #include <linux/errno.h>
      6 #include <linux/kernel.h>
      7 #include <linux/module.h>
      8 #include <linux/slab.h>
      9 #include <linux/input.h>
     10 #include <linux/init.h>
     11 #include <linux/serio.h>
     12 #include <linux/delay.h>
     13 #include <linux/clk.h>
     14 #include <linux/miscdevice.h>
     15 #include <linux/io.h>
     16 #include <linux/ioport.h>
     17 #include <asm/uaccess.h>
     18 
     19 #include <linux/gpio.h>
     20 #include <mach/gpio.h>
     21 #include <plat/gpio-cfg.h>
     22 #include <linux/irq.h>
     23 #include <linux/interrupt.h>
     24 
     25 #include <asm/irq.h>
     26 #include <asm/ptrace.h>
     27 #include <asm/irq_regs.h>
     28 
     29 MODULE_LICENSE("GPL");
     30 MODULE_AUTHOR("bunfly");
     31 
     32 void led_on(void);
     33 void led_off(void);
     34 void pwm_on(void);
     35 void pwm_off(void);
     36 
     37 irqreturn_t do_irq(int irq, void *data);
     38 
     39 unsigned long wdt_virt;
     40 unsigned long gpiobase_led;
     41 unsigned long gpiobase_pwm;
     42 unsigned long *wtcon, *wtdat, *wtcnt, *wtclrint;
     43 unsigned long *GPMCON, *GPMDAT;
     44 unsigned long *GPD0CON, *GPD0DAT;
     45 struct clk *k;
     46 int extern_irq;
     47 
     48 int test_init()
     49 {
     50     extern_irq=gpio_to_irq(EXYNOS4_GPX3(2));
     51     //获得外部中断号码  
     52     int ret = 0;
     53     ret = request_irq(IRQ_WDT, do_irq, IRQF_SHARED, "bunflydog", 0x1111);
     54     //注册狗中断
     55     ret = request_irq(extern_irq, do_irq,IRQ_TYPE_EDGE_FALLING, "exter_interrupt", 0x1111);
     56     //注册外部中断       中断号    处理中断函数回调函数, 
     57     if(ret < 0){
     58         printk("request_irq
    ");
     59         return 1;
     60     }
     61 
     62     k = clk_get(NULL, "watchdog");
     63     clk_enable(k);
     64 
     65     wdt_virt = ioremap(0x10060000, SZ_4K);
     66     wtcon = wdt_virt + 0x00;
     67     wtdat = wdt_virt + 0x04;
     68     wtcnt = wdt_virt + 0x08;
     69     wtclrint = wdt_virt + 0x0c;
     70     ////映射物理地址到虚拟地址
     71 
     72     gpiobase_pwm = ioremap(0x11400000, SZ_4K);
     73     GPD0CON = (gpiobase_pwm + 0x00a0);
     74     GPD0DAT = (gpiobase_pwm + 0x00a4);
     75     //映射蜂鸣器的物理地址
     76 
     77     gpiobase_led = ioremap(0x11000000, SZ_4K);
     78     GPMCON = (gpiobase_led + 0x02e0);
     79     GPMDAT = (gpiobase_led + 0x02e4);
     80     //映射LED的物理地址
     81 
     82     return 0;
     83 }
     84 
     85 void pwm_on(void)
     86 {
     87     //*GPD0CON &= ~0xffff;
     88     *GPD0CON = 0x1;//配置寄存器为2
     89     *GPD0DAT = 0x1;//date=0xf
     90 }
     91 
     92 void pwm_off(void)
     93 {
     94     //*GPD0CON &= ~0xffff;
     95     *GPD0CON = 0x0;
     96 }
     97 
     98 void led_on(void)
     99 {
    100     *GPMCON &= ~0xffff;
    101     *GPMCON |= 0x1111;//配置寄存器3-0-----3-3全为1111,全为输出模式
    102     *GPMDAT &= ~0x1;//打开置0-4位为0000
    103 }
    104 void led_off(void)
    105 {
    106     *GPMCON &= ~0xffff;//清零
    107     *GPMCON |= 0x0000;//0---3位清零
    108     *GPMDAT |= 0x0;//date=0xf关闭置一
    109 }
    110 void test_exit()
    111 {
    112     printk("exit
    ");
    113 }
    114 
    115 module_init(test_init);
    116 module_exit(test_exit);
    117 
    118 irqreturn_t do_irq(int irq, void *data)
    119 {
    120 
    121     if(irq == extern_irq)//如果按键中断
    122     {
    123              printk("key 1 down
    ");
    124              static int flag=1;
    125              if(flag)
    126              {
    127                  printk("wtc_on
    ");
    128                 // wtc_on();
    129 
    130                 *wtcon = 0 | (1 << 2) | (3 << 3) | (1 << 5) | (50 << 8);
    131                 *wtdat = 0x8000;
    132                 *wtcnt = 0x8000;
    133                 //打开狗
    134                 //
    135                  flag=0;
    136              }
    137              else if(flag == 0)
    138              {
    139                  printk("wtc_off
    ");
    140 
    141                 *wtcon = 0 ;
    142                 //关狗
    143                  led_off();
    144                  pwm_off();
    145                  flag=1;
    146              }
    147 
    148      }
    149      if(irq == IRQ_WDT)//如果DOG中断
    150      {
    151          printk("dog  dog   dog  
    ");
    152          static int flag=1;
    153          if(flag)
    154          {
    155              led_on();
    156              pwm_on();
    157              flag=0;
    158          }
    159          else
    160          {
    161              led_off();
    162              pwm_off();
    163              flag=1;
    164          }
    165         *wtclrint = 250;
    166     }
    167     return IRQ_HANDLED;
    168 }

          

                     在内核环境构建中,很多与裸板驱动相同,都跳到函数do_irq()中处理中断,所以,在do_irq中和拷贝裸板的驱动。

  • 相关阅读:
    js简直了,连大小都不能直接比,还变量提升,这个是挖了多少坑啊,故意的把,,,,写起来又不简单,运行起来又不是很稳,很迷啊
    bootstrap 强制左移
    图片轮播/无缝滚动的原理
    jQuery放大镜的原理
    下拉列表的两种实现方式
    Html css图片文本对齐问题
    一键换肤原理
    setInterval与clearInterval用法
    jQuery课堂测验
    Css画圣诞树
  • 原文地址:https://www.cnblogs.com/hongzhunzhun/p/4523957.html
Copyright © 2011-2022 走看看