三星的S5PV210 GPIO中断--寄存器版
S5PV210 是一款三星的cortex-A8系列的处理器,不知什么原因,听说已经停产了,市面上应该都是以前生产的库存品吧。
程序中使用了7个GPIO作为外部中断,奇怪的是在清除中断标志的位置是在获取值之前,因为这个还调试了很久,在此记录一下吧。
//奇怪的是这里只能先清除在取值,之前尝试过取值后在清除,却造成了无法进入中断中
*((unsigned long*)(addr_VIC0_base+VIC0ADDRESS)) = 0;
如下为程序
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //switch cmd define#define MAGIC 0x01#define GET_STATUS _IOR(MAGIC,0x60,unsigned char)//physical address(gph1)#define GPH1_REGISTER 0xE0200C20#define GPH1_CON 0x00//physical address(gph2)#define GPH2_REGISTER 0xE0200C40#define GPH2_CON 0x00#define EXT_INT_CON 0xE0200E00#define EXT_INT_1_CON 0x04#define EXT_INT_2_CON 0x08#define EXT_INT_MASK 0xE0200F00#define EXT_INT_1_MASK 0x04#define EXT_INT_2_MASK 0x08#define EXT_INT_PEND 0xE0200F40#define EXT_INT_1_PEND 0x04#define EXT_INT_2_PEND 0x08#define VIC0_base 0xF2000000#define VIC1_base 0xF2100000#define VIC2_base 0xF2200000#define VIC3_base 0xF2300000#define VIC0VECTADDR 0x100#define VIC0ADDRESS 0xf00#define VIC0INTSELECT 0x0c#define VIC0INTENABLE 0x10#define VIC0IRQSTATUS 0x0#define VIC0INTENCLEAR 0x14//virtual adress(gph1)unsigned long addr_gph1 = 0;//virtual adress(gph2)unsigned long addr_gph2 = 0;unsigned long addr_EXT_INT_CON = 0;unsigned long addr_EXT_INT_MASK = 0;unsigned long addr_EXT_INT_PEND = 0;unsigned long addr_VIC0_base = 0;unsigned long addr_Exception_Vector = 0;#define DEVICENAME "switch"#define CLASSNAME "class"static dev_t devno; static struct cdev cdev; static struct class* switch_class; static struct device* switch_device; int nprintFlag = 0;int nnowChannel = 0;/*********************************************************************photoelectric switchs:switch 1 : gph2_4 //position 1switch 2 : gph2_2 //position 2switch 3 : gph2_3 //position 3switch 4 : gph2_1 //position 4switch 5 : gph1_3 //position 5switch 6 : gph1_6 //position 1 protect motorswitch 7: gph1_7 //position 5 protect motor**********************************************************************/void clear_int_pend(void);void intc_init(void);void irq_handler(void);void IRQ_handle(void);void system_initexception( void);//中断初始化static int switch_open(struct inode *inode, struct file *file){ // system_initexception(); //外部中断对应的GPIO模式设置*((unsigned long*)(addr_gph1+GPH1_CON)) |=(0xff00f<<12); //配置为外部中断模式EXT_INT[11]、EXT_INT[14]、EXT_INT[15]*((unsigned long*)(addr_gph2+GPH2_CON)) |=(0xffff<<4); //EXT_INT[20]、EXT_INT[18]、EXT_INT[19]、EXT_INT[17]//设置中断触发模式 高电平触发*((unsigned long*)(addr_EXT_INT_CON+EXT_INT_1_CON)) |=(0x001<<12|0x001<<24|0x001<<28); //EXT_INT_1_CON[3]、EXT_INT_1_CON[6]、EXT_INT_1_CON[7]*((unsigned long*)(addr_EXT_INT_CON+EXT_INT_2_CON)) |=(0x001<<16|0x001<<8|0x001<<12|0x001<<4); //EXT_INT_2_CON[4]、EXT_INT_2_CON[2]、EXT_INT_2_CON[3]、EXT_INT_2_CON[1]//中断允许*((unsigned long*)(addr_EXT_INT_MASK+EXT_INT_1_MASK)) &= ~ (0x1<<3|0x1<<6|0x1<<7); //外部中断允许*((unsigned long*)(addr_EXT_INT_MASK+EXT_INT_2_MASK)) &= ~ (0x1<<4|0x1<<2|0x1<<3|0x1<<1);*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_1_PEND)) |= (0x1<<3|0x1<<6|0x1<<7);*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_2_PEND)) |= (0x1<<4|0x1<<2|0x1<<3|0x1<<1);intc_init();return 0;}void clear_int_pend(void){//清挂起*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_1_PEND)) |= (0x1<<3|0x1<<6|0x1<<7);*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_2_PEND)) |= (0x1<<4|0x1<<2|0x1<<3|0x1<<1);}static int switch_close(struct inode *inode, struct file *file){ *((unsigned long*)(addr_VIC0_base+VIC0INTENCLEAR)) |=(1<<11|1<<14|1<<15|1<<20|1<<18|1<<19|1<<17);// VIC0INTENCLEAR |= (1<<11|1<<14|1<<15|1<<20|1<<18|1<<19|1<<17);return 0; } static ssize_t switch_ioctl(struct file *file, unsigned int cmd, unsigned long argc){ unsigned long data=-1;int err;int gph1_3 =0;int gph2_1 =0;int gph2_3 =0;int gph2_2 =0;int gph2_4 =0;int gph1_6 =0;int gph1_7 =0;int reg1;int reg2;if(GET_STATUS != cmd) printk("invalid command id for %s\n",DEVICENAME);else{//奇怪的是这里只能先清除在取值,之前尝试过取值后在清除,却造成了无法进入中断中*((unsigned long*)(addr_VIC0_base+VIC0ADDRESS)) = 0;*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_1_PEND)) |= (0x1<<3|0x1<<6|0x1<<7);*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_2_PEND)) |= (0x1<<4|0x1<<2|0x1<<3|0x1<<1);*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_1_PEND)) |= (0x1<<3|0x1<<6|0x1<<7);*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_2_PEND)) |= (0x1<<4|0x1<<2|0x1<<3|0x1<<1);reg1=*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_1_PEND));reg2=*((unsigned long*)(addr_EXT_INT_PEND+EXT_INT_2_PEND));gph1_3 = ((reg1>>3)&0x01);gph2_1 = ((reg2>>1)&0x01);gph2_3 = ((reg2>>3)&0x01);gph2_2 = ((reg2>>2)&0x01);gph2_4 = ((reg2>>4)&0x01);gph1_6 = ((reg1>>6)&0x01);//protect motorgph1_7 = ((reg1>>7)&0x01);//protect motordata = gph1_3 << 0 | gph2_1 << 1 | gph2_3 << 2 | gph2_2 << 3 | gph2_4 << 4 | gph1_6 << 5 |gph1_7 << 6;//add protect motor}err = put_user(data, (int *)argc);return err;}void intc_init(void){*((unsigned long*)(addr_VIC0_base+VIC0ADDRESS)) = 0;*((unsigned long*)(addr_VIC0_base+VIC0INTENCLEAR)) |=(1<<11|1<<14|1<<15|1<<20|1<<18|1<<19|1<<17);*((unsigned long*)(addr_VIC0_base+VIC0INTSELECT)) &= ~(1<<11|1<<14|1<<15|1<<20|1<<18|1<<19|1<<17); //选择中断类型为IRQ//设置EXT_INT[11]~EXT_INT[20]对应的中断服务程序的入口地址16-20共用一个*((unsigned long*)(addr_VIC0_base+VIC0VECTADDR+4*11))= (unsigned)switch_ioctl;//中断函数入口*((unsigned long*)(addr_VIC0_base+VIC0VECTADDR+4*14))= (unsigned)switch_ioctl;*((unsigned long*)(addr_VIC0_base+VIC0VECTADDR+4*15))= (unsigned)switch_ioctl;*((unsigned long*)(addr_VIC0_base+VIC0VECTADDR+4*16))= (unsigned)switch_ioctl;*((unsigned long*)(addr_VIC0_base+VIC0INTENABLE)) |= (1<<11|1<<14|1<<15|1<<16);}struct file_operations switch_ops = { .open = switch_open, .release = switch_close, .unlocked_ioctl = switch_ioctl, }; static int __init switch_init(void){ int ret;cdev_init(&cdev,&switch_ops); cdev.owner = THIS_MODULE; ret = alloc_chrdev_region(&devno, 0, 1,DEVICENAME); if(ret){ printk(KERN_ERR "alloc char device region faild!\n"); return ret; } ret = cdev_add(&cdev, devno, 1); if(ret){ printk(KERN_ERR "add char device faild!\n"); goto add_error; } // 在sys/class下创建名为switch_class的类switch_class = class_create(THIS_MODULE, CLASSNAME); if(IS_ERR(switch_class)){ printk(KERN_ERR "create class error!\n"); goto class_error; }//在 名为switch_class的类创建XP_switch设备switch_device = device_create(switch_class, NULL, devno, NULL, DEVICENAME); if(IS_ERR(switch_device)){ printk(KERN_ERR "create buttons device error!\n"); goto device_error; } //physical adress to virtual adressaddr_gph1 = (unsigned long)ioremap(GPH1_REGISTER,0x10);addr_gph2 = (unsigned long)ioremap(GPH2_REGISTER,0x10);addr_EXT_INT_CON = (unsigned long)ioremap(EXT_INT_CON,0x10);addr_EXT_INT_MASK = (unsigned long)ioremap(EXT_INT_MASK,0x10);addr_EXT_INT_PEND = (unsigned long)ioremap(EXT_INT_PEND,0x10);addr_VIC0_base = (unsigned long)ioremap(VIC0_base,0xFFF);// addr_Exception_Vector = (unsigned long)ioremap(_Exception_Vector,0x20);printk("%s is installed\n",DEVICENAME);return 0; device_error: class_destroy(switch_class); class_error: cdev_del(&cdev); add_error: unregister_chrdev_region(devno,1); return -ENODEV; } void __exit switch_exit(void){ iounmap((void*)addr_gph2);iounmap((void*)addr_gph1);iounmap((void*)addr_EXT_INT_CON);iounmap((void*)addr_EXT_INT_MASK);iounmap((void*)addr_EXT_INT_PEND);iounmap((void*)addr_VIC0_base);// iounmap((void*)addr_Exception_Vector);device_destroy(switch_class, devno); class_destroy(switch_class); cdev_del(&cdev); unregister_chrdev_region(devno, 1); printk("%s is uninstalled\n",DEVICENAME);} module_init(switch_init); module_exit(switch_exit); MODULE_LICENSE("GPL");
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
