# STM32 Note Week3
Author: KT LIU
reference: Mastering_STM32-Second_Edtion
## Interrupts Management
所有的微控制器都提供一個名為中斷(interrupt)的功能。中斷是一種異步事件,它會根據優先級(中斷越重要,優先級越高,這會導致優先級較低的中斷被暫停)停止當前代碼的執行。處理中斷的代碼稱為中斷服務程式(ISR, Interrupt Service Routine)。
中斷可以由硬體和軟體本身觸發。ARM架構區分這兩種類型:中斷由硬體觸發,異常(exceptions)由軟體觸發(例如,訪問無效的內存位置)。在ARM術語中,中斷是一種異常。Cortex-M處理器提供了一個專門用於異常管理的單元,稱為嵌套向量中斷控制器(NVIC)。
### NVIC Controller

#### MCU 內部外設:
例如:定時器、UART 等
#### MCU 外部外設:
來自這些外設的中斷來源是 MCU 的 I/O
### MCU I/O 的配置方式:
#### 通用 I/O:
例如,一個連接到配置為輸入的引腳的觸摸開關
#### 驅動外部高級外設:
例如,配置為通過 RMII 接口與以太網 PHY 交換數據的 I/O
### 外部中斷/事件控制器 (EXTI)
EXTI(External Interrupt/Event Controller) 是一個專用的可編程控制器
#### 功能:
負責外部 I/O 信號與 NVIC 控制器之間的互連
,中斷管理,NVIC 單元處理異常和中斷
#### 中斷來源:
來自 MCU 外部外設,通过 I/O 接收中斷信號
EXTI 負責將外部 I/O 信號連接到 NVIC 控制器
### Cortex M 內建中斷
#### Reset
說明:此異常在CPU重置後立即觸發,是運行中的韌體的真正入口點。
功能:處理程序包含一些用於初始化執行環境(如主堆棧、.bss 區域等)的匯編代碼。
詳細介紹:第22章將深入討論啟動過程。
#### NMI(Non-Maskable Interrupt)
說明:這是一種特殊的異常,優先級僅次於Reset異常,不能被屏蔽,與關鍵和不可延遲的活動相關聯。
功能:在所有STM32微控制器中,NMI與時鐘安全系統(CSS)相關聯。CSS是一種自診斷外設,檢測外部時鐘(HSE)的故障,並在故障時自動禁用HSE、啟用內部HSI,並觸發NMI中斷以通知軟體HSE出現問題。
詳細介紹:第10章將進一步介紹。
#### Hard Fault
說明:這是一種通用的故障異常,與軟體中斷相關。
功能:當其他故障異常被禁用時,Hard Fault會收集所有類型的異常(例如,如果總線故障異常未啟用,訪問無效內存位置會觸發Hard Fault異常)。
#### Memory Management Fault¹
說明:當執行代碼嘗試訪問非法位置或違反內存保護單元(MPU)的規則時觸發。
詳細介紹:第20章將進一步探討。
#### Bus Fault¹
說明:當AHB接口從總線從設備收到錯誤響應時觸發(指令預取失敗稱為預取中止,數據訪問失敗稱為數據中止)。
功能:也可能由其他非法訪問引起(例如,訪問不存在的SRAM內存位置)。
#### Usage Fault¹
說明:當程序出現錯誤時觸發,例如非法指令、對齊問題或嘗試訪問不存在的協處理器。
#### SVCall
說明:這不是一種故障條件,當Supervisor Call(SVC)指令被調用時觸發。
功能:RTOS使用它在特權狀態下執行指令(需要執行特權操作的任務執行SVC指令,操作系統執行請求的操作,這與其他操作系統中的系統調用行為相同)。
#### Debug Monitor¹
說明:當處理器核心處於監視器調試模式時發生軟體調試事件時觸發。
功能:也用於軟體調試解決方案中的斷點和觀察點等調試事件。
#### PendSV
說明:這是與RTOS相關的另一個異常。
功能:與SVCall異常不同,SVCall異常在執行SVC指令後立即執行,而PendSV可以延遲執行,允許RTOS完成更高優先級的任務。
#### SysTick
說明:此異常通常與RTOS活動相關。
功能:每個RTOS需要一個定時器定期中斷當前代碼的執行並切換到另一個任務。所有STM32微控制器都提供Cortex-M核心內部的SysTick定時器,即使其他定時器可以用來調度系統活動,專用定時器的存在確保了在所有STM32系列中的可移植性。此外,即使在我們的韌體中未使用RTOS,ST CubeHAL也使用SysTick定時器執行內部與時間相關的活動(假設SysTick定時器配置為每1ms產生一次中斷)。
下圖中可以看到各自的優先級與功能

### 關於interrupt在記憶體中的執行
定義:向量表是一個陣列,其每個條目包含異常或中斷服務程序 (ISR) 的地址。
首項:向量表的第一個條目是主堆棧指針 (Main Stack Pointer, MSP) 在SRAM中的地址。
後續項:從第二個條目開始,是各異常和中斷的服務程序地址。
向量表的長度
Cortex-M0/0+:向量表長度為48。
Cortex-M3/4/7:向量表長度為256。
關鍵點
異常處理程序名稱
靈活性:異常處理程序的名稱只是慣例,可以根據需要進行更改,它們只是符號(像變數和函數一樣)。
注意事項:CubeMX軟件設計時使用這些名稱來生成ISR,因此更改名稱時需同步更改ISR名稱。
向量表位置
位置要求:向量表必須位於閃存 (Flash) 的起始位置。
工具支持:GCC Linker將向量表放置在閃存數據開始處的任務是在生成絕對文件(二進制文件)的過程中完成的。

### Enabling Interrupts
以 STM32F4 為例
只有特定的GPIO腳位支援interrupt的特殊功能,但其實有114個GPIO腳位連接至16個EXIT line,但是因為共用EXIT的關係,只有7條interrupt是獨立作用的,可看下圖所示

### 範例程式 腳位開關高低控制LED
以下是如何使用中斷每次按下用戶可編程按鈕(連接到PC13引腳)時切換LD2 LED的示例。首先,我們配置GPIO PC13,使其每次從低電平變為高電平時觸發中斷。
這是通過設置GPIO.Mode為GPIO_MODE_IT_RISING來實現的。
接下來,我們啟用與Px13引腳相關聯的EXTI線的中斷,EXTI15_10_IRQn。
```cpp
#include "stm32f4xx_hal.h"
int main(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* MCU Configuration ----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* GPIOA and GPIOC Configuration ----------------------------------------------*/
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* Configure GPIO pin : PA5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
/* EXTI interrupt init */
HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);
while (1) {
// Main loop does nothing, waiting for interrupts
}
}
void EXTI15_10_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
```
這裡主要利用以下function來進行interrupt的判斷,可以將希望進行的判斷或是中斷後要執行的內容寫在此處,可由先前的架構圖判斷哪些腳位對應的interrupt。
```cpp
void EXTI15_10_IRQHandler(void) {
if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET) {
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
```
### Cubr Mx設定
上面提到除了主要的callback function,其他大部分都是由cube Mx設定的,主要要將須使用的腳位,調整成指定的EXIT模式

並且要將interrupt的功能打開

這樣就差不多可以進行程式的編寫了