当前位置: > 华清远见教育科技集团 > 嵌入式学习 > 讲师博文 > 关于AT91SAM3S8E的SysTick原理和代码分析
关于AT91SAM3S8E的SysTick原理和代码分析
时间:2016-12-14作者:华清远见

SysTick是一个24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。

SYSTICK相关寄存器定义
图中 为SYSTICK相关寄存器定义

CM3允许为 SysTick提供两个时钟源以供选择。第一个是内核的“自由运行时钟”FCLK。“自由”表现在它不来自系统时钟HCLK,因此在系统时钟停止时FCLK也继续运行。第二个是一个外部的参考时钟。但是使用外部时钟时,因为它在内部是通过 FCLK 来采样的,因此其周期必须至少是FCLK 的两倍(采样定理)。很多情况下芯片厂商都会忽略此外部参考时钟,因此通常不可用。通过检查校准寄存器的位[31](NOREF),可以判定是否有可用的外部时钟源,而芯片厂商则必须把该引线连接至正确的电平。

当SysTick定时器从 1计到0时,它将把COUNTFLAG位置位;而下述方法可以清零之:

读取SysTick控制及状态寄存器(STCSR)

往SysTick当前值寄存器(STCVR)中写任何数据

SysTick的大使命,就是定期地产生异常请求,作为系统的时基。OS都需要这种“滴答”来推动任务和时间的管理。如欲使能 SysTick异常,则把 STCSR.TICKINT 置位。另外,如果把向量表重定位到了 SRAM中,还需要为 SysTick异常建立向量,提供其服务例程的入口地址。

SysTick定时器软件设计与实现

SysTick定时器结构体定义

typedef struct
        {
                __IO uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */
                __IO uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */
                __IO uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */
                __I uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */
        } SysTick_Type;

系统倍频到128MHZ// (12000000U)×32÷3=128MHZ

#define CONFIG_PLL0_SOURCE     6
        #define CONFIG_PLL0_MUL       32
        #define CONFIG_PLL0_DIV        3
        #define pll_get_default_rate(pll_id)                  \
                ((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE)         \
                        * CONFIG_PLL##pll_id##_MUL)               \
                        / CONFIG_PLL##pll_id##_DIV)

获取当前系统频率,查看相关宏定义,可知sysclk_get_cpu_hz()的return值为64Mhz

static inline uint32_t sysclk_get_cpu_hz(void)
        {
                /* CONFIG_SYSCLK_PRES is the register value for setting the expected */
                /* prescaler, not an immediate value. */
                return sysclk_get_main_hz() /
                ((CONFIG_SYSCLK_PRES == SYSCLK_PRES_3) ? 3 :
                (1 << (CONFIG_SYSCLK_PRES >> PMC_MCKR_PRES_Pos)));
        }

SysTick_Config()是配置函数,在此将SysTick定时器设置为中断方式。

#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
        static __INLINE uint32_t SysTick_Config(uint32_t ticks)
        {
                if (ticks > SysTick_LOAD_RELOAD_Msk)
                return (1); /* Reload value impossible */
                SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
                NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
                SysTick->VAL = 0; /* Load the SysTick Counter Value */
                SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
                        SysTick_CTRL_TICKINT_Msk |
                        SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
                return (0);                  /* Function successful */
        }

中断函数

void SysTick_Handler(void)
        {
                //进行具体的数据处理
        }

SysTick定时器参考程序及说明

在上几节使用的mdelay函数就是使用定时器实现的。具体代码如下

配置SYSTICK中断时间,每1ms产生一次中断。

SysTick_Config(sysclk_get_cpu_hz() / 1000);

定义一个全局变量,每ms中断使g_ul_ms_ticks加1。

/** Global g_ul_ms_ticks in milliseconds since start of application */
        volatile uint32_t g_ul_ms_ticks = 0;
        void SysTick_Handler(void)
        {
                g_ul_ms_ticks++;
        }

延时函数,记录当前时间,并等待ul_dly_ticks

void mdelay(uint32_t ul_dly_ticks)
        {
                uint32_t ul_cur_ticks;
                ul_cur_ticks = g_ul_ms_ticks;
                while ((g_ul_ms_ticks - ul_cur_ticks) < ul_dly_ticks);
        }

发表评论
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)