# RTOS 學習筆記 - 1
> 參考資源:[科技下午茶 - RTOS-01](https://www.youtube.com/watch?v=a0jo2wJXhgU&list=PLJvU73y7BpTsNAHgz0KoRtcyq16xflK9K)。
## OS v.s. Micro Kernel
### Linux 架構及名詞解釋

- Open System:隨時能下載新的應用程式(如 Linux、Windows、Android)。
- Closed System:產品出貨之後,Application 就定了,不能再下載新的應用程式(如大部分的嵌入式系統)。
- Dynamic Linking:OS 本身所提供的 API 或服務可以在出貨之後「再更新」(如 Windows Update)。於 Windows 可用 DLL 達成;在 Linux 則有 Shell library 的概念。
- Static Linking:大部分簡單的 OS。API 無法再增加。
- Monolithic Kernel:如 Linux(百萬行程式碼),是單核心的龐大設計,效率較佳;但維護起來較麻煩。
- Micro Kernel:約幾千行,此設計下的 Kernel 只提供基本服務(Task、IPC、Memory),調整上較快速且穩定、容易維護。大部分 MCU 市場皆屬於此設計。
### RTOS for MCU
- MCU 的常見設計為「單核」且「無 MMU(Memory Management Unit),意味著無 Virtual Address」。
- 多數 RTOS 僅提供
- Task Management(Create/Delete, Scheduler, Priority, etc.)
- IPC(Queue, Event, Semaphore, etc.)
- Memory services
> 故本質上應歸類於 Micro Kernel。
- 以 Micro Kernel 搭配獨立的 Services,理論上可架構出完整的 OS,但在 MCU 的應用上幾乎未見。
- MCU 的軟體架構(如 CMSIS、NXP-SDK)中,RTOS 多以「模組」的方式存在,其定位如同 Vendor APIs,處於平行的層級。
- 對於複雜的需求,透過 RTOS 的多緒能力,可明顯降低設計上的負擔。如啟用常駐服務、背景監聽等。
## C v.s. ARM

> C 語言的成功,讓 ARM 在設計其 Instructions 時,針對 C 的特性去作最佳化。
高階語言設計與 CPU 架構發展時,會有「互相參考」的情形。
## Context Switch
Context Switch:Task 之間的交換執行。

> FreeRTOS:在 Task 的環境保存方面,只用到 2 Blocks,即 TCB(Task Control Block)-放 Block 的基本資訊(如 Task 名稱、堆疊大小、優先級等);Stack-放暫存器內容。
### 程式解析(以 Cortex-M 為例)
參照 [FreeRTOSConfig.h](https://github.com/Infineon/freertos/blob/master/Source/portable/COMPONENT_CM33/FreeRTOSConfig.h) 之三種 ISR 如下,以便說明 Context Switch 運作原理:
```c
/* Definitions that map the FreeRTOS port interrupt handlers to their CMSIS
standard names - or at least those used in the unmodified vector table. */
#define vPortSVCHandler SVC_Handler
#define xPortPendSVHandler PendSV_Handler
#define xPortSysTickHandler SysTick_Handler
```
- `SVC_Handler`:用於啟動第一個 Task,同時設定 PSP。
- `SysTick_Handler`:當 TIME_SLICING 啟動後,可用於強制切換 Task(取決於優先級)。
- `PendSV_Handler`:Context Switch 執行之處。
> 此三種 ISR 皆為 Cortex-M 內建。
### `SysTick_Handler`
觀察 [port.c](https://github.com/Infineon/freertos/blob/master/Source/portable/COMPONENT_CM4/TOOLCHAIN_ARM/port.c#L508) 中,`xPortSysTickHandler` 的函式內容:
```c
void xPortSysTickHandler( void )
{
/* The SysTick runs at the lowest interrupt priority, so when this interrupt
* executes all interrupts must be unmasked. There is therefore no need to
* save and then restore the interrupt mask value as its value is already
* known. */
portDISABLE_INTERRUPTS();
{
/* Increment the RTOS tick. */
if( xTaskIncrementTick() != pdFALSE )
{
/* A context switch is required. Context switching is performed in
* the PendSV interrupt. Pend the PendSV interrupt. */
portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
}
}
portENABLE_INTERRUPTS();
}
```
進出函式時,會分別「將中斷關閉 / 開啟」,因函式中段是一 Critical section,可能執行 Task 切換動作。
`xTaskIncrementTick` 函式透過 tick+1 來實現 Task Switching,若發現有 Task 需要交換,則回傳 `true` 並紀錄一些狀態。接著透過設定 `portNVIC_PENDSVSET_BIT`,由 PendSV 接手執行。
### `PendSV_Handler`
同樣在 port.c 中,存在 `xPortPendSVHandler` 函式如下:
```c
void xPortPendSVHandler( void )
{
__asm volatile
(
" mrs r0, psp \n"
" isb \n"
" \n"
" ldr r3, pxCurrentTCBConst \n"/* Get the location of the current TCB. */
" ldr r2, [r3] \n"
" \n"
" tst r14, #0x10 \n"/* Is the task using the FPU context? If so, push high vfp registers. */
" it eq \n"
" vstmdbeq r0!, {s16-s31} \n"
" \n"
" stmdb r0!, {r4-r11, r14} \n"/* Save the core registers. */
" str r0, [r2] \n"/* Save the new top of stack into the first member of the TCB. */
" \n"
" stmdb sp!, {r0, r3} \n"
" mov r0, %0 \n"
" msr basepri, r0 \n"
" dsb \n"
" isb \n"
" bl vTaskSwitchContext \n"
" mov r0, #0 \n"
" msr basepri, r0 \n"
" ldmia sp!, {r0, r3} \n"
" \n"
" ldr r1, [r3] \n"/* The first item in pxCurrentTCB is the task top of stack. */
" ldr r0, [r1] \n"
" \n"
" ldmia r0!, {r4-r11, r14} \n"/* Pop the core registers. */
" \n"
" tst r14, #0x10 \n"/* Is the task using the FPU context? If so, pop the high vfp registers too. */
" it eq \n"
" vldmiaeq r0!, {s16-s31} \n"
" \n"
" msr psp, r0 \n"
" isb \n"
" \n"
" bx r14 \n"
" \n"
"pxCurrentTCBConst: .word pxCurrentTCB \n"
::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
);
}
```
> 注意,若換成 RISC-V 等,則實作上會截然不同。
Context Switch 流程可如下呈現:

