在 CPU 在正常執行指令序列時,當外部源(外設信號或GPIO引腳)或內部(指令異常、總線錯誤等)觸發 CPU 暫停當前工作,跳轉到相應的服務函數入口執行緊急任務。
對于每個中斷類型都需要指定一個中斷處理函數,這些中斷處理函數的地址組成中斷向量表,當發生中斷時,如果中斷使能,CPU 會自動跳轉的相應的中斷處理函數去執行中斷處理任務。
Py32f030 中斷
主要特性如下:
- 32 個可屏蔽的中斷通道(不包括 16 個 CPU 的中斷)
- 4 個可編程的優先級(2 位中斷優先級)
PY32F030 中斷向量地址
代碼實現
Py32f030 的內核為 Cortex-M0+ 內核,內核的標準中斷抽象在 cortex-m-rt,這部分的中斷抽象實現在文件:src/lib.rs
/* Exceptions */
#[doc(hidden)]
pubenum Exception {
NonMaskableInt,
// Not overridable
// HardFault,
#[cfg(not(armv6m))]
MemoryManagement,
#[cfg(not(armv6m))]
BusFault,
#[cfg(not(armv6m))]
UsageFault,
#[cfg(armv8m)]
SecureFault,
SVCall,
#[cfg(not(armv6m))]
DebugMonitor,
PendSV,
SysTick,
}
#[doc(hidden)]
pubuse self::Exception as exception;
extern"C" {
fn Reset() -> !;
fn NonMaskableInt();
fn HardFaultTrampoline();
#[cfg(not(armv6m))]
fn MemoryManagement();
#[cfg(not(armv6m))]
fn BusFault();
#[cfg(not(armv6m))]
fn UsageFault();
#[cfg(armv8m)]
fn SecureFault();
fn SVCall();
#[cfg(not(armv6m))]
fn DebugMonitor();
fn PendSV();
fn SysTick();
}
#[doc(hidden)]
pubunion Vector {
handler: unsafeextern"C"fn(),
reserved: usize,
}
#[doc(hidden)]
#[cfg_attr(cortex_m, link_section = ".vector_table.exceptions")]
#[no_mangle]
pubstatic __EXCEPTIONS: [Vector; 14] = [
// Exception 2: Non Maskable Interrupt.
Vector {
handler: NonMaskableInt,
},
// Exception 3: Hard Fault Interrupt.
Vector {
handler: HardFaultTrampoline,
},
// Exception 4: Memory Management Interrupt [not on Cortex-M0 variants].
#[cfg(not(armv6m))]
Vector {
handler: MemoryManagement,
},
#[cfg(armv6m)]
Vector { reserved: 0 },
// Exception 5: Bus Fault Interrupt [not on Cortex-M0 variants].
#[cfg(not(armv6m))]
Vector { handler: BusFault },
#[cfg(armv6m)]
Vector { reserved: 0 },
// Exception 6: Usage Fault Interrupt [not on Cortex-M0 variants].
#[cfg(not(armv6m))]
Vector {
handler: UsageFault,
},
#[cfg(armv6m)]
Vector { reserved: 0 },
// Exception 7: Secure Fault Interrupt [only on Armv8-M].
#[cfg(armv8m)]
Vector {
handler: SecureFault,
},
#[cfg(not(armv8m))]
Vector { reserved: 0 },
// 8-10: Reserved
Vector { reserved: 0 },
Vector { reserved: 0 },
Vector { reserved: 0 },
// Exception 11: SV Call Interrupt.
Vector { handler: SVCall },
// Exception 12: Debug Monitor Interrupt [not on Cortex-M0 variants].
#[cfg(not(armv6m))]
Vector {
handler: DebugMonitor,
},
#[cfg(armv6m)]
Vector { reserved: 0 },
// 13: Reserved
Vector { reserved: 0 },
// Exception 14: Pend SV Interrupt [not on Cortex-M0 variants].
Vector { handler: PendSV },
// Exception 15: System Tick Interrupt.
Vector { handler: SysTick },
];
// If we are not targeting a specific device we bind all the potential device specific interrupts
// to the default handler
#[cfg(all(any(not(feature = "device"), test), not(armv6m)))]
#[doc(hidden)]
#[cfg_attr(cortex_m, link_section = ".vector_table.interrupts")]
#[no_mangle]
pubstatic __INTERRUPTS: [unsafeextern"C"fn(); 240] = [{
extern"C" {
fn DefaultHandler();
}
DefaultHandler
}; 240];
// ARMv6-M can only have a maximum of 32 device specific interrupts
#[cfg(all(not(feature = "device"), armv6m))]
#[doc(hidden)]
#[link_section = ".vector_table.interrupts"]
#[no_mangle]
pubstatic __INTERRUPTS: [unsafeextern"C"fn(); 32] = [{
extern"C" {
fn DefaultHandler();
}
DefaultHandler
}; 32];
Py32f030 的芯片中斷抽象在 PY32f030xx-pac 已經自動實現。
中斷向量表的定義在文件:src/lib.rs +35
#[cfg(feature = "rt")]
extern"C" {
fn WWDG();
fn PVD();
fn RTC();
fn FLASH();
fn RCC();
fn EXTI0_1();
fn EXTI2_3();
fn EXTI4_15();
fn DMA_CHANNEL1();
fn DMA_CHANNEL2_3();
fn ADC_COMP();
fn TIM1_BRK_UP_TRG_COM();
fn TIM1_CC();
fn TIM3();
fn TIM14();
fn TIM16();
fn TIM17();
fn I2C1();
fn SPI1();
fn SPI2();
fn USART1();
fn USART2();
fn LED();
}
#[doc(hidden)]
pubunion Vector {
_handler: unsafeextern"C"fn(),
_reserved: u32,
}
#[cfg(feature = "rt")]
#[doc(hidden)]
#[link_section = ".vector_table.interrupts"]
#[no_mangle]
pubstatic __INTERRUPTS: [Vector; 31] = [
Vector { _handler: WWDG },
Vector { _handler: PVD },
Vector { _handler: RTC },
Vector { _handler: FLASH },
Vector { _handler: RCC },
Vector { _handler: EXTI0_1 },
Vector { _handler: EXTI2_3 },
Vector { _handler: EXTI4_15 },
Vector { _reserved: 0 },
Vector {
_handler: DMA_CHANNEL1,
},
Vector {
_handler: DMA_CHANNEL2_3,
},
Vector { _reserved: 0 },
Vector { _handler: ADC_COMP },
Vector {
_handler: TIM1_BRK_UP_TRG_COM,
},
Vector { _handler: TIM1_CC },
Vector { _reserved: 0 },
Vector { _handler: TIM3 },
Vector { _reserved: 0 },
Vector { _reserved: 0 },
Vector { _handler: TIM14 },
Vector { _reserved: 0 },
Vector { _handler: TIM16 },
Vector { _handler: TIM17 },
Vector { _handler: I2C1 },
Vector { _reserved: 0 },
Vector { _handler: SPI1 },
Vector { _handler: SPI2 },
Vector { _handler: USART1 },
Vector { _handler: USART2 },
Vector { _reserved: 0 },
Vector { _handler: LED },
];
#[doc = r"Enumeration of all the interrupts."]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u16)]
pubenum Interrupt {
#[doc = "0 - Window WatchDog Interrupt"]
WWDG = 0,
#[doc = "1 - PVD Interrupt through EXTI Lines 16"]
PVD = 1,
#[doc = "2 - RTC Interrupt through EXTI Lines 19"]
RTC = 2,
#[doc = "3 - FLASH global Interrupt"]
FLASH = 3,
#[doc = "4 - RCC global Interrupt"]
RCC = 4,
#[doc = "5 - EXTI Line 0 and 1 Interrupt"]
EXTI0_1 = 5,
#[doc = "6 - EXTI Line 2 and 3 Interrupt"]
EXTI2_3 = 6,
#[doc = "7 - EXTI Line 4 to 15 Interrupt"]
EXTI4_15 = 7,
#[doc = "9 - DMA Channel 1 Interrupt"]
DMA_CHANNEL1 = 9,
#[doc = "10 - DMA Channel 2 and Channel 3 Interrupt"]
DMA_CHANNEL2_3 = 10,
#[doc = "12 - ADC and COMP Interrupt through EXTI Lines 17 and 18"]
ADC_COMP = 12,
#[doc = "13 - TIM1 Break, Update, Trigger and Commutation Interrupt"]
TIM1_BRK_UP_TRG_COM = 13,
#[doc = "14 - TIM1 Capture Compare Interrupt"]
TIM1_CC = 14,
#[doc = "16 - TIM3 global Interrupt"]
TIM3 = 16,
#[doc = "19 - TIM14 global Interrupt"]
TIM14 = 19,
#[doc = "21 - TIM16 global Interrupt"]
TIM16 = 21,
#[doc = "22 - TIM17 global Interrupt"]
TIM17 = 22,
#[doc = "23 - I2C1 global Interrupt"]
I2C1 = 23,
#[doc = "25 - SPI1 global Interrupt"]
SPI1 = 25,
#[doc = "26 - SPI2 global Interrupt"]
SPI2 = 26,
#[doc = "27 - USART1 global Interrupt"]
USART1 = 27,
#[doc = "28 - USART2 global Interrupt"]
USART2 = 28,
#[doc = "30 - LED global Interrupt"]
LED = 30,
}
unsafeimpl cortex_m::interrupt::InterruptNumber for Interrupt {
#[inline(always)]
fn number(self) -> u16 {
selfasu16
}
}
中斷服務函數的實現
盡管 PY32f030xx-pac
crate 已經對所有的中斷進行了抽象,但對于中斷服務函數的實現只做了默認的空函數,如果需要重寫某個中斷服務函數,也非常簡單, 與嵌入式 C 的方式原理一樣。中斷函數名必須與中斷向量表中預定的函數名保持一致,且添加屬性 #[interrupt]
。如下所示展示串口1 和串口2的中斷服務函數:
use crate::pac::interrupt;
#[interrupt]
fn USART1() {
critical_section::with(|cs| unsafe {
EventFuture::::on_interrupt(cs, Id::USART1 asusize)
})
}
#[interrupt]
fn USART2() {
critical_section::with(|cs| unsafe {
EventFuture::::on_interrupt(cs, Id::USART2 asusize)
})
}