STM32 eCos 啟動程式碼分析(三)系統時鐘滴答
時鐘滴答好比人的心臟一樣,是作業系統必不可少的一個部件,線上程的切換和軟體延時等系統時間相關功能中起著無法替代的角色。
作業系統中的時鐘滴答,需要一個週期性的可配置的訊號源來實現,並且一般都是以中斷的方式在後臺通知系統下一個滴答的到來。
eCos中為了提供移植性,一般會用CYGNUM_HAL_INTERRUPT_RTC表示系統時鐘滴答的中斷源
下面是MINI2440中的時鐘滴答,採用的是TIMER4
packages\hal\arm\arm9\mini2440\current\include\hal_platform_ints.h
// The vector used by the Real time clock #define CYGNUM_HAL_INTERRUPT_RTC CYGNUM_HAL_INTERRUPT_TIMER4
這個是我們正在討論的CortexM的時鐘滴答
packages\hal\cortexm\arch\current\include\hal_intr.h
//========================================================================== // Include variant definitions here. #include <cyg/hal/var_intr.h> // Variant or platform allowed to override these definitions to use // a different RTC #ifndef CYGNUM_HAL_INTERRUPT_RTC #define CYGNUM_HAL_INTERRUPT_RTC CYGNUM_HAL_INTERRUPT_SYS_TICK #endif
eCos的CortexM體系結構中,預設採用systick作為系統的時鐘滴答,因為採用了體系+變體抽象層,所以可以在具體的硬體平臺去覆蓋這個設定。
systick是cortexm特有的一個部件,在Cortex-M3和STM32不完全手冊中都有介紹。作為Cortex-M3 CPU的特殊部件,systick得暫存器地址和設定方法
對於所有的CortexM體系結構的CPU都是公用的,他可以像普通的定時器一樣設定裝入值。因此選擇這個定時器作為時鐘滴答對於這個體系結構的可移植性來說有很大的幫助。
下面看一下如何設定時鐘滴答的時間
// Select the clock source of the system tick timer #ifdef CYGHWR_HAL_CORTEXM_SYSTICK_CLK_SOURCE_EXTERNAL #define CYGARC_REG_SYSTICK_CSR_CLK_SRC CYGARC_REG_SYSTICK_CSR_CLK_EXT #elif defined(CYGHWR_HAL_CORTEXM_SYSTICK_CLK_SOURCE_INTERNAL) #define CYGARC_REG_SYSTICK_CSR_CLK_SRC CYGARC_REG_SYSTICK_CSR_CLK_INT #endif #define HAL_CLOCK_INITIALIZE( __period ) \ { \ cyg_uint32 __p = __period; \ __p = hal_cortexm_systick_clock / ( 1000000 / __p ) - 1; \ HAL_WRITE_UINT32(CYGARC_REG_SYSTICK_BASE+CYGARC_REG_SYSTICK_RELOAD, \ __p ); \ HAL_WRITE_UINT32(CYGARC_REG_SYSTICK_BASE+CYGARC_REG_SYSTICK_CSR, \ CYGARC_REG_SYSTICK_CSR_ENABLE | \ CYGARC_REG_SYSTICK_CSR_CLK_SRC ); \ } #define HAL_CLOCK_RESET( __vector, __period ) \ { \ cyg_uint32 __csr; \ HAL_READ_UINT32(CYGARC_REG_SYSTICK_BASE+CYGARC_REG_SYSTICK_CSR, __csr ); \ } #define HAL_CLOCK_READ( __pvalue ) \ { \ cyg_uint32 __period, __value; \ HAL_READ_UINT32(CYGARC_REG_SYSTICK_BASE+CYGARC_REG_SYSTICK_RELOAD, __period ); \ HAL_READ_UINT32(CYGARC_REG_SYSTICK_BASE+CYGARC_REG_SYSTICK_VALUE, __value ); \ __value = ( __period + 1 ) - __value; \ __value /= (hal_cortexm_systick_clock / 1000000 ); \ *(__pvalue) = __value; \ }
在eCos的cortexm體系的移植中一個重要的一點就是,系統時鐘運算工具。
// Configure clocks
hal_stm32_sysclk = CYGARC_HAL_CORTEXM_STM32_INPUT_CLOCK;
cfgr = 0;
#if defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSE)
cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE;
#elif defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSE_HALF)
cfgr |= CYGHWR_HAL_STM32_RCC_CFGR_PLLSRC_HSE |
CYGHWR_HAL_STM32_RCC_CFGR_PLLXTPRE;
hal_stm32_sysclk /= 2;
#elif defined(CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_SOURCE_HSI_HALF)
hal_stm32_sysclk /= 2;
#endif
// Calculate clocks from configuration
hal_stm32_sysclk *= CYGHWR_HAL_CORTEXM_STM32_CLOCK_PLL_MUL;
hal_stm32_hclk = hal_stm32_sysclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_HCLK_DIV;
hal_stm32_pclk1 = hal_stm32_hclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK1_DIV;
hal_stm32_pclk2 = hal_stm32_hclk / CYGHWR_HAL_CORTEXM_STM32_CLOCK_PCLK2_DIV;
#ifdef CYGHWR_HAL_CORTEXM_SYSTICK_CLK_SOURCE_INTERNAL
hal_cortexm_systick_clock = hal_stm32_hclk;
#else
hal_cortexm_systick_clock = hal_stm32_hclk / 8;
#endif
從上面兩段程式來看,變體抽象層裡系統時鐘初始化的時候計算出最後的需要的hal_cortexm_systick_clock
給體系結構抽象層中直接應用。
有了以上的知識,大家就知道eCos中CortexM裡面怎麼樣去設定和修改時鐘滴答了。