版本 4a89956d0e273f0f9d42c538ddeae192b86db95f
ChibiOS/RT
組員
- 莊承翰 / vchchuang
- 詹尚倫 / game
- 陳祐任 / bruce30262
- 陳易駿 / alex122380
- 郭耀琮 / rbugoo131
共筆: hackpad<https://stm32f429.hackpad.com/ChibiOSRT--tRTURqqJOhr>
_
ChibiOS/RT 參考應用
ChibiOS/RT users<http://www.chibios.org/dokuwiki/doku.php?id=chibios:users>
_
作業系統架構
ChibiOS/RT 是一個相當模組化的設計,部由許多主要的獨立組件構成。而每一個組件又可能細分成許多子系統
.. image:: /embedded/chibi_architecture.png
kernel : OS kernel中與平台無關的部份
port layer :OS kernel中與結構/編譯器 相關的部份
HAL(hardware abstraction layer) : 包含許多抽象的device drivers,提供普遍的I/O API給不同平台的應用程式
platform layer : 包含許多device drivers的實作
various : 提供各種額外但不包含在特定組件的工具的函式庫
HAL 與 platform關係如下 .. image:: /embedded/chibi_HAL_plat.png
中斷(Interrupt) ^^^^^^^^^^^^^^^ * 先備知識 + 可遮罩式中斷 ( Maskable Interrupt ) :
- 一種硬體中斷 - 可以透過軟體控制去設定中斷遮罩暫存器 ( Interrupt Mask Register ) 內的位元遮罩值 ( bit-mask ) 來讓CPU決定要不要回應這個中斷要求。 + 不可遮罩式中斷 ( Non-Maskable Interrupt, NMI ) :
- 一種硬體中斷 - 與可遮罩式中斷不同,它無法用軟體去控制。CPU一定要回應這個中斷要求,不可以忽略。 + 中斷遮罩暫存器 ( Interrupt Mask Registers ) : 在 ARM Cortex-M3中,可以透過設定中斷遮罩暫存器,來控制系統的中斷。共有三種: - PRIMASK : 一個只有一個 bit 的暫存器。設為1時,系統將只會處理 NMI 和 hard fault exception,其他可遮罩式中斷將被全部忽略。設為0時,則可以處理所有中斷。 - FAULTMASK: 一個只有一個 bit 的暫存器。設為1時,系統將只會處理 NMI,其他像是 hard fault exception 或是可遮罩式中斷都將被全部忽略。設為0時,則可以處理 hard fault exception。 - BASEPRI: 8個 bit 的暫存器,用來儲存優先度等級( priority level )。當這個暫存器被設為一個非0值時,系統將會忽略優先度比這個值還要大(代表優先度等級較低) 的中斷。
- Chibi OS/RT 的中斷類別
- 正常中斷 ( Regular Interrupts ):
- 可遮罩式的中斷
- 在 GCC Ports / ARM Cortex-Mx / ARMv7-M 的移植版本中,優先度等級較低的中斷將被視為正常中斷
- 無法搶佔部分的 kernel code
- 在此類的 interrupt handler 裡面可以呼叫 operating system APIs。
- 快速中斷 ( Fast Interrupts ):
- 可遮罩式的中斷
- 在 GCC Ports / ARM Cortex-Mx / ARMv7-M 的移植版本中,優先度等級較高的中斷將被視為快速中斷
- 可以搶佔 kernel code ,也因此有較短的延遲 ( lantency ) 。
- 在此類的 interrupt handler 裡面無法呼叫任何一個 operating system API 。
- 不可遮罩式中斷 ( Non Maskable Interrupts, NMI):
- 不受OS控制的中斷,擁有最短的延遲 ( lowest latency )
- 正常中斷 ( Regular Interrupts ):
- Chibi OS/RT 中對 STM32F4XX 系列所支援的中斷
hal_lld.h<https://github.com/ChibiOS/ChibiOS-RT/blob/master/os/hal/platforms/STM32F4xx/hal_lld.h>
_ 中定義了可用的 ISR name 和 對應的 vector name
.. code-block:: c
#define FLASH_IRQHandler Vector50 /**< Flash. */
#define RCC_IRQHandler Vector54 /**< RCC. */
#define EXTI0_IRQHandler Vector58 /**< EXTI Line 0. */
#define EXTI1_IRQHandler Vector5C /**< EXTI Line 1. */
#define EXTI2_IRQHandler Vector60 /**< EXTI Line 2. */
#define EXTI3_IRQHandler Vector64 /**< EXTI Line 3. */
#define EXTI4_IRQHandler Vector68 /**< EXTI Line 4. */
而在 /os/ports/GCC/ARMCMx/STM32F4xx/vectors.c<https://github.com/ChibiOS/ChibiOS-RT/blob/master/os/ports/GCC/ARMCMx/STM32F4xx/vectors.c>
_ 中則定義了 Interrupt Vector Table 及宣告了處理 Interrupt 的函式
.. code-block:: c
void SysTickVector(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector40(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector44(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector48(void) __attribute__((weak, alias("_unhandled_exception")));
void Vector4C(void) __attribute__((weak, alias("_unhandled_exception")));
另外在 /os/hal/platforms/STM32F4xx/stm32f4xx.h <https://github.com/ChibiOS/ChibiOS-RT-Community/blob/master/os/hal/platforms/STM32F4xx/stm32f4xx.h>
_ 中有一段 code 定義了 Interrupt number
.. code-block:: c
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */
EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */
- 如何設定中斷
- 中斷的初始設定
- 根據所要設定的中斷,確定其 ISR name 有連結到對應的 vector name (就是確認 vector table 裡面有這個 ISR)
- 如果為自設的外部中斷 ( EXTI ) ,則還要先設定 GPIO
- 需注意正常中斷 ( IRQ ) 的 priority 不要設太高
- 最後呼叫 NVICEnableVector( Interrupt_Number, Interrupt_priority ) 這個函式,將這個 Interrupt 做 enabled 的動作
- 撰寫 Interrupt Handler
需依照規定的格式撰寫
.. code-block:: c
CH_IRQ_HANDLER(myIRQ) //傳入參數通常為一 ISR name { CH_IRQ_PROLOGUE();
/* IRQ handling code, preemptable if the architecture supports it.*/ chSysLockFromIsr(); /* Invocation of some I-Class system APIs, never preemptable.*/ chSysUnlockFromIsr(); /* More IRQ handling code, again preemptable.*/ CH_IRQ_EPILOGUE();
}
如果為快速中斷 ( FIQ ) 則不需要 prologue/epilogue,也不能夠呼叫 API
.. code-block:: c
CH_FAST_IRQ_HANDLER(myIRQ) { /* Fast IRQ handling code, preemptable if the architecture supports it. The invocation of any API is forbidden here because fast interrupt handlers can preempt the kernel even within its critical zones in order to minimize latency.*/ }
- 中斷的初始設定
執行緒(Thread)狀態 ^^^^^^^^^^^^^
.. image:: /embedded/chibiThdState.png
- Start : 初始的狀態
- Suspended : Thread剛被create出來時的狀態,尚未決定要被放進ReadyList等待執行或是直接執行
- Running : 正在執行中的狀態
- Stop : 終止的狀態,到達這個狀態表示Thread被執行完了
- Sleeping : Thread暫時不進行工作。此時Thread會被暫時移出ReadyList。等待Mutex解鎖,等待其他Thread執行完,或是等待接收訊息時都會進入這個狀態。
- Ready : 被放進ReadyList, 等待被執行的狀態
ChbiOS/RT 初始化後會建立兩個 thread + Idle thread : - priority level最低,只有在其他thread 處於sleep狀態時才會執行,通常在執行這個threaad時 系統會進入low power mode 且不會做任何事情 + Main thread : - priority=NORMALPRIO ,此thread在一開始執行main() function,且需要時可以變更自己的priority,通常其他的thread也都是由此建立的
Thread and Structure Reference ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. image:: /thread_stuct.png
- 較重要的 member data
- p_prio : Thread priority
- p_ctx : Processor context, 紀錄 Thread 目前的執行狀態
- p_state : 紀錄 Thread 前所處於的狀態 (正在執行, 等待被執行, 等待某一個 Mutex 被解鎖….等)
- p_preempt : 記錄這個 Thread 還有多少個 tick 可以用來執行
- p_waiting : 一個單向的 Thread linked list。 當有其他 Thread 欲等待此 Thread 執行完時, 這些 Thread 就會被塞進這個 waiting list 裡面
- p_msgqueue : 一個雙向的 Thread linked list。 用來存放欲傳給此 Thread 訊息的 Thread (詳見後面 IPC 的部分)。
- p_mtxlist : Mutex 結構,用來存放此 Thread 目前佔有的 Mutex
行程間通訊 ( Inter-Process Communication, IPC ) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Ready List ^^^^^^^^^^^^^ ChibiOS/RT 的 ready list以doubly linked list 實作
.. image:: /embedded/chibi_ready_list.png
數字愈大,優先權愈大 ( priority 相同的話,採用 round-robin strategy)
- 執行序的priority level
- IDLEPRIO :
- value = 1
- 保留給Idle Thread的特殊priority level
- LOWPRIO :
- value = 2
- user thread 中 priority level 最低
- NORMALPRIO :
- value = 64
- main() thread從這個level開始,通常user thread 的priority level是以此為中心
- HIGHPRIO :
- value = 127
- user thread 中 priority level 最高
- IDLEPRIO :
選出下一個可執行的thread, 並進行Context Switch
chsch.c<https://github.com/louis7340/ChibiOS-RT-Community/blob/master/os/kernel/src/chschd.c#L227>
_
.. code-block:: c
if (ntp->p_prio <= currp->p_prio) chSchReadyI(ntp); else { Thread *otp = chSchReadyI(currp); setcurrp(ntp); ntp->p_state = THD_STATE_CURRENT; chSysSwitch(ntp, otp); }
上下文交換(Context Switch) ^^^^^^^^^^^^^^^^^^^^^^^^^
/os/ports/GCC/ARMCMx/chcore_v7m.c(line:236)
.. code-block:: c
void _port_switch(Thread *ntp, Thread *otp) {
asm volatile ("push {r4, r5, r6, r7, r8, r9, r10, r11, lr}" ←儲存舊的thread的狀態
: : : "memory");
#if CORTEX_USE_FPU
asm volatile ("vpush {s16-s31}" : : : "memory");
#endif
asm volatile ("str sp, [%1, #12] \n\t" ←切換stack pointer所指的位址
"ldr sp, [%0, #12]" : : "r" (ntp), "r" (otp)); ←
#if CORTEX_USE_FPU
asm volatile ("vpop {s16-s31}" : : : "memory");
#endif
asm volatile ("pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}" ←讀入新的thread的狀態
: : : "memory");
}
系統狀態(System States) ^^^^^^^^^^^^^^^^^^^^^^
.. image:: http://chibios.sourceforge.net/html/dot_inline_dotgraph_1.png
.. image:: http://chibios.sourceforge.net/html/dot_inline_dotgraph_2.png
.. image:: http://chibios.sourceforge.net/html/dot_inline_dotgraph_3.png
- Init
- ChibiOS/RT 進行OS初始化之前的狀態,進行所謂的物理重置(physical reset)時也會進到這個狀態
- 呼叫chSysInit()這個函式進行初始化
- 在這個狀態裡所有可以發出Maskable Interrupt的sources全部失效
- 初始化完後進到 Normal
- Normal
- 初始化完後到達的狀態
- 在這裡可以執行Thread, 接收並處理任何中斷及呼叫任何system API
- Suspended
- 在這個狀態裡,無法接收正常中斷(IRQ),但是可以接收快速中斷(FIQ)
- 除了可以呼叫chSysDisable()到達Disable狀態,以及chSysEnable()到達Normal狀態之外,其他所有system API都不能呼叫
- Disabled
- 所有可遮罩式中斷資源全部失效,系統僅能處理不可遮罩式中斷(NMI)
- 除了可以呼叫chSysEnable()到達Normal狀態,以及chSysSuspend()到達Suspended狀態之外,其他所有system API都不能呼叫
- Sleep
- 當系統中沒有其他的Thread要跑時,此時系統會執行一個
idle thread<idle thread>
_,到達這個狀態 - 此時系統將處於 low power mode,並等待一個中斷跳出這個狀態
- 接收到一個IRQ時,將會跑到 SRI 狀態去處理中斷,處理完後會回到 Normal
- 當系統中沒有其他的Thread要跑時,此時系統會執行一個
- S-Locked
- 在 Normal 的狀態中呼叫 chSysLock() 之後會進入此狀態
- 此時系統會進入 Kernel locked 的狀態
- 此時處理器會跑在 thread-privileged mode
- 在這個狀態裡,無法接收正常中斷(IRQ),但是可以接收快速中斷(FIQ)
- 在這個狀態裡可以使用 S class 和 I class 的 API
- 呼叫 chSysUnlock() 會回到 Normal 狀態
- 在 Normal 的狀態中呼叫 chSysLock() 之後會進入此狀態
- I-Locked
- 在 SRI 的狀態中呼叫 chSysLockFromIsr() 之後會進入這個狀態
- 此時系統會進入 Kernel locked 的狀態
- 此時處理器會跑在 exception-privileged mode
- 在這個狀態裡,無法接收正常中斷(IRQ),但是可以接收快速中斷(FIQ)
- 在這個狀態裡可以使用 I class 的 API
- 呼叫 chSysUnlockFromIsr() 會回到 SRI 狀態
- Serving Regular Interrupt ( SRI )
- 處理一個正常中斷 ( IRQ ) 時,會進入這個狀態
- 此時只有更高等級的中斷能夠進行搶佔
- 此時處理器會跑在 exception-privileged mode
- 此時無法呼叫大部分的 system API,除非先呼叫 chSysLockFromIsr() 進入 I-Locked state,之後才能夠進行其他 API 的呼叫
- Serving Fast Interrupt ( SFI )
- 處理一個快速中斷 ( FIQ ) 時會進入這個狀態
- 無法呼叫所有 system API
- 除了 Init , Halted , SNMI , Disabled 之外的任一狀態,只要接收到 FIQ 就會跳到這個狀態,處理完後會回到上一狀態
- Serving Non-Maskable Interrupt ( SNMI )
- 處裡一個不可遮罩式的中斷時 (NMI) 會進入這個狀態
- 無法呼叫所有 system API
- 除了 Halted 的任一狀態裡只要接收到 NMI,或是在 Halted 中收到非同步的 NMI 時就會跳到這個狀態,處理完後會回到上一狀態
- Halted
- 呼叫 chSysHalt() 時會進入這個狀態
- 所有中斷都不能使用
硬體驅動原理
以 DMA2D 為例
DMA2D的架構簡圖:
.. image:: /DMA2D_structure.png
在對硬體的driver作設計時會用到很多_IO的type
在
core_cm4.h<https://github.com/rbugoo131/ChibiOS-RT-Community/blob/master/os/ports/common/ARMCMx/CMSIS/include/core_cm4.h#L207>
_裡找到相關定義 .. code-block:: c#define __IO volatile /!< Defines ‘read / write’ permissions/
DMA2D memory address
- 記錄在
stm32f4xx.h<https://github.com/rbugoo131/ChibiOS-RT-Community/blob/master/os/hal/platforms/STM32F4xx/stm32f4xx.h>
_
- 記錄在
.. code-block:: c
#define PERIPH_BASE ((uint32_t)0x40000000) /!< Peripheral base address in the alias region #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) #define DMA2D_BASE (AHB1PERIPH_BASE + 0xB000) #define DMA2D ((DMA2D_TypeDef )DMA2D_BASE)
設定要取得的資料 .. code-block:: c
static uint8_t frame_buffer[240 * 320 * 3] attribute((section(“.sdram”)));
DMA2D的API與資料結構設定,記錄在
stm32_dma2d<https://github.com/rbugoo131/ChibiOS-RT-Community/tree/master/os/hal/platforms/STM32/DMA2Dv1>
_- dma2d_layercfg_t的struct
========== ==== ================ ==== =============== Type Name Description
————————————————————- void bufferp Frame buffer address size_t wrap_offset Offset between lines, in pixels dma2d_pixfmt_t fmt Pixel format dma2d_color_t def_color Default color, RGB-888 uint8_t const_alpha Constant alpha factor dma2d_palcfg_t palettep Palette specs, or @p NULL ========== ==== ================ ==== ===============
- 設定DMA2D取得memory data的位址(API):
- dma2dBgSetConfig + dma2dBgSetConfigS
- dma2dBgSetAddressI
- dma2dBgSetWrapOffsetI
- dma2dBgSetPixelFormatI
- dma2dBgSetDefaultColorI
- dma2dBgSetConstantAlphaI
- DMA2D TypeDef:
============== === ================================================ == ===================== Name Description Address offset ———————————————————————————————— CR Control Register 0x00 ISR Interrupt Status Register 0x04 IFCR Interrupt Flag Clear Register 0x08 FGMAR Foreground Memory Address Register 0x0C FGOR Foreground Offset Register 0x10 BGMAR Background Memory Address Register 0x14 BGOR Background Offset Register 0x18 FGPFCCR Foreground PFC Control Register 0x1C FGCOLR Foreground Color Register 0x20 BGPFCCR Background PFC Control Register 0x24 BGCOLR Background Color Register 0x28 FGCMAR Foreground CLUT Memory Address Register 0x2C BGCMAR Background CLUT Memory Address Register 0x30 OPFCCR Output PFC Control Register 0x34 OCOLR Output Color Register 0x38 OMAR Output Memory Address Register 0x3C OOR Output Offset Register 0x40 NLR Number of Line Register 0x44 LWR Line Watermark Register 0x48 AMTCR AHB Master Timer Configuration Register 0x4C RESERVED[236] Reserved 0x50-0x3FF FGCLUT[256] Foreground CLUT 400-7FF BGCLUT[256] Background CLUT 800-BFF ============== === ================================================ == =====================
效能表現
- 參考 ChibiOS/RT 的 test/testbmk.c
參考資料
Building eye-catching GUIs for your embedded MCU designs<http://www.embedded.com/design/mcus-processors-and-socs/4426244/1/Building-eye-catching-GUIs-for-your-embedded-MCU-designs>
_ChibiOS/RT - SourceForge<http://chibios.sourceforge.net/html/index.html>
_Overview of the Cortex-M3, Chapter 2<http://www.arm.com/files/word/Yiu_Ch2.pdf>
_