SylixOS BSP tick驅動流程

SylixOS BSP tick驅動流程

1. 開發環境

- 操作系統:SylixOS 
- 編程環境:RealEvo-IDE3.1 
- 硬件平臺:IMX6Q實驗箱

2.技術實現

時鐘節拍(clock tick)是特定的週期性中斷。這個中斷可以看做是系統心臟的脈動。時鐘的節拍式中斷使得內核可以將任務延時若干個整數時鐘節拍,同時當任務等待事件發生時,提供等待超時的依據。

2.1 Tick的頻率設置 
Tick的頻率需要根據具體的硬件性能來設置。頻率越快,系統的額外開銷也會越大。SylixOS中頻率通 過bspInit.c文件中的halPrimaryCpuMain函數設置,如程序清單 2-1 所示。

                                 程序清單 2-1 tick頻率設置

 

 /*********************************************************************************************************
** 函數名稱: halPrimaryCpuMain
** 功能描述: Primary CPU C 入口
** 輸 入  : NONE
** 輸 出  : 0
** 全局變量:
** 調用模塊:
*********************************************************************************************************/
INT  halPrimaryCpuMain (VOID)
{
    /*
     *  系統內核堆與系統堆
     */
    externUCHAR  __heap_start, __heap_end;
 
    bspOpenocdInit();                                                   /*  初始化 openocd              */
 
    halModeInit();                                                      /*  初始化硬件                  */
 
    /*
     *  這裏的調試端口是脫離操作系統的, 所以它應該不依賴於操作系統而存在.
     *  當系統出現錯誤時, 這個端口顯得尤爲關鍵. (項目成熟後可以通過配置關掉)
     *  (!!當前串口已經由bootloader初始化了, 這裏無需處理.)
     */
 
    /*
     *  這裏使用 bsp設置啓動參數, 如果 bootloader支持, 可使用 bootloader設置.
     *  爲了兼容以前的項目, 這裏 kfpu=yes 允許內核中(包括中斷)使用 FPU.
     */
 
#if (BOARD_MARSBOARD == 1)
    API_KernelStartParam("ncpus=2 kdlog=no kderror=yes kfpu=no heapchk=yes hz=1000 hhz=1000");
#else
    API_KernelStartParam("ncpus=4 kdlog=no kderror=yes kfpu=no heapchk=yes hz=1000 hhz=1000");
#endif
                                                                        /*  操作系統啓動參數設置        */
    API_KernelStart(usrStartup,
                    (PVOID)&__heap_start,
                    (size_t)&__heap_end - (size_t)&__heap_start,
                    LW_NULL, 0);                                        /*  啓動內核                    */
 
    return  (0);                                                        /*  不會執行到這裏              */
}

在代碼中,調用了API_KernelStartParam函數,函數參數是字符串類型,字符串裏的“hz”參數選項後面的數值是需要設置的頻率,調用API_KernelStartParam之後,系統的宏LW_TICK_HZ也會被設置爲對應的頻率,這裏的代碼運行後LW_TICK_HZ被設置爲1000。

2.2 tick初始化

一般選用硬件定時器來實現系統tick功能,因此tick的初始化其實就是IMX6Q實驗箱定時器的初始化。 
SylixOS中通過bsplib.c文件裏的bspTickInit函數實現tick的初始化。 
Imx6Q實驗箱的tick初始化代碼如程序清單 2 2 所示,流程見代碼中的註釋。

                                     程序清單 2-2 tick 初始化
/*********************************************************************************************************
** 函數名稱: bspTickInit
** 功能描述: 初始化 tick 時鐘
** 輸  入  : NONE
** 輸  出  : NONE
** 全局變量:
** 調用模塊:
*********************************************************************************************************/
VOID  bspTickInit (VOID)
{
    REGISTERUINT32      uiIncrementValue, uiPrescaler;
 
#if TICK_IN_THREAD > 0
    LW_CLASS_THREADATTR  threakattr;
 
    API_ThreadAttrBuild(&threakattr, (8 * LW_CFG_KB_SIZE),
                        LW_PRIO_T_TICK,
                        LW_OPTION_THREAD_STK_CHK |
                        LW_OPTION_THREAD_UNSELECT |
                        LW_OPTION_OBJECT_GLOBAL |
                        LW_OPTION_THREAD_SAFE, LW_NULL);
 
    htKernelTicks = API_ThreadCreate("t_tick", (PTHREAD_START_ROUTINE)__tickThread,
                                     &threakattr, LW_NULL);
#endif                                                                  /*  TICK_IN_THREAD > 0          */
 
    /*
     *                          (PRESCALER_value+1) x (Load_value+1) x 2
     * The timer interval = ---------------------------------------------
     *                                          PERIPHCLK
     */
    uiIncrementValue = ((imx6qMainClkGet(CPU_CLK) / 2) / LW_TICK_HZ);
    uiPrescaler      = 0;
 
    /*
     * 1.設置定時器分頻係數,根據LW_TICK_HZ和分頻係數計算出定時器的比較數值;
     */
    _G_uiFullCnt       = uiIncrementValue;
    _G_ui64NSecPerCnt7 = ((1000 * 1000 * 1000 / LW_TICK_HZ) << 7) / _G_uiFullCnt;
 
    /*
     * 2.初始化硬件定時器,設置爲對應的計數模式;
     */
    armGlobalTimerInit(LW_TRUE, uiIncrementValue, uiPrescaler, LW_TRUE);
 
    /*
     * 3.將定時器當前的計數值,和比較值寫入對應的寄存器;
     */
    armGlobalTimerCounterSet(0);
    armGlobalTimerComparatorSet(uiIncrementValue);
    _G_ui64ComparatorCur = 0;
 
    /*
     * 4.綁定定時器的中斷服務函數(__tickTimerIsr),設置中斷優先級;
     */
    API_InterVectorConnect(ARM_TICK_INT_VECTOR,
                           (PINT_SVR_ROUTINE)__tickTimerIsr,
                           LW_NULL,
                           "tick_isr");
 
    API_InterVectorEnable(ARM_TICK_INT_VECTOR);
 
    armGicIrqPrioritySet(ARM_TICK_INT_VECTOR, ARM_TICK_INT_PRIORITY);
 
    /*
     * 5.使能定時器,開始計數。
     */
    armGlobalTimerStart();
}

 

2.3 tick中斷服務函數

SylixOS裏tick中斷服務函數爲__tickTimerIsr,在2.2節的tick初始化過程中已經綁定,對於bsp開發,只需要在__tickTimerIsr函數內,清除tick使用的定時器的中斷位。其餘的不需要修改。如程序清單 2-3 所示。

                       程序清單 2-3 tick 中斷服務函數
 /*********************************************************************************************************
** 函數名稱: __tickTimerIsr
** 功能描述: tick 定時器中斷服務例程
** 輸  入  : NONE
** 輸  出  : 中斷返回值
** 全局變量:
** 調用模塊:
*********************************************************************************************************/
staticirqreturn_t  __tickTimerIsr (VOID)
{
    armGlobalTimerIntClear();                                           /*  清除中斷                    */
 
    API_KernelTicksContext();                                           /*  保存被時鐘中斷的線程控制塊  */
 
#if TICK_IN_THREAD > 0
    API_ThreadResume(htKernelTicks);
#else
    API_KernelTicks();                                                  /*  內核 TICKS 通知             */
    API_TimerHTicks();                                                  /*  高速 TIMER TICKS 通知       */
#endif                                                                  /*  TICK_IN_THREAD > 0          */
 
    return  (LW_IRQ_HANDLED);
}

3.參考資料


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章