分享到plurk 分享到twitter 分享到facebook

版本 21fb774f5dcc7288fe71a10d3529190df96affd3

embedded/chibios

Changes from 21fb774f5dcc7288fe71a10d3529190df96affd3 to 4853f33f6fa475252b80b42403a23bb2eb7bfefd

---
title: ChibiOS/RT
categories: embedded, arm, stm32, stm32f429
toc: yes
...

組員
----
* 莊承翰 / vchchuang
* 詹尚倫 / game
* 陳祐任 / bruce30262
* 陳易駿 / alex122380
* 郭耀琮 / rbugoo131

共筆:  `hackpad<https://stm32f429.hackpad.com/ChibiOSRT--tRTURqqJOhr>`_

作業系統架構
------------
  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 ) 

執行緒(Thread)狀態
^^^^^^^^^^^^^

.. image:: /embedded/chibiThdState.png

* Start : 初始的狀態
* Suspended :
* Running : 正在執行中的狀態
* Stop : 停止的狀態
* Sleeping :
* Ready : 準備好的狀態

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:: /struct_threads_list__coll__graph.png

* 實線方向 : 資料結構繼承關係
* 虛線方向 : 指標指向的資料結構

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 最高

選出下一個可執行的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)
^^^^^^^^^^^^^^^^^^^^^^^^^

| 在chibios當中,是以port_switch()來完成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 

* S-Locked
    + 在 Normal 的狀態中呼叫 chSysLock() 之後會進入此狀態    
    + 此時系統會進入 Kernel locked 的狀態
    + 此時處理器會跑在 thread-privileged mode
    + 在這個狀態裡,無法接收正常中斷(IRQ),但是可以接收快速中斷(FIQ)
    + 在這個狀態裡可以使用 S class 和 I class 的 API 
    + 呼叫 chSysUnlock() 會回到 Normal 狀態 

* I-Locked 
* Serving Regular Interrupt ( SRI ) 
* Serving Fast Interrupt ( SFI ) 
* Serving Non-Maskable Interrupt ( SNMI ) 
    + 在 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
 + 在ChibiOS-RT-Community/os/ports/common/ARMCMx/CMSIS/include/core_cm4.h裡找到相關定義
::

   #define     __IO    volatile             /*!< Defines 'read / write' permissions*/

* Peripheral memory map for DMA2D
  +記錄在`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)

效能表現
--------
* 參考 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>`_