首页 > 其他分享 >RV1126按键中断驱动和应用调试

RV1126按键中断驱动和应用调试

时间:2023-07-05 17:25:32浏览次数:49  
标签:cnt rp RV1126 buttons num 按键 gpio data 调试

 本人使用的调试平台是荣品的rv1126开发板,最近在调试按键中断。经过查看原理图,发现竟然没有一个空闲的IO,所以使用UART1的RX作为按键中断引脚。         驱动部分:           因为UART1原先已经在设备树中已经有了定义,需要将 kernel/arch/arm/boot/dts/rongpin/rv1126_1109_common.dtsi 中的uart1去掉   //&uart1 { // pinctrl-names = "default"; // pinctrl-0 = <&uart1m0_xfer>; // status = "okay"; //}; 并在kernel/arch/arm/boot/dts/rp-rv1126.dts 中的rp_gpio,加入该IO:   rp_gpio { status = "okay"; compatible = "rp_gpio";                  gpio0b7{             gpio_num = <&gpio0 RK_PB7 IRQ_TYPE_EDGE_FALLING>;  gpio_function = <2>;         };         ......         设备树修改完毕,下面开始编写代码。           rv1126的gpio采用的是gpiolib架构,工程师可以不必查阅寄存器即可完成配置,在kernal/drivers/rongpin/rp_gpio.c中修改。           1、修改probe:              static int rp_gpio_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct device_node *child_np; static struct proc_dir_entry *root_entry_gpio; enum of_gpio_flags  gpio_flags; int ret = 0; int gpio_cnt = 0; char gpio_name_num[GPIO_NUM_MAX]; int gpio_in_cnt = 0;     gpio_data = devm_kzalloc(&pdev->dev, sizeof(struct rp_gpio_data),GFP_KERNEL); if (!gpio_data) { dev_err(&pdev->dev, "failed to allocate memory\n"); return -ENOMEM; }   gpio_data->gpio_dts_num = of_get_child_count(np);         printk("rp_gpio prepare build %d gpio\n",gpio_data->gpio_dts_num);       if (gpio_data->gpio_dts_num == 0){         dev_info(&pdev->dev, "no gpio defined\n"); }   /* create node */ root_entry_gpio = proc_mkdir("rp_gpio", NULL);   for_each_child_of_node(np, child_np) { /* parse dts */ gpio_data->rp_gpio_num[gpio_cnt].gpio_num = of_get_named_gpio_flags(child_np, "gpio_num", 0, &gpio_flags); if (!gpio_is_valid(gpio_data->rp_gpio_num[gpio_cnt].gpio_num)){ return -1; }   gpio_data->rp_gpio_num[gpio_cnt].gpio_name = (char*)child_np -> name; gpio_data->rp_gpio_num[gpio_cnt].action = gpio_flags; gpio_data->rp_gpio_num[gpio_cnt].gpio_ctrl = gpio_cnt; of_property_read_u32(child_np, "gpio_function", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_function));   printk("rp_gpio request %s\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_name);     switch(gpio_data->rp_gpio_num[gpio_cnt].gpio_function) { case GPIO_FUNCTION_INPUT :/* init input gpio */ ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0) { printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); }else{ printk("success request gpio %d in\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);   //gpio_set_value(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num); event_flag = gpio_flags; of_property_read_u32(child_np, "send_mode", &(gpio_data->rp_gpio_num[gpio_cnt].send_mode)); of_property_read_u32(child_np, "gpio_event", &(gpio_data->rp_gpio_num[gpio_cnt].gpio_event)); gpio_in_cnt++; } break; #if 1 case GPIO_FUNCTION_IRQ :/* init input gpio */   ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0) { printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); }else{ printk("success request gpio %d irq\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num);   //gpio_set_value(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); printk("gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num) = %d\n",gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num)); irq_gpio = gpio_data->rp_gpio_num[gpio_cnt].gpio_num; gpio_direction_input(gpio_data->rp_gpio_num[gpio_cnt].gpio_num); ret  = request_irq(gpio_to_irq(gpio_data->rp_gpio_num[gpio_cnt].gpio_num), button_irq_handler, //IRQ_TYPE_EDGE_FALLING, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "key_irq", NULL);     //1、分配一个input_dev结构体 buttons_dev = input_allocate_device(); if(!buttons_dev) { printk("input_allocate_device error!\n"); return -ENOMEM; } buttons_dev->name = "input_key"; buttons_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_set_capability(buttons_dev, EV_KEY, KEY_0);   ret = input_register_device(buttons_dev); if (ret) { printk("register input device failed!\r\n"); return ret; }   //初始化定时器,用于按键消抖 timer_setup(&buttons_timer,my_buttons_timer_function,0); buttons_timer.expires = jiffies + msecs_to_jiffies(20); add_timer(&buttons_timer); } break; #endif case GPIO_FUNCTION_OUTPUT :/* init output gpio */ ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0){ printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); //return ret; }else{ gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); printk("success request gpio%d out\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); } break;   case GPIO_FUNCTION_FLASH : ret = gpio_request(gpio_data->rp_gpio_num[gpio_cnt].gpio_num, "gpio_num"); if (ret < 0){ printk("gpio%d request error\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); //return ret; }else{ gpio_direction_output(gpio_data->rp_gpio_num[gpio_cnt].gpio_num,!gpio_data->rp_gpio_num[gpio_cnt].action); printk("success request gpio%d flash\n",gpio_data->rp_gpio_num[gpio_cnt].gpio_num); gpio_in_cnt++;   } break; }   sprintf(gpio_name_num,gpio_data->rp_gpio_num[gpio_cnt].gpio_name,gpio_cnt); proc_create(gpio_name_num, 0666 , root_entry_gpio , &gpio_ops); gpio_cnt++; }     gpio_wq = create_singlethread_workqueue("gpio_wq"); INIT_WORK(&gpio_work, gpio_work_func);   platform_set_drvdata(pdev, gpio_data); return 0; }           代码中的case GPIO_FUNCTION_IRQ是新增加的,主要是申请IO、设置IO方向、注册中断函数、配置输入子系统、初始化定时器。其中定时器是用来消抖的。按键信号通过输入子系统传递到应用程序。           2、增加外部中断以及定时器服务函数。     unsigned irq_gpio; static struct input_dev *buttons_dev; static struct timer_list buttons_timer;   static irqreturn_t button_irq_handler(int irq, void *dev_id) {     mod_timer(&buttons_timer, jiffies+msecs_to_jiffies(20));     return IRQ_HANDLED; }     //定时器中断处理函数 static void my_buttons_timer_function(struct timer_list* list) { int gpio_value = 0; gpio_value = gpio_get_value(irq_gpio);   if(gpio_value == 0) { input_report_key(buttons_dev, KEY_0, 1); input_sync(buttons_dev); } if(gpio_value == 1) { input_report_key(buttons_dev, KEY_0, 0); input_sync(buttons_dev); } }              应用程序:           编写应用程序之前,先使用cat /proc/bus/input/devices 确定驱动使用了哪个输入子系统的event。           应用程序比较简单。           检测输入子系统信号采用一个线程,以下函数为线程函数:              void *scan_key_main(void *data) {     int fd = 0;     struct input_event buttons_event;     unsigned long cur_ms = 0;     data = data;          //fd = open("/dev/event0", O_RDWR | O_NONBLOCK);     fd = open("/dev/input/event3", O_RDWR);     if (fd < 0)     {         printf("can't open!\n");     }       while (1)     {         read(fd, &buttons_event, sizeof(struct input_event));   //        if(buttons_event.type == EV_SYN) //            continue;           cur_ms = (buttons_event.time.tv_sec * 1000) + (buttons_event.time.tv_usec/1000);           //打印时间,事件类型,事件码,事件值         printf("cur_ms:%ld type:0x%x code:%d value:%d\n",             cur_ms,             buttons_event.type,             buttons_event.code,             buttons_event.value);     } }           如果在调试过程中出现问题,可以使用hexdump /dev/input/eventX命令辅助调试。  

标签:cnt,rp,RV1126,buttons,num,按键,gpio,data,调试
From: https://www.cnblogs.com/kn-zheng/p/17529074.html

相关文章

  • 【快应用】ad-button按钮与加桌组件文案调试
    ​ 【关键词】体验版、文案配置、广告、加桌 【问题背景】快应用引擎版本更新到1106版本后,广告ad-button和加桌组件新增了预制文案配置,仅支持使用已有的,不再支持自定义文案。在使用最新版本的加载器进行调试的时候,设置的文案不能生效仍是显示的是默认的文案,该如何处理?代码......
  • JAVA 调试高内存占用与CPU满载异常场景
    高内存占用,堆溢出,OOM代码: @RequestMapping(value="/oom",method={RequestMethod.GET}) publicResultBasegetMessage2()throwsInterruptedException{ List<String>strList=Lists.newArrayList(); for(inti=0;i<10240;i++){ strLi......
  • 西门子S7系列PLC以太网通讯处理器编程调试方法
    捷米特(北京)科技有限公司研发的捷米特以太网通讯模块,转以太网通讯模块型号有ETH-S7200-JM01和ETH-S7300-JM01,适用于西门子S7-200/S7-300/S7-400、SMARTS7-200、西门子数控840D、840DSL、合信、亿维PLC的PPI/MPI/PROFIBUS转以太网。用于西门子S7-200/S7-300/S7-400程序上下载、上位......
  • vscode 连接 wsl2 下 linux 配置纯 clang 编译调试环境
    安装clang和lldb本人为ArchLinux,执行命令sudopacman-Sclanglldbvscode插件vscode安装clangd和codelldb(调试用)插件,其中codelldb插件建议手动安装,官方下载连接:codelldb-linux.vsix。下载好后移进文件夹中,用vscode打开,右键该文件安装扩展即可。配置文......
  • 前端学习 C 语言 —— GDB调试器
    GDB调试器我们在讲指针时用GDB调试段错误。本篇将详细介绍gdb的最常用命令、日志记录、检测点,最后介绍如何用gdb调试进程以及用gdb调试一个开源项目的调试版本——glmark2。gdb介绍GDB,theGNUProjectdebugger——gdb官网gdb是一款调试器,能打断点。支持多种语......
  • 编译安装openGauss并用GDB进行调试
    编译安装openGauss并用GDB进行调试惜月夜于2021-06-2818:15:07发布1810收藏2分类专栏:openGauss文章标签:数据库版权openGauss专栏收录该内容1篇文章0订阅订阅专栏编译安装openGauss并用GDB进行调试关于编译opengauss,然后怎么去调试它,不知道花了多长时间.本来想着用......
  • php 根据条件打印输出,方便调试
    laravel核心代码调试起来,还是挺麻烦的,循环太多了。当从某个路由进去之后,进入到核心内部,断点打印的可能根据不是你认为的执行过程。为此,我想到了条件打印,跟用idedebug设置条件一样的思想。不过还是觉得打印更加直观一些吧。代码很简单,一看就懂,不过多介绍了。  <?php......
  • Idea远程debug调试本地代码 Remote JVM Debug
    如果项目太大本地启动不了,或者假设你项目是微服务项目依赖太多,你写了个功能后,想本地启动debug调试又不方便,此时可以用一个idea远程debug神奇。实现访问测试环境,回调到你本地启动的代码。1,准备一个springboot项目什么都不用配置2,idea设置RemoteJVMDebug端口随便设置就行......
  • 08_调试与使用虚拟的GPIO控制器
    目录资料下载视频观看调试与使用虚拟的GPIO控制器1.硬件功能2.编写设备树文件3.上机实验3.2编译、替换设备树3.3编译、安装驱动程序4.STM32MP157上的bug资料下载coding无法使用浏览器打开,必须用git工具下载:gitclonehttps://e.coding.net/weidongshan/linux/doc_and_sourc......
  • 【调试笔记】韦东山:在100ASK_IMX6ULL板子上支持其他型号的屏幕
    论  坛:http://bbs.100ask.net/(学术答疑)公 众 号:百问科技版本日期作者说明V12020韦东山技术文档在100ASK_IMX6ULL板子上支持其他型号的屏幕1.在100ASK_IMX6ULL底板上如何接其他厂家的屏幕很多学员有过STM32的学习经验,他们手上的开发板很多,LCD也很多。一个LCD还挺贵的,不能浪......