时钟滴答好比人的心脏一样,是操作系统必不可少的一个部件,在线程的切换和软件延时等系统时间相关功能中起着无法替代的角色。
操作系统中的时钟滴答,需要一个周期性的可配置的信号源来实现,并且一般都是以中断的方式在后台通知系统下一个滴答的到来。
(本文原创,转载请注明出处http://blog.youkuaiyun.com/rickleaf)
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里面怎么样去设置和修改时钟滴答了。