interrupts-and-exceptions-baremetal
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseInterrupts and Exceptions (Bare-Metal)
中断与异常(裸机)
Purpose
用途
Guide agents through bare-metal interrupt handling on ARM Cortex-M: NVIC configuration, ISR writing rules, exception handlers (HardFault, BusFault), priority grouping, nesting, tail-chaining, and latency considerations.
指导开发者完成ARM Cortex-M上的裸机中断处理:NVIC配置、ISR编写规则、异常处理程序(HardFault、BusFault)、优先级分组、嵌套、尾链以及延迟相关考量。
When to Use
使用场景
- Configuring peripheral IRQ priorities
- Writing ISRs that must not block
- Debugging HardFault after enabling interrupts
- Sharing data between ISR and main loop
- Optimizing interrupt latency
- 配置外设IRQ优先级
- 编写不可阻塞的ISR
- 启用中断后调试HardFault问题
- 在ISR与主循环之间共享数据
- 优化中断延迟
Workflow
工作流程
1. NVIC overview (Cortex-M)
1. NVIC概述(Cortex-M)
Exception / IRQ flow
├── NVIC receives IRQ (priority compare with BASEPRI/PRIMask)
├── Stacking: automatic save r0-r3, r12, lr, pc, psr
├── Branch to handler from vector table
├── Handler runs (should be short)
└── Unstack and return — tail-chain if another IRQ pendingException / IRQ flow
├── NVIC receives IRQ (priority compare with BASEPRI/PRIMask)
├── Stacking: automatic save r0-r3, r12, lr, pc, psr
├── Branch to handler from vector table
├── Handler runs (should be short)
└── Unstack and return — tail-chain if another IRQ pending2. Enable and prioritize an IRQ
2. 启用并设置IRQ优先级
c
#include "stm32f4xx.h" /* CMSIS device header */
void uart_irq_init(void) {
NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 2, 0));
NVIC_EnableIRQ(USART2_IRQn);
}Priority: lower numeric value = higher urgency (on most Cortex-M implementations). Check vendor docs for grouping bits.
c
#include "stm32f4xx.h" /* CMSIS device header */
void uart_irq_init(void) {
NVIC_SetPriority(USART2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 2, 0));
NVIC_EnableIRQ(USART2_IRQn);
}优先级:数值越小,紧急程度越高(在大多数Cortex-M实现中)。请查看厂商文档了解分组位相关信息。
3. ISR template
3. ISR模板
c
void USART2_IRQHandler(void) {
if (USART2->SR & USART_SR_RXNE) {
uint8_t b = (uint8_t)USART2->DR; /* read clears RXNE */
ringbuf_push(b);
}
if (USART2->SR & USART_SR_ORE) {
(void)USART2->DR; /* clear overrun */
}
}ISR rules:
- No blocking calls (,
printf, long loops)malloc - Minimize work — defer to main via flag/ring buffer
- Clear interrupt flags per datasheet (read-to-clear vs write-1-clear)
c
void USART2_IRQHandler(void) {
if (USART2->SR & USART_SR_RXNE) {
uint8_t b = (uint8_t)USART2->DR; /* read clears RXNE */
ringbuf_push(b);
}
if (USART2->SR & USART_SR_ORE) {
(void)USART2->DR; /* clear overrun */
}
}ISR规则:
- 禁止阻塞调用(如、
printf、长循环)malloc - 最小化工作量——通过标志/环形缓冲将任务延迟到主循环处理
- 按照 datasheet 要求清除中断标志(读清除或写1清除)
4. Critical sections
4. 临界区
c
uint32_t primask = __get_PRIMASK();
__disable_irq();
/* atomic section */
__set_PRIMASK(primask);Or raise to mask lower-priority IRQs only.
BASEPRIc
uint32_t primask = __get_PRIMASK();
__disable_irq();
/* 原子操作段 */
__set_PRIMASK(primask);或者提高值,仅屏蔽低优先级IRQ。
BASEPRI5. HardFault handler
5. HardFault处理程序
c
void HardFault_Handler(void) {
__asm volatile(
"tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b hard_fault_c\n"
);
}
void hard_fault_c(uint32_t *stack) {
uint32_t r0 = stack[0];
uint32_t pc = stack[6];
uint32_t psr = stack[7];
/* log pc — GDB: info registers, bt */
while (1);
}Decode CFSR/HFSR registers for fault cause:
c
volatile uint32_t cfsr = SCB->CFSR;
volatile uint32_t hfsr = SCB->HFSR;
volatile uint32_t bfar = SCB->BFAR;c
void HardFault_Handler(void) {
__asm volatile(
"tst lr, #4\n"
"ite eq\n"
"mrseq r0, msp\n"
"mrsne r0, psp\n"
"b hard_fault_c\n"
);
}
void hard_fault_c(uint32_t *stack) {
uint32_t r0 = stack[0];
uint32_t pc = stack[6];
uint32_t psr = stack[7];
/* 记录pc — GDB命令:info registers, bt */
while (1);
}解码CFSR/HFSR寄存器以确定故障原因:
c
volatile uint32_t cfsr = SCB->CFSR;
volatile uint32_t hfsr = SCB->HFSR;
volatile uint32_t bfar = SCB->BFAR;6. Latency and tail-chaining
6. 延迟与尾链
| Factor | Impact |
|---|---|
| Higher priority IRQ | Preempts lower |
| Tail-chaining | Back-to-back IRQs skip unstack/restack |
| FPU context | Lazy stacking adds latency on M4F/M7 |
| Long ISRs | Starves other IRQs and main |
Measure with GPIO toggle + scope, or DWT cycle counter ().
DWT->CYCCNT| 因素 | 影响 |
|---|---|
| 高优先级IRQ | 抢占低优先级IRQ |
| 尾链 | 连续IRQ跳过出栈/入栈操作 |
| FPU上下文 | M4F/M7上的延迟入栈会增加延迟 |
| 长ISR | 导致其他IRQ和主循环饥饿 |
可通过GPIO翻转+示波器,或DWT周期计数器()进行测量。
DWT->CYCCNT7. Agent usage examples
7. 技能使用示例
/interrupts-and-exceptions-baremetal Configure NVIC priority for UART vs SysTick
/interrupts-and-exceptions-baremetal Decode HardFault stacked PC with GDB/interrupts-and-exceptions-baremetal 配置UART与SysTick的NVIC优先级
/interrupts-and-exceptions-baremetal 使用GDB解码HardFault栈中的PC值Common Problems
常见问题
| Symptom | Cause | Fix |
|---|---|---|
| IRQ never fires | NVIC not enabled or IRQ masked | |
| Spurious re-entry | Flag not cleared | Clear per RM (ORE needs DR read) |
| HardFault in ISR | Stack overflow | Increase |
| Lost bytes | ISR too slow | Ring buffer + higher IRQ priority |
| Priority inversion | Long critical section | Shorten |
| 症状 | 原因 | 解决方法 |
|---|---|---|
| IRQ从未触发 | NVIC未启用或IRQ被屏蔽 | 调用 |
| 虚假重入 | 标志未清除 | 参考RM清除标志(ORE需要读取DR) |
| ISR中出现HardFault | 栈溢出 | 增大 |
| 数据丢失 | ISR执行过慢 | 使用环形缓冲+提高IRQ优先级 |
| 优先级反转 | 临界区过长 | 缩短 |
Related Skills
相关技能
- — vector table entries
skills/baremetal/baremetal-startup - — UART IRQ handlers
skills/baremetal/uart-serial-baremetal - — GDB breakpoint in ISR
skills/embedded/openocd-jtag - — examine fault stack frame
skills/debuggers/gdb - — fault handler asm
skills/low-level-programming/assembly-arm
- — 向量表条目
skills/baremetal/baremetal-startup - — UART IRQ处理程序
skills/baremetal/uart-serial-baremetal - — 在ISR中设置GDB断点
skills/embedded/openocd-jtag - — 检查故障栈帧
skills/debuggers/gdb - — 故障处理程序汇编代码
skills/low-level-programming/assembly-arm