有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 皋陶 于 2020-8-25 18:01 编辑
Sifive Learn Inventor 基础之gpio 按键中断
本文目录
Sifive Learn Inventor是Sifive的一款基于RISC-V内核的开发板,具体见官网的Hifive Rev b 的文档
一,硬件连接芯片的gpio11连接到buttonA,如下,可见,按键按下是低电平,所以我们可以设置gpio11为下降沿中断来实现按键中断。
二,代码编写
- /**
- *buttona初始化为下降沿触发中断
- */
- void ButtonA_init(int *flag)
- {
-
- struct metal_gpio *gpio0;//声明一个gpio对象
- int buttonA_id=12;//根据芯片手册查询到gpio11的中断id的为12
- gpio0=metal_gpio_get_device(0);//实例化gpio对象
- //获得gpio控制器,其实就是plic
- buttonA_intr=metal_gpio_interrupt_controller(gpio0);
-
- metal_interrupt_init(buttonA_intr);
- //注册回调函数 buttonA_isr是回调函数的函数名,最后传递的flag是一个指针,是传递给回调函数的参数
- metal_interrupt_register_handler(buttonA_intr,buttonA_id,buttonA_isr,flag);
- //设置优先级为3
- metal_interrupt_set_priority(buttonA_intr,buttonA_id,3);
-
- //enable gpio
- metal_gpio_disable_output(gpio0,11);
- metal_gpio_enable_input(gpio0,11);
-
- //禁止gpio功能复用
- metal_gpio_disable_pinmux(gpio0,11);
-
- //先关闭一下中断
- metal_gpio_config_interrupt(gpio0,11,METAL_GPIO_INT_DISABLE);
-
- //清楚gpio中断的所有标志位
- metal_gpio_clear_interrupt(gpio0,11, METAL_GPIO_INT_MAX);
- //配置为下降沿中断
- metal_gpio_config_interrupt(gpio0,11,METAL_GPIO_INT_FALLING);
- //使能gpio11
- metal_interrupt_enable(buttonA_intr,buttonA_id);
- }
复制代码
2,中断服务函数中,改变全局变量flag的值,随后在主函数中判断flag的值,再进入处理函数;
这里的中断函数的名称是可以随意取的,但是传递的参数必须是固定的int id, void data,voiddata 是由初始化注册回调函数的传递过来的无类型的一个指针。在回调函数中,先拿到gpio对象,然后清楚gpio11的下降沿中断的标志位。然后从data里拿到flag的地址,从而改变flag的值。
- /**
- *buttona回调函数 清除下降沿中断标志位,将flag置2
- */
- void buttonA_isr (int id, void *data){
- struct metal_gpio *gpio0=metal_gpio_get_device(0);
- metal_gpio_clear_interrupt(gpio0, 11,METAL_GPIO_INT_FALLING);
- int *flag=(int *)data;
- *flag=2;
- }
复制代码
3,在main()函数中检测flag的值
- while(1){
- if(flag==2){
- fun();
- }
- }
复制代码
三,小结
这是一个简单的gpio中断的配置,从这个例子出发,来讨论一下sifive的中断是如何完成的。然后就可以依样画葫芦,其他外设的中断也可以相对容易的去理解。
中断产生的过程大概是这样的:
inturrpt就是我们的中断源,当我们的按键按下时,gpio11就产生了一个中断请求,中断信号先来到plic控制器,plic根据请求的优先级来给中断请求排队,根据中断的id来找到中断服务程序的入口,随后进入中断服务函数,当完成中断服务函数后,plic相应的id的中断标志位会被置0
根据手册可以知道plic负责管理所有外设的中断请求,从下表可以知道外设对应的中断id。
其实上面代码中的buttonA_intr=metal_gpio_interrupt_controller(gpio0);这个函数就是把plic控制器的对象负责给buttonA_intr,这样通过操作buttonA_intr,其实也就是对plic的操作。
综上,要初始化一个外设中断,我们需要配置外设的中断寄存器,同时还要拿到plic对象,中断id,接下来就是配置plic,设置回调函数和中断优先级。这时候再来看初始化代码
这两个语句就是获取中断id和plic;
int buttonA_id=12;
buttonA_intr=metal_gpio_interrupt_controller(gpio0);
初始化一下plic,主要是把plic对象里的一些参数赋值为0或null
metal_interrupt_init(buttonA_intr);
这个函数就是配置plic的作用,在plic的中断表里id=12的地方写入中断回调函数的地址和传递的参数
metal_interrupt_register_handler(buttonA_intr,buttonA_id,buttonA_isr,flag);
设置一下优先级,使能这个中断
metal_interrupt_set_priority(buttonA_intr,buttonA_id,3);
metal_interrupt_enable(buttonA_intr,buttonA_id);
至此,一个中断初始化的plic部分就设置完成了,另一部分,外设的中断寄存器配置就要根据手册的说明或者库函数去相应的配置
可以根据下面的图片理解plic,其实初始化一个外设中断就像是给下面的表格填写对应的内容,我们需要的就是plic对象,id,回调函数地址,优先级,传递参数。更多的plic内容查看芯片手册。
本篇完,感谢关注:RISC-V单片机中文网
|