电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
GD32VF103之中断最小配置
分 享
扫描二维码分享
GD32VF103之中断最小配置
中断
gd32vf
gcrisis
关注
发布时间: 2020-10-09
丨
阅读: 1111
![](https://cf04.ickimg.com/bbsimages/202009/ac5b2acbe8bfd75e5e87b098c3a40f94.png) **中断**是一颗芯片非常重要的功能之一,芯片没有了中断就像雷神没了他的锤头一样,“战斗力”大大下降。 在Bumblebee内核用户手册中对中断的概述如下,很好的解释了中断机制和中断的核心知识点。 ![](https://cf04.ickimg.com/bbsimages/202009/b59c8a000844d9746c7842f1975f117e.png) gd32vf103的中断配置大致分为下面几步: ** 1、打开全局中断; 2、设置优先级组; 3、打开对应设备的中断; 4、设置该设备中断的level和priority; 5、打开该设备具体某个功能的中断; 6、编写中断服务程序;** ###**1、打开全局中断** 在GD32VF103系列器件的系统架构示意图中,内核部分有一个**ECLIC**,这就是中断控制器,全称是“**改进型内核中断控制器 (Enhanced Core Local Interrupt Controller,ECLIC)**“,是基于RISC-V标准的CLIC优化而来。 ![](https://cf04.ickimg.com/bbsimages/202009/a3f9a2ee0a579661b0a65c7bdc8baa7b.png) ECLIC是存储器映射单元,它的基地址是**0xd2000000**,寄存器和地址偏移如图所示: ![](https://cf04.ickimg.com/bbsimages/202009/73e89547241d978b8366326ccbb57c82.png) 它与核心的关系如下图所示。eclic左边进来的箭头是各种外设的中断源,右边出去的箭头是**全局中断**,我们要开的全局中断就是这个右边的箭头。只有打开它外设的中断才能告知处理器内核,它就是整个中断系统的**总开关**。 ![](https://cf04.ickimg.com/bbsimages/202009/08d6f323bea1c3d87f528c09f122ac6d.png) 打开全局中断需要操作寄存器**mstatus**,它是内核寄存器,操作它直接使用单词mstatus,编译器就知道它是谁。它的控制位如图所示,**bit3**的**MIE**就是全局中断使能位,写1全局中断打开,写0全局中断关闭。 ![](https://cf04.ickimg.com/bbsimages/202009/f5f6b031c5f9eca4c0cfbee6b60a17be.png) 具体的代码如下: ![](https://cf04.ickimg.com/bbsimages/202009/aa1a93b333e155a8f6a8b3fa87160d6a.png) **set_csr**是一个宏定义,具体内容为一串汇编。关于汇编的内容,我后边可能会写文章介绍(不敢挖这个坑)。 ![](https://cf04.ickimg.com/bbsimages/202009/935237eaefd7ddb23474f2fdd56789ec.png) ###**2、设置优先级组** ECLIC中断控制器的每个中断源都可以设置不同的**级别(Level)**和**优先级(Priority)**。Level越大级别越高,高Level可以打断低Level的中断进而形成嵌套,在多个中断同时等待需要进行仲裁时要参考Level值。Priority是越大优先级越高,优先级不参与中断嵌套的判断,而是多个中断同时pending时,通过Priority来仲裁决定哪个中断发送到内核。 Bumblebee内核硬件实现使用了**4位宽**来配置Level和Priority,可以通过读取**clicinfo**寄存器的**CLICINTCTLBITS**得到。 ![](https://cf04.ickimg.com/bbsimages/202009/80251b745eb95414df4ba4d33354858c.png) 配置优先级组其实就是如何将这4位分配给Level和Priority。通过**cliccfg**寄存器的**nlbits**指定Level的宽度,剩下的就是Priority的宽度。 ![](https://cf04.ickimg.com/bbsimages/202009/9b1df8b502049af40f58f99dcea70195.png) ![](https://cf04.ickimg.com/bbsimages/202009/b947d1c11d9497eb0bbb5ecf3ab62d6c.png) 如图配置nlbits为2,就表示用两位表示Level,2位表示Priority,那么Level和Priority就可以各有4个等级;如果nlbits为3,那么Level就有8个等级,Priority只有一个等级。以此类推,所以一共可以有5种情况——nlbits可以为**0,1,2,3,4**。 具体代码如下: ![](https://cf04.ickimg.com/bbsimages/202009/7a77f13290675281fc9837fae31b4626.png) ###**3、打开对应设备的中断** 在上文ECLIC与核心关系图中,左边有很多中断源,这些中断源有内核内部的,也有内核外部即外设的。Bumblebee 内核中**0-18**预留作为了内核特殊的**内部中断**,目前实际用到的只有**4**个。**19**以后是普通**外部中断**,到**86**就没了。实际起作用的中断源一共**63**个。 ![](https://cf04.ickimg.com/bbsimages/202009/6b3e66c6b31277dc57b0c0df17cfc68d.png) 打开外设的中断就是要使能这些中断源,让对应的中断信号能够被ECLIC捕获。通过ECLIC寄存器**clicintie[i]**来配置,i就是中断源的向量编号,它只有**bit0**有效,写1中断源被打开,写0中断源被屏蔽。 ![](https://cf04.ickimg.com/bbsimages/202009/af266f60318e584c8775d974077177fc.png) 这里以串口0的中断为例,它的中断向量号是56,具体代码如下: ![](https://cf04.ickimg.com/bbsimages/202009/8100c57f582d432a2ffcbb4d7da5fe15.png) 关于串口0的内容可以查看我的另一篇文章 《[GD32VF103之串口uart最小配置](https://www.icxbk.com/article/detail/1759.html "GD32VF103之串口uart最小配置")》。 ###**4、设置该设备中断的level和priority** 我们前面已经讲过Level和Priority,这里就要给外设设置具体的值了,ECLIC就是通过比较这里设置的值来决定不同中断执行的先后顺序的。这里我设置Level和Priority都是1,寄存器是**clicintctl[i]**,它是8位的寄存器,**bit[7:6]**设置level,**bit[5:4]**设置priority。具体代码如下(ECLICINTCTLBITS=4): ![](https://cf04.ickimg.com/bbsimages/202009/16e996b86ee0a0ada0238594ffa90fa2.png) ###**5、打开该设备具体某个功能的中断** 通过上面的步骤,关于中断控制器本身的配置就完成了。下面我们需要在外设端打开对应的中断使能位。这里继续以串口0为例,**控制寄存器0**的**bit5**是读数据缓冲区非空中断和过载错误中断使能,就是我们需要的接收数据中断使能。 ![](https://cf04.ickimg.com/bbsimages/202009/3ceb60d5705bdc52a89a56d2927d413b.png) 具体代码如下: ![](https://cf04.ickimg.com/bbsimages/202009/fdc553c66751e933a202cd91723685c8.png) 对于像串口0这种外设,它的功能中断有很多,比如接收数据非空、发送完成、错误、校验错误等等,而ECLIC的串口0中断源只有一个,也就是说所有外设的功能中断是**或**的关系,只要有一个触发就会触发串口0的中断,具体是什么中断需要我们在中断服务程序中判断。 ![](https://cf04.ickimg.com/bbsimages/202009/d45b4926154b2069b1cf70057bde53bf.png) ###**6、编写中断服务程序** 中断服务程序是在中断触发后调用的一个函数,虽然都是函数,但是它与普通函数有一些区别,比如执行的上下文环境不同,执行时芯片的模式不同,执行时间要求不同等等。 ECLIC的每个中断源可以配置成**向量**或者**非向量**模式,向量模式是每一个中断源有一个中断服务程序入口地址,中断触发后会直接跳到这个地址执行中断服务程序;而非向量模式是所有的非向量中断有一个公共地址,中断来了后会跳到这个公共地址处执行。关于它们的具体内容可以查阅Bumblebee内核数据手册,这里我们使用**向量模式**。 **中断向量入口**代码在**start.S**文件中,它是汇编写的启动文件,一般厂家会提供,他与手册中的中断向量表一一对应。 ![](https://cf04.ickimg.com/bbsimages/202009/f3a5945e89561f06096e313e1749e5fe.png) 我们不能随意定义中断服务程序,关键字.word后的xxx_IRQHandler就是中断服务程序的函数名称,所以串口0的中断服务程序就应该这样: ![](https://cf04.ickimg.com/bbsimages/202009/0e25a521918b1fb5473a50c56adaacba.png) 这里就是判断一下是否为**读数据缓冲区非空**中断,如果是就读取数据。手册上有说”**只要是对 USART_DATA寄存器的一个读操作都可以清除RBNE位**”,这里可以看出,如果连续接收n个数据,就会触发n次中断,而不是一个中断读取多个数据。对于大量数据的读取发送,最好采用DMA的方式。关于DMA我后边会写文章介绍。 这里还抛了一个问题,就是我这个**uart_recv()**函数内部是有一个临时变量来读取并保存数据的,但是如果我只调函数没有左边的赋值,中断就会出问题,本来一个中断变成了两个,搞不明白为什么,欢迎大家帮我解惑。 ![](https://cf04.ickimg.com/bbsimages/202009/bd521ae32001ed162f42883b6d34acf1.png) 到这里中断的整个流程就走完了,当然严格来讲最开始还有eclic的初始化,这里工程自动帮我配置了,而且是在调用main之前,所以我就把它略过了。 实际做项目我想大家都会使用官方提供的sdk,那配置中断只需调用3个函数就搞定了,也就是把我上面1-4步的内容封装起来了。我傻傻的这么搞目的是要大家了解更多背后的东西,这样可能会对更好的理解和使用中断有所帮助。 ok,如果本文对你有所帮助,就用你们力所能及的方式支持我吧(点赞、分享都行)! **参考文档:**《GD32VF103_User_Manual_CN_V1.2》,《Bumblebee core datasheet_cn》
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
gcrisis
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交