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中和拷贝裸板的驱动。

原文地址:https://www.cnblogs.com/hongzhunzhun/p/4523957.html