【GD32 MCU入门教程】四、GD32 MCU 常见外设介绍(3)NVIC 介绍

news2024/11/17 16:01:31

NVIC(Nested vectored interrupt controller,嵌套向量中断控制器)是Cortex-M处理器的一部分,它是可编程的,且寄存器位于存储器映射的系统控制空间(SCS)。NVIC与内核相辅相成,共同完成对中断的响应。本章将介绍中断的优先级设置、如何定义中断函数名称、中断向量如何偏移。有关NVIC的更多知识,请见《ARM Coretex-M3权威指南》。

3.1.优先级的设置

在Cortex-M中,优先级对于异常来说很关键的,它会影响一个异常是否能被响应,以及何时可以响应。优先级的数值越小,则优先级越高。Cortex-M支持中断嵌套,使得高优先级异常会抢占低优先级异常。有3个系统异常:复位,NMI以及硬fault,它们有固定的优先级,并且它们的优先级号是负数,从而高于所有其它异常。所有其它异常的优先级则都是可编程的,但不能编程为负数。

原则上,Cortex-M支持3 个固定的高优先级和多达256 级的可编程优先级,并且支持128级抢占。但是,绝大多数CM3芯片都会精简设计,以致实际上支持的优先级数会更少,如8级,16级,32级 等。它们在设计时会裁掉表达优先级的几个低端有效位,以达到减少优先级数的目的。

举例来说,如果只使用了4位来表达优先级,则优先级配置寄存器的结构如图所示。

使用 4bit 表达优先级

输入图片说明

GD32Fxxx系列、GD32E50x系列、GD32H7xx系 列、GD32A5x系列、GD32W51x系列和GD32VF103、GD32E10X系列使用了4位来表达优先级。GD32E23x和GD32L23x使用的是M23内核,只使用了2位表达优先级。

说明:GD32Fxxx系列是指:GD32F10x、GD32F1x0、GD32F20x、GD32F30x、GD32F3x0、GD32F40x、GD32F4xx。

用于表达优先级的这4bit,又被分组成抢占优先级和子优先级。如果有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行。如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

GD32Fxxx系列、GD32E10x系列、GD32E50x系列、GD32H7xx系列、GD32A5x系列、GD32W51X系列和GD32VF103和GD32E10x系列可以设置抢占优先级和子优先级的等级,GD32E23x和GD32L23x系列没有抢占优先级和子优先级的说法,只可以设置优先级。

下面以GD32F10x举例说明如何设置优先级位数以及抢占优先级和子优先级的等级。在GD32f10x_misc.c文件中,nvic_priority_group_set函数用于设置多少位用于抢占优先级,多少位用于子优先级;nvic_irq_enable函数用于设置相应中断的抢占优先级和子优先级的等级。比如现在要设置SPI0的中断,其抢占优先级和子优先级的位数均为2,抢占优先级的等级为0,子优先级 的等级为1,那么代码如代码清单SPI0中断优先级设置所示。

nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
nvic_irq_enable(SPI0_IRQn,0,1);

有关这两个函数的原型以及函数参数的说明,请见代码清单nvic_priority_group_set函数原型、参数nvic_prigroup说明表、代码清单nvic_irq_enable函数原型、nvic_irq_enable()函数的参数说明表。

代码清单nvic_priority_group_set 函数原型

void nvic_priority_group_set(uint32_t nvic_prigroup)
{
 /* set the priority group value */
 SCB->AIRCR = NVIC_AIRCR_VECTKEY_MASK | nvic_prigroup;
}

参数 nvic_prigroup 说明表

输入图片说明

代码清单nvic_irq_enable 函数原型

void nvic_irq_enable(uint8_t nvic_irq, 
 uint8_t nvic_irq_pre_priority, 
 uint8_t nvic_irq_sub_priority)
{
 uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;
 /* use the priority group value to get the temp_pre and the temp_sub */
 switch ((SCB->AIRCR) & (uint32_t)0x700U) {
 case NVIC_PRIGROUP_PRE0_SUB4:
 temp_pre = 0U;
 temp_sub = 0x4U;
 break;
 case NVIC_PRIGROUP_PRE1_SUB3:
 temp_pre = 1U;
 temp_sub = 0x3U;
 break;
 case NVIC_PRIGROUP_PRE2_SUB2:
 temp_pre = 2U;
 temp_sub = 0x2U;
 break;
 case NVIC_PRIGROUP_PRE3_SUB1:
 temp_pre = 3U;
 temp_sub = 0x1U;
 break;
 case NVIC_PRIGROUP_PRE4_SUB0:
 temp_pre = 4U;
 temp_sub = 0x0U;
 break;
 default:
 nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
 temp_pre = 2U;
 temp_sub = 0x2U;
 break;
 }
 /* get the temp_priority to fill the NVIC->IP register */
 temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
 temp_priority |= nvic_irq_sub_priority &(0x0FU >> (0x4U - temp_sub));
 temp_priority = temp_priority << 0x04U;
NVIC->IP[nvic_irq] = (uint8_t)temp_priority;
 /* enable the selected IRQ */
 NVIC->ISER[nvic_irq >> 0x05U] = (uint32_t)0x01U << (nvic_irq & (uint8_t)0x1FU);
}

nvic_irq_enable()函数的参数说明表

输入图片说明

参数nvic_irq是一个枚举变量,它定义了每一个中断的编号,具体定义在gd32f10x.h文件中,如代码清单中断号定义所示。

typedef enum IRQn
{
 /* Cortex-M3 processor exceptions numbers */
 NonMaskableInt_IRQn = -14, /*!< 2 non maskable interrupt */
 MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 memory management interrupt */
 BusFault_IRQn = -11, /*!< 5 Cortex-M3 bus fault interrupt */
 UsageFault_IRQn = -10, /*!< 6 Cortex-M3 usage fault interrupt */
 SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV call interrupt */
 DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 debug monitor interrupt */
 PendSV_IRQn = -2, /*!< 14 Cortex-M3 pend SV interrupt */
 SysTick_IRQn = -1, /*!< 15 Cortex-M3 system tick interrupt */
 /* interruput numbers */
 WWDGT_IRQn = 0, /*!< window watchDog timer interrupt */
 LVD_IRQn = 1, /*!< LVD through EXTI line detect interrupt */
 TAMPER_IRQn = 2, /*!< tamper through EXTI line detect */
 RTC_IRQn = 3, /*!< RTC through EXTI line interrupt */
 FMC_IRQn = 4, /*!< FMC interrupt */
 RCU_CTC_IRQn = 5, /*!< RCU and CTC interrupt */
 EXTI0_IRQn = 6, /*!< EXTI line 0 interrupts */
 EXTI1_IRQn = 7, /*!< EXTI line 1 interrupts */
 EXTI2_IRQn = 8, /*!< EXTI line 2 interrupts */
 EXTI3_IRQn = 9, /*!< EXTI line 3 interrupts */
 EXTI4_IRQn = 10, /*!< EXTI line 4 interrupts */
 DMA0_Channel0_IRQn = 11, /*!< DMA0 channel0 interrupt */
 DMA0_Channel1_IRQn = 12, /*!< DMA0 channel1 interrupt */
 DMA0_Channel2_IRQn = 13, /*!< DMA0 channel2 interrupt */
 DMA0_Channel3_IRQn = 14, /*!< DMA0 channel3 interrupt */
 DMA0_Channel4_IRQn = 15, /*!< DMA0 channel4 interrupt */
 DMA0_Channel5_IRQn = 16, /*!< DMA0 channel5 interrupt */
 DMA0_Channel6_IRQn = 17, /*!< DMA0 channel6 interrupt */
 ADC0_1_IRQn = 18, /*!< ADC0 and ADC1 interrupt */
#ifdef GD32F10X_MD
 USBD_HP_CAN0_TX_IRQn = 19, /*!< CAN0 TX interrupts */
 USBD_LP_CAN0_RX0_IRQn = 20, /*!< CAN0 RX0 interrupts */
 CAN0_RX1_IRQn = 21, /*!< CAN0 RX1 interrupts */
 CAN0_EWMC_IRQn = 22, /*!< CAN0 EWMC interrupts */
 EXTI5_9_IRQn = 23, /*!< EXTI[9:5] interrupts */
TIMER0_BRK_IRQn = 24, /*!< TIMER0 break interrupts */
 TIMER0_UP_IRQn = 25, /*!< TIMER0 update interrupts */
 TIMER0_TRG_CMT_IRQn = 26, /*!< TIMER0 trigger and commutation interrupts */
 TIMER0_Channel_IRQn = 27, /*!< TIMER0 channel capture compare interrupts */
 TIMER1_IRQn = 28, /*!< TIMER1 interrupt */
 TIMER2_IRQn = 29, /*!< TIMER2 interrupt */
 TIMER3_IRQn = 30, /*!< TIMER3 interrupts */
 I2C0_EV_IRQn = 31, /*!< I2C0 event interrupt */
 I2C0_ER_IRQn = 32, /*!< I2C0 error interrupt */
 I2C1_EV_IRQn = 33, /*!< I2C1 event interrupt */
 I2C1_ER_IRQn = 34, /*!< I2C1 error interrupt */
 SPI0_IRQn = 35, /*!< SPI0 interrupt */
 SPI1_IRQn = 36, /*!< SPI1 interrupt */
 USART0_IRQn = 37, /*!< USART0 interrupt */
 USART1_IRQn = 38, /*!< USART1 interrupt */
 USART2_IRQn = 39, /*!< USART2 interrupt */
 EXTI10_15_IRQn = 40, /*!< EXTI[15:10] interrupts */
 RTC_Alarm_IRQn = 41, /*!< RTC alarm interrupt */
 USBD_WKUP_IRQn = 42, /*!< USBD Wakeup interrupt */
 EXMC_IRQn = 48, /*!< EXMC global interrupt */
#endif /* GD32F10X_MD */
} IRQn_Type;

3.2.中断服务函数的命名

上一小节介绍了如何设置中断的优先级,那么中断服务函数如何命名和使用呢? 本小结将介绍这方面的内容。

下面以GD32F103C8T6产品为例,介绍如何命名中断服务函数名。GD32F103C8T6的flash容量为64KB,属于中密度产品,其对应的启动文件为startup_gd32f10x_md.s。在该启动文件中我们预先为每个中断都命名了一个中断服务函数,为的是初始化中断向量表。实际的中断服务函数里面的内容需要我们重新编写,中断服务函数我们统一写在gd32f10x_it.c文件里。

需要注意的是,中断服务函数的函数名必须和启动文件里面的一样,如果写错了,系统在中断向量表中就会找不到中断服务函数的入口,从而导致进不了中断。为了避免该错误,简单的处理方法是:打开startup_gd32f10x_md.s,找到需要的中断服务函数名,复制该函数名到gd32f10x_it.c文 件 中 即 可 。 以 SPI0 中 断 为 例 , 打 开 startup_gd32f10x_md.s , 找 到 SPI0_IRQHandler (SPI0_IRQHandler就是SPI0中断服务函数的名称),复制SPI0_IRQHandler到gd32f10x_it.c,修改其如代码清单SPI0中断服务函数所示即可。在该函数中就可以添加用户所需的中断服务 代码了。

void SPI0_IRQHandler(void)
{
}

3.3.中断向量偏移

当发生了异常并且要响应它时,Cortex-M 需要定位其处理例程的入口地址。这些入口地址存储在所谓的“异常向量表”中。默认情况下,Cortex-M认为该表位于零地址处,且各向量占用4 节,因此每个表项占用4 字节,如上电后的向量表所示。

输入图片说明

因为地址0处应该存储引导代码,所以它通常是Flash或者是ROM器件,并且它们的值不得在运行时改变。然而,为了动态重分发中断,Cortex-M允许向量表重定位,从其它地址处开始定位各异常向量。这些地址对应的区域可以是代码区,但更多在RAM区。在RAM区就可以修改向量的入口地址了。为了实现这个功能,NVIC中有一个寄存器,称为“向量表偏移量寄存器”(在地址0xE000_ED08处),通过修改它的值就能定位向量表。但必须注意的是:向量表的起始地址是有要求的:必须先求出系统中共有多少个向量,再把这个数字向上增大到是2 的整次幂,而起始地址必须对齐到后者的边界上。例如,如果一共有32个中断,则共有32+16(系统异常)=48个向量,向上增大到2 的整次幂后值为64,因此地址地址必须能被64*4=256 整除,从而合法的起始地址可以是:0x0, 0x100, 0x200等。向量表偏移量寄存器的定义如向量表偏移寄存器(VTOR)表所示。

输入图片说明

在gd32f10x_misc.c文件中,nvic_vector_table_set函数就是用来定义中断向量偏移的,该函数的原型如代码清单 0-16 nvic_vector_table_set函数原型所示,函数参数说明如参数说明表所示。

代码清单nvic_vector_table_set 函数原型

void nvic_vector_table_set(uint32_t nvic_vict_tab, uint32_t offset)
{
 SCB->VTOR = nvic_vict_tab | (offset & NVIC_VECTTAB_OFFSET_MASK);
}

参数说明表

输入图片说明

下面举例说明如何使用该函数。

在实际使用中,用户会把FALSH分成BOOT区和APP区。BOOT区只用于代码升级,实际应用的程序在APP区里运行。假设客户把FLASH的第0页(大小为1KB)作为BOOT区,该页的地址范围为0x08000000~0x080003FF,第2页、第3页作为APP区,地址范围为0x08000800~0x08000FFF。执行完BOOT区的代码后,程序会跳转到0x08000800的地址开始执行APP程序。0x08000800相对于基地址0x08000000的偏移地址为0x800,此时调用nvic_vector_table_set函数的格式如代码清单调用nvic_vector_table_set函数所示。

nvic_vector_table_set(NVIC_VECTTAB_FLASH, 0x800);

3.4.NVIC 使用注意事项

E23x 系列使用的是 M23 内核,该内核的 NVIC 使用 2bit 定义优先级,并且不分抢占优先级和子优先级。在 gd32e23x_misc.c 文件中,nvic_irq_enable(uint8_t nvic_irq, uint8_t nvic_irq_priority)函数用于设置优先级,该函数的参数说明如图所示。

输入图片说明

更多GD32 MCU相关咨询:https://www.gd32bbs.com/  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1991735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

教育机构如何避免数据泄露?两种方法保护数据安全

随着数字化时代的发展&#xff0c;教育机构的很多信息都以数字化的方式存储在计算机或移动存储设备中。为了避免数据泄露&#xff0c;我们需要加密保护重要数据。下面我们就来了解一下教育机构避免数据泄露的方法。 超级加密3000 电脑在教育行业中扮演着重要的角色&#xff0c…

阿里云万网推出首个域名AI大模型智能体应用,上线“.ai”等40个全新域名后缀

中国域名保有量3160万&#xff0c;以9.4%的份额位居全球第二。 域名资源越来越紧张&#xff0c;运维越来越复杂&#xff0c;面对的网络攻击也越来越频繁&#xff0c;都给这一领域提出了更大挑战。 8月8日&#xff0c;在阿里云万网焕新发布会上&#xff0c;阿里云宣布域名产品服…

waf绕过:网络安全狗绕过

引言&#xff1a; 所有的绕过原理都大致一致&#xff0c;但是并不是所有的绕过都能起到作用&#xff0c;渗透测试主要还是一个猜加试的过程&#xff0c;本文仅供参考 网络攻击或扫描绕过 1.get绕过&#xff08;未开启cc防护&#xff09; 网络安全狗的默认防护为&#xff0c;拒…

【C++】模拟实现reverse_iterator(反向迭代器适配器)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:实战项目集 ⚙️操作环境:Visual Studio 2022 目录 一.了解项目功能 &#x1f4cc;什么是适配器 &#x1f4cc;了解reverse_iterator官方标准 &#x1f4cc;了解模拟实现reverse_iterator 二.逐步实现项目功能模块及…

【C++综合项目】——基于Boost库的搜索引擎(手把手讲解,小白一看就会!!)

目录 一、前言 二、项目的相关背景 ⚡什么是Boost库&#xff1f;⚡ ⚡什么是搜索引擎&#xff1f;⚡ ⚡为什么要做Boost搜索引擎&#xff1f;⚡ 二、搜索引擎的宏观原理 三、搜索引擎技术栈和项目环境 四、正排索引 VS 倒排索引 —— 搜索引擎的具体原理 &#x…

leetcode22. 括号生成,DFS深度优先搜索

leetcode22. 括号生成 数字 n 代表生成括号的对数&#xff0c;请你设计一个函数&#xff0c;用于能够生成所有可能的并且 有效的 括号组合。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[“((()))”,“(()())”,“(())()”,“()(())”,“()()()”] 示例 2&am…

SQL面试题练习 —— 最后一次登录停留时长

目录 1 题目2 建表语句3 题解 题目来源&#xff1a;腾讯微信。 1 题目 有一张用户登录日志表ods_usr_login_log, 包含user_id&#xff08;用户id&#xff09;、ds&#xff08;登录时间&#xff09;以及stay_time&#xff08;停留时长&#xff0c;单位:ms&#xff09; 问题&…

再等等,iPhone 17系列大革新,即将带来颠覆性的升级

自从苹果在2021年的iPhone 13 Pro系列中引入了ProMotion自适应刷新率技术以来&#xff0c;这项技术便成为了高端智能手机显示技术的重要标志。 如今&#xff0c;随着iPhone 17系列即将登场&#xff0c;我们有望见证这项技术向下一代更广泛的设备拓展。不仅如此&#xff0c;iPh…

每日一题~ abc 365 E 异或运算(拆位+贡献)

处理位运算常用的方法&#xff1a; 拆位法&#xff08;一位一位的处理&#xff0c;通常题目中会给出元素的最大是2的的多少次幂&#xff0c;当然也有给10的次幂的&#xff0c;自己注意一下就可以了&#xff09; 常用的思想 &#xff1a; 算贡献。 异或的性质&#xff1a; A^A0 …

抖音外卖区域服务商有哪些城市开放了?搭建本地生活系统抢先入局的成功率如何?

随着多家互联网大厂对本地生活重视程度的不断提高&#xff0c;本地生活服务商逐渐成为众多创业者心目中的首选赛道。在此背景下&#xff0c;抖音外卖区域服务商的申请通道一经开放便引发了一阵申请热潮。 毕竟&#xff0c;根据艾瑞咨询数据预测&#xff0c;到2025年&#xff0…

Linux5.15.71编译问题处理

目录 1 编译环境及源码版本2 移植Linux 5.15.71遇到问题2.1 imx-sdma 20ec000.dma-controller: Direct firmware load for imx/sdma/sdma-imx6q.bin failed with error -22.2 cfg80211: failed to load regulatory.db 1 编译环境及源码版本 ​ 1. uboot-alientek-v2022.04 ​…

红酒与亚洲菜肴:品味东方韵味

当西方的红酒遇上东方的菜肴&#xff0c;一场跨越地域与文化的味蕾盛宴就此展开。洒派红酒&#xff08;Bold & Generous&#xff09;与亚洲菜肴的相遇&#xff0c;不仅是一场美食的邂逅&#xff0c;更是一次对东方韵味的深度品味。 一、红酒的醇厚与亚洲菜肴的精致 红酒&…

【Unity程序】和【控制台程序】连接【asp.net core的websocket服务】(1)——在编辑器中运行

一、说明 1、本文实验内容所涉及的开发环境说明&#xff1a; win11VisualStudio2022&#xff08;.Net6.0&#xff09;Unity2021.3.40 2、本文参考资料 【1】NativeWebSocketUnity包&#xff1a; https://github.com/endel/NativeWebSocket 【2】asp.net core架设websocket国…

【安卓】SharedPreferences存储

SharedPreferences使用键值对的方式来存储数据的。也就是说&#xff0c;当保存一条数据的时候&#xff0c;需要给这条数据提供一个对应的键&#xff0c;这样在读取数据的时候就可以通过这个键把相应的值取出来。而且SharedPreferences还支持多种不同的数据类型存储&#xff0c;…

游戏原画可节省60-80%工时,大厂在用AI做什么

AIGC技术的迭代&#xff0c;是不是太快了点&#xff1f; 前年年中还是光速出图的Stable Diffusion&#xff0c;到年底就有了可以媲美真人的文本处理模型ChatGPT&#xff0c;今年开年又蹦出来了可以凭空变出视频、动画的Sora……我们对技术升级的认知被一次次刷新&#xff0c;同…

BHGMall生活超市天通苑店盛大开业,多重好礼只等你来

据悉8月10日&#xff0c;BHGMall生活超市天通苑店焕新开业&#xff0c;催旺“七夕浪漫经济”造福社区百姓&#xff0c;不仅提供助老服务&#xff0c;还有超值福利、多重好礼&#xff0c;倡导天天有低价&#xff0c;以实惠的价格买到优质的商品&#xff0c;提升居民幸福感和城市…

解题思考:为什么Java中使用Arrays.stream()创建流处理数组通常会增加开销,提高时间复杂度?

目录 问题描述&#xff1a;问题回答&#xff1a; 问题描述&#xff1a; 在解决力扣上的&#xff1a; 3131. 找出与数组相加的整数 I 时&#xff0c;使用传统遍历会比创建流处理数组的时间复杂度更低。 1.传统遍历代码&#xff1a; class Solution {public int addedInteger(i…

大模型与数据分析的融合:创新与发展的新机遇

大模型与数据分析的融合&#xff1a;创新与发展的新机遇 前言大模型与数据分析的融合 前言 大模型与数据分析的融合正成为推动企业发展的关键力量。大模型在数据分析领域展现出了强大的能力。它能够以接近人类的水平理解和处理自然语言&#xff0c;快速、准确地解析大量非结构…

vue实现PC端图片放大缩小可鼠标拖动,鼠标滚轮控制放大缩小完整代码付效果图

vue实现图片放大缩小可鼠标拖动&#xff0c;鼠标滚轮控制放大缩小完整代码付效果图 效果图&#xff1a; 创建一个ImageViewer 组件&#xff0c;并且在当前页面引用完整代码如下&#xff1a; 代码引用&#xff1a; <template><view><image-viewer :imageUrl&q…

大数据-69 Kafka 高级特性 物理存储 实机查看分析 日志存储一篇详解

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…