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.參考資料