Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
RT-Thread Studio
RT-Thread活动
瑞萨_RA6M4
基于RT-Thread+RA6M4的虚拟仪器开发:第四章中断介绍
发布于 2022-07-07 14:52:41 浏览:620
订阅该版
[TOC] # 第四章中断介绍 ## 前言 中断作为MCU的核心重点内容之一,必须对其底层细节完全了解,这样才能进行后面的开发。对于传统的裸机MCU程序开发,就是一个前后台系统,即大循环+中断的架构,对于基于RTOS的系统,要了解其底层机制,调度等,也必须要先了解芯片的中断机制。本章就讲讲本芯片的中断。 该芯片使用的是CORTEX-M33内核,所以需要了解该内核的NVIC。另外该芯片在此基础上有一个ICU模块进行中断管理。所以参考的就是CORTEX-M33的架构手册和本芯片的手册。 代码见 https://gitee.com/qinyunti/ra6m4 ## 中断向量表 对于MCU中断,首先要理解的就是中断向量表:产生中断时硬件控制程序自动跳到指定的地址处执行,中断向量表就是这个指定的地址表,这个表放的位置一般是固定的,或者通过寄存器比如VTOR指定。 我们通过链接脚本可以看到 ``` KEEP(*(.fixed_vectors*)) KEEP(*(.application_vectors*)) ``` ``` #define BSP_SECTION_FIXED_VECTORS ".fixed_vectors" #define BSP_SECTION_APPLICATION_VECTORS ".application_vectors" ``` 固定的中断向量如下 ``` /* Vector table. */ BSP_DONT_REMOVE const exc_ptr_t __Vectors[BSP_CORTEX_VECTOR_TABLE_ENTRIES] BSP_PLACE_IN_SECTION( BSP_SECTION_FIXED_VECTORS) = { (exc_ptr_t) (&g_main_stack[0] + BSP_CFG_STACK_MAIN_BYTES), /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler, /* NMI Handler */ HardFault_Handler, /* Hard Fault Handler */ MemManage_Handler, /* MPU Fault Handler */ BusFault_Handler, /* Bus Fault Handler */ UsageFault_Handler, /* Usage Fault Handler */ SecureFault_Handler, /* Secure Fault Handler */ 0, /* Reserved */ 0, /* Reserved */ 0, /* Reserved */ SVC_Handler, /* SVCall Handler */ DebugMon_Handler, /* Debug Monitor Handler */ 0, /* Reserved */ PendSV_Handler, /* PendSV Handler */ SysTick_Handler, /* SysTick Handler */ }; ``` 用户的中断向量如下在`vector_data.c`中 ``` /* generated vector source file - do not edit */ #include "bsp_api.h" /* Do not build these data structures if no interrupts are currently allocated because IAR will have build errors. */ #if VECTOR_DATA_IRQ_COUNT > 0 BSP_DONT_REMOVE const fsp_vector_t g_vector_table[BSP_ICU_VECTOR_MAX_ENTRIES] BSP_PLACE_IN_SECTION(BSP_SECTION_APPLICATION_VECTORS) = { [0] = sci_uart_rxi_isr, /* SCI7 RXI (Received data full) */ [1] = sci_uart_txi_isr, /* SCI7 TXI (Transmit data empty) */ [2] = sci_uart_tei_isr, /* SCI7 TEI (Transmit end) */ [3] = sci_uart_eri_isr, /* SCI7 ERI (Receive error) */ [4] = r_icu_isr, /* ICU IRQ0 (External pin interrupt 0) */ }; const bsp_interrupt_event_t g_interrupt_event_link_select[BSP_ICU_VECTOR_MAX_ENTRIES] = { [0] = BSP_PRV_IELS_ENUM(EVENT_SCI7_RXI), /* SCI7 RXI (Received data full) */ [1] = BSP_PRV_IELS_ENUM(EVENT_SCI7_TXI), /* SCI7 TXI (Transmit data empty) */ [2] = BSP_PRV_IELS_ENUM(EVENT_SCI7_TEI), /* SCI7 TEI (Transmit end) */ [3] = BSP_PRV_IELS_ENUM(EVENT_SCI7_ERI), /* SCI7 ERI (Receive error) */ [4] = BSP_PRV_IELS_ENUM(EVENT_ICU_IRQ0), /* ICU IRQ0 (External pin interrupt 0) */ }; #endif ``` 用户中断紧挨着固定中断。 如果要添加用户自己的中断服务函数,需要在`vector_data.h`添加函数申明 `vector_data.c`的`g_vector_table`数组中添加中断服务函数,指定`g_interrupt_event_link_select`。 `IELSR`的配置值对应的中断实际通过`BSP_PRV_IELS_ENUM`这个宏进行定义和手册对应。 ## ICU与用户中断指定 参见《RA6M4 Group User’s Manual: Hardware》的《13. Interrupt Controller Unit (ICU)》 该芯片有个特点除了前面固定的中断向量外,从16开始的中断可以通过ICU去选择对应的是什么中断。 中断选择 根据《13.3 Vector Table》 从16号中断开始通过ICU.IELSRn去选择中断源 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220707/2ceb49b0d3589bdcb2afab59655d210e.png.webp) 中断源参见《Table 13.4 Event table》 比如ICU.IELSR0~3分别是0x1AA~0x1AD ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220707/f077c4d76c2f4445981cd12591f9ad62.png.webp) 对应的是SCI7的中断 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220707/6d7e94c6d4329d1d6d47574c1163fab1.png.webp) 对应的正是`g_interrupt_event_link_select`这个表格。 NVIC 见https://developer.arm.com/documentation/ddi0553/bs/?lang=en 实际ARM的CMSIS标准对NVIC的操作提供了标准的接口, 位于`\CPKRA6M4\ra\arm\CMSIS_5\CMSIS\Core\Include`下 两个主要的接口如下 ### 设置优先级组 ``` NVIC_SetPriorityGrouping __STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) { uint32_t reg_value; uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ reg_value = SCB->AIRCR; /* read old register configuration */ reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ reg_value = (reg_value | ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ SCB->AIRCR = reg_value; } ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220707/9e0a41aa963c0cdfb58509c8f91dd059.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220707/4cb300ab764a14d0bff002ea22f25c21.png.webp) 可以通过仿真器查看对应内存之去查看寄存器的值。 ### 中断使能 ``` #define NVIC_EnableIRQ __NVIC_EnableIRQ /** \brief Enable Interrupt \details Enables a device specific interrupt in the NVIC interrupt controller. \param [in] IRQn Device specific interrupt number. \note IRQn must not be negative. */ __STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { __COMPILER_BARRIER(); NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); __COMPILER_BARRIER(); } } ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20220707/b1d381b2816524c7ac463f1ac196c111.png.webp) ### 中断号 `__NVIC_EnableIRQ`等接口中要传入中断号参数,在添加了用户中断服务函数后,需要对应其中断号 `\CPKRA6M4\ra\fsp\src\bsp\mcu\all\bsp_arm_exceptions.h`中定义 用户中断从0开始,比如SCI7_RXI_IRQn = 0, 对应的就是`g_vector_table`这个表的第0个中断服务函数,对应的就是 `g_interrupt_event_link_select`这个表的第0个中断源选择寄存器。 `__NVIC_EnableIRQ(SCI7_RXI_IRQn)`就可以使能该中断。 ``` /* This list includes only Arm standard exceptions. Renesas interrupts are defined in vector_data.h. */ typedef enum IRQn { Reset_IRQn = -15, /* 1 Reset Vector invoked on Power up and warm reset */ NonMaskableInt_IRQn = -14, /* 2 Non maskable Interrupt cannot be stopped or preempted */ HardFault_IRQn = -13, /* 3 Hard Fault all classes of Fault */ MemoryManagement_IRQn = -12, /* 4 Memory Management MPU mismatch, including Access Violation and No Match */ BusFault_IRQn = -11, /* 5 Bus Fault Pre-Fetch-, Memory Access, other address/memory Fault */ UsageFault_IRQn = -10, /* 6 Usage Fault i.e. Undef Instruction, Illegal State Transition */ SecureFault_IRQn = -9, /* 7 Secure Fault Interrupt */ SVCall_IRQn = -5, /* 11 System Service Call via SVC instruction */ DebugMonitor_IRQn = -4, /* 12 Debug Monitor */ PendSV_IRQn = -2, /* 14 Pendable request for system service */ SysTick_IRQn = -1, /* 15 System Tick Timer */ SCI7_RXI_IRQn = 0, SCI7_TXI_IRQn = 1, SCI7_TEI_IRQn = 2, SCI7_ERI_IRQn = 3, ICU_IRQ0_IRQn = 4, SCI6_RXI_IRQn = 5, SCI6_TXI_IRQn = 6, SCI6_TEI_IRQn = 7, SCI6_ERI_IRQn = 8, SCI6_AM_IRQn = 9, } IRQn_Type; ``` ### 中断向量地址设置 `SystemInit`中 `SCB->VTOR = (uint32_t) &__Vectors;` `__Vectors`正是固定中断向量的地址。 `BSP_PLACE_IN_SECTION( BSP_SECTION_FIXED_VECTORS)`并放在了 `.fixed_vectors*`段,即FLASH的开头。 ``` /* Vector table. */ BSP_DONT_REMOVE const exc_ptr_t __Vectors[BSP_CORTEX_VECTOR_TABLE_ENTRIES] BSP_PLACE_IN_SECTION( BSP_SECTION_FIXED_VECTORS) = { (exc_ptr_t) (&g_main_stack[0] + BSP_CFG_STACK_MAIN_BYTES), /* Initial Stack Pointer */ Reset_Handler, /* Reset Handler */ NMI_Handler, /* NMI Handler */ HardFault_Handler, /* Hard Fault Handler */ MemManage_Handler, /* MPU Fault Handler */ BusFault_Handler, /* Bus Fault Handler */ UsageFault_Handler, /* Usage Fault Handler */ SecureFault_Handler, /* Secure Fault Handler */ 0, /* Reserved */ 0, /* Reserved */ 0, /* Reserved */ SVC_Handler, /* SVCall Handler */ DebugMon_Handler, /* Debug Monitor Handler */ 0, /* Reserved */ PendSV_Handler, /* PendSV Handler */ SysTick_Handler, /* SysTick Handler */ }; ``` ## 中断的配置 1. 初始化时调用 ``SystemInit`调用`bsp_irq_cfg`,该函数中会根据表`g_interrupt_event_link_select`配置`R_ICU->IELSR`寄存器。 这样就设置了某个中断号对应的是哪一个外设中断。 所以我们只需要修改`g_interrupt_event_link_select`这个表即可,要和数组的序号对应。 2. 在`\CPKRA6M4\ra\fsp\src\bsp\mcu\all\bsp_arm_exceptions.h`中定义中断号 和`g_interrupt_event_link_select`的数组下标对应 3. `vector_data.c`中`g_vector_table`中添加中断服务函数, 在`vector_data.h`中申明中断服务函数,在用户代码中实现终端服务函数。 4. 调用`NVIC_SetPriorityGrouping` 设置中断优先级组,调用一次即可 5. 调用`NVIC_EnableIRQ` 使能中断,参数是`bsp_arm_exceptions.h`中定义的中断号,与`g_vector_table`的下标对应。 ## 中断的调试 分析思路如下: 比如串口 - 先确认模块初始化正确,通过仿真器查看模块寄存器是否配置对。 - 确认中断标志是否置位,再看中断是否使能,查看SCI寄存器的SSR。 - 再看中断向量表是否配置好,中断源选择配置是不是对。查看ICU的IELSR寄存器。 - 确认外设中断有没有产生 查看ICU的IELSR寄存器的bit16是否置位。 - 再看NVIC中断是否使能,查看NVIC的ISER寄存器。 ## 总结 一般要了解芯片的中断,需要从其芯片的架构手册去了解,比如我们这里的《arm_cortex_m33_trm_100230_0100_03_en.pdf》和《DDI0553B_s_armv8m_arm.pdf》 以及芯片本身的手册中关于中断的描述,比如这里的《RA6M4 Group User’s Manual: Hardware》的《13. Interrupt Controller Unit (ICU)》 通过手册描述,结合仿真器去分析底层的细节,是嵌入式开发必备的技能。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
qinyunti
这家伙很懒,什么也没写!
文章
30
回答
1
被采纳
0
关注TA
发私信
相关文章
1
(苏州站)RT-Thread物联网开发者沙龙【已结束】
2
(成都站)RT-Thread物联网开发者沙龙
3
(深圳站)RT-Thread物联网开发者沙龙
4
(西安站)RT-Thread物联网开发者沙龙
5
成都站2018 RT-Thread开发者沙龙回顾及PPT下载
6
2018 RT-Thread物联网开发者沙龙(北京站)
7
2018 RT-Thread物联网开发者沙龙(南京站)
8
第十三届研电赛RT-Thread企业专项奖发布通知
9
RT-Thread应用作品征集大赛开始啦!
10
你的投票将决定RT-Thread官网应该优先准备的文档是哪些
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部