SysTick Software Timer

 1 #ifndef __SYSTEM_H__
 2 #define __SYSTEM_H__
 3
 4 #include <stdint.h>
 5 #include <stddef.h>
 6
 7 #include "bsp.h"
 8
 9 extern void sys_srand( unsigned int seed );
10 extern int sys_rand( void );
11
12 extern uint32_t g_SysTick_Counter;
13
14 typedef void (*SYS_TIMER_CALLBACK_T)( void * pContext );
15
16 typedef struct SYS_TIMER_T
17 {
18   // set before SysTick_Start()
19   uint32_t Period;
20   SYS_TIMER_CALLBACK_T callback;
21   void * pContext;
22   uint32_t Periodical;
23   // set after SysTick_Start()
24   uint32_t Active;
25   uint32_t Time; // Delta value relative to prev timer
26   struct SYS_TIMER_T *pNext;
27 } SYS_TIMER_T;
28
29 //------------------------------------------------------------------------------
30 void SysTick_DelayTicks( uint32_t ticks );
31
32 void SysTick_DelayUs( uint32_t usec );
33
34 void SysTick_DelayMs( uint32_t msec );
35
36 uint32_t SysTick_Get( void );
37
38 void SysTick_DelayUnitl( uint32_t time );
39
40 void SysTick_Init( void );
41
42 //------------------------------------------------------------------------------
43 void SysTick_Start( SYS_TIMER_T * pTimer );
44
45 void SysTick_Stop( SYS_TIMER_T * pTimer );
46
47 //------------------------------------------------------------------------------
48 uint32_t SysInt_Enable( void );
49
50 uint32_t SysInt_Disable( void );
51
52 void SysInt_Init( void );
53
54 #endif /* __SYSTEM_H__ */
#include "system.h"

#define SysTick_CLKSource_HCLK_Div8_Used    ( 0 )
#define SysTick_IRQ_Priority                ( SYSTICK_PRIORITY )

static uint32_t g_Ticks_In_Ms;
static uint32_t g_Ticks_In_1us;
static uint32_t g_Ticks_In_10us;
static uint32_t g_Ticks_In_100us;
static SYS_TIMER_T *g_TimerHead = 0;
uint32_t g_SysTick_Counter = 0;
uint32_t g_SysInt_Counter = 0;

static unsigned int g_Next = 1;

//------------------------------------------------------------------------------
/// Initialize the seed for rand generator.
/// \param seed rand initiation seed -- g_SysTick_Counter ?
//------------------------------------------------------------------------------
void sys_srand( unsigned int seed )
{
  g_Next = seed;
}

//------------------------------------------------------------------------------
/// Return a random number, maxinum assumed to be 65535
//------------------------------------------------------------------------------
int sys_rand( void )
{
  g_Next = g_Next * 1103515245 + 12345;
  return (unsigned int) ( g_Next / 131072 ) % 65536;
}

/*
 * Configures the priority grouping: pre-emption priority and subpriority.
 *    4 bits for pre-emption priority
 *    0 bits for subpriority
 */
void SysInt_Init( void )
{
  NVIC_PriorityGroupConfig( NVIC_PRIORITY_GROUP );
}

uint32_t SysInt_Disable( void )
{
  __disable_interrupt( );
  if ( g_SysInt_Counter < UINT32_MAX )
    g_SysInt_Counter++;

  return g_SysInt_Counter;
}

uint32_t SysInt_Enable( void )
{
  if ( g_SysInt_Counter > 0 )
    g_SysInt_Counter--;

  if ( g_SysInt_Counter == 0 )
    __enable_interrupt( );
  return g_SysInt_Counter;
}

//------------------------------------------------------------------------------
void SysTick_DelayTicks( uint32_t ticks )
{
  uint32_t SysTickVal = SysTick->VAL;  // from VAL downto 0
  while ( ticks >= SysTickVal ) // SysTick->VAL <= SysTick->LOAD
  {
    ticks -= SysTickVal;
    while ( !( SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk ) )
    {
    }
    SysTickVal = SysTick->LOAD;  // from LOAD downto 0
  }

  if ( ticks > 0 )  // LOAD >= VAL > ticks > 0
  {
    uint32_t SysTickValMarker = SysTick->LOAD - ticks;
    while ( SysTick->VAL > SysTickValMarker )
    {
    }
  }
}

static void SysTick_DelayTicks_64( uint64_t totalTicks )
{
  while ( totalTicks > 0xFFFFFFFF )
  {
    SysTick_DelayTicks( 0xFFFFFFFF );
    totalTicks -= 0xFFFFFFFF;
  }
  SysTick_DelayTicks( totalTicks );
}

void SysTick_DelayUs( uint32_t usec )
{
  uint64_t totalTicks;

  totalTicks = (uint64_t) g_Ticks_In_1us * usec;
  if ( totalTicks == 0 )
  {
    usec /= 10;
    totalTicks = (uint64_t) g_Ticks_In_10us * usec;

    if ( totalTicks == 0 )
    {
      usec /= 10;
      totalTicks = (uint64_t) g_Ticks_In_100us * usec;
    }
  }
  SysTick_DelayTicks_64( totalTicks );
}

void SysTick_DelayMs( uint32_t msec )
{
  uint64_t totalTicks;

  totalTicks = (uint64_t) g_Ticks_In_Ms * msec;
  SysTick_DelayTicks_64( totalTicks );
}

void SysTick_DelayUnitl( uint32_t time )
{
  while ( time > g_SysTick_Counter )
  {
  }
}

uint32_t SysTick_Get( void )
{
  return g_SysTick_Counter;
}
/*------------------------------------------------------------------------------
 Setup SysTick Timer for 1 msec interrupts.
 -------------------------------------------------------------------------------
 1. The SysTick_Config() function is a CMSIS function which configure:
 - The SysTick Reload register with value passed as function parameter.
 - Configure the SysTick IRQ priority to the lowest value (0x0F).
 - Reset the SysTick Counter register.
 - Configure the SysTick Counter clock source to be Core Clock Source (HCLK).
 - Enable the SysTick Interrupt.
 - Start the SysTick Counter.

 2. You can change the SysTick Clock source to be HCLK_Div8 by calling the
 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8) just after the
 SysTick_Config() function call.
 The SysTick_CLKSourceConfig() is defined inside the misc.c file.

 3. You can change the SysTick IRQ priority by calling the
 NVIC_SetPriority(SysTick_IRQn, n)
 just after the SysTick_Config() function call.
 The NVIC_SetPriority() is defined inside the core_cm3.h file.

 4. To adjust the SysTick time base, use the following formula:

 Reload Value = SysTick Counter Clock (Hz) x  Desired Time base (s)

 - Reload Value is the parameter to be passed for SysTick_Config() function
 - Reload Value should not exceed 0xFFFFFF

 5. SysTick_CLKSource: specifies the SysTick clock source.

 SysTick_CLKSource_HCLK
 AHB clock selected as SysTick clock source.

 SysTick_CLKSource_HCLK_Div8
 AHB clock divided by 8 selected as SysTick clock source.

 */
void SysTick_Init( void )
{
#if ( RTOS_USED > 0 )
  return;
#else
  SysTick_Config( SystemCoreClock / 1000 );
  NVIC_SetPriority( SysTick_IRQn, SYSTICK_PRIORITY );

#if (SysTick_CLKSource_HCLK_Div8_Used > 0 )
  uint32_t SysTick_Clock = SystemCoreClock / 8;
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
#else
  uint32_t SysTick_Clock = SystemCoreClock;
#endif

  g_TimerHead = 0;
  g_SysTick_Counter = 0;
  g_Ticks_In_1us = ( SysTick_Clock + 500000 ) / 1000000;   // 168/21, 72/9
  g_Ticks_In_10us = ( SysTick_Clock + 50000 ) / 100000;
  g_Ticks_In_100us = ( SysTick_Clock + 5000 ) / 10000;
  g_Ticks_In_Ms = ( SysTick_Clock + 500 ) / 1000;   // 168000/21000, 72000/9000
#endif
}

#if (RTOS_USED > 0 )
__weak
#endif
//------------------------------------------------------------------------------
// The hook function is called directly from the interrupt handler
// The callback therefore should execute as fast as possible.
// The callback called must not re-enable interrupts.
//
void SysTick_Handler( void )
{
  SysInt_Disable( );

  g_SysTick_Counter++;

  SYS_TIMER_T * pTimerHead = g_TimerHead;
  SYS_TIMER_T * pTimerNext = pTimerHead->pNext;
  if ( pTimerHead )  // at least one timer is Active ...
  {
    pTimerHead->Time--;

    // There might be more than one timeout pr. tick ( with same Period )
    while ( pTimerHead )
    {
      if ( pTimerHead->Time > 0 )
        break;

      // The callback may place new/same items in the queue !!!
      if ( pTimerHead->callback ) // execute as fast as possible
      {
        ( pTimerHead->callback )( pTimerHead->pContext );

        if ( pTimerHead->Periodical > 0 )
          SysTick_Start( pTimerHead );
        else
          SysTick_Stop( pTimerHead );
      }

      pTimerHead = pTimerNext;
      pTimerNext = pTimerHead->pNext;
    }
  }

  SysInt_Enable( );
}

//------------------------------------------------------------------------------
// place timer in the queue
// If the timer is already Active, it will be restarted with new configuration
//
void SysTick_Start( SYS_TIMER_T * pTimer )
{
  uint32_t accumulated;
  SYS_TIMER_T *this, **last;
  if ( ( pTimer->callback == 0 ) || ( pTimer->Period == 0 ) )
    return;

  SysInt_Disable( );

  if ( pTimer->Active )
    SysTick_Stop( pTimer );

  pTimer->Active = 1;
  pTimer->pNext = 0;

  if ( g_TimerHead == 0 ) /* Queue empty ?  */
  {
    pTimer->Time = pTimer->Period;
    g_TimerHead = pTimer;
  }
  else /* Do a sorted insert */
  {
    this = g_TimerHead;
    last = &g_TimerHead;
    accumulated = 0;

    while ( this )
    {
      /* Insert before "this" ? */
      if ( pTimer->Period < accumulated + this->Time )
      {
        pTimer->pNext = this;
        pTimer->Time = pTimer->Period - accumulated;
        this->Time -= pTimer->Time; /* Adjust timeout */
        *last = pTimer;
        break;
      }
      else if ( this->pNext == 0 ) /* At end of queue ?  */
      {
        pTimer->Time = //
          pTimer->Period - accumulated - this->Time;
        this->pNext = pTimer;
        break;
      }
      accumulated += this->Time;
      last = &this->pNext;
      this = this->pNext;
    }
  }

  SysInt_Enable( );
}

void SysTick_Stop( SYS_TIMER_T * pTimer )
{
  if ( pTimer == 0 )
    return;

  if ( g_TimerHead == 0 ) /* Queue empty ?    */
    return;

  SYS_TIMER_T *this, **last;

  SysInt_Disable( );

  this = g_TimerHead;
  last = &g_TimerHead;
  pTimer->Active = 0;

  while ( this )
  {
    if ( this == pTimer ) /* Correct timer ?  */
    {
      pTimer->Period = 0;
      pTimer->Active = 0;
      if ( this->pNext ) /* Adjust timeout   */
        this->pNext->Time += pTimer->Time;
      *last = this->pNext;
      break;
    }
    last = &this->pNext;
    this = this->pNext;
  }

  SysInt_Enable( );
}
时间: 2024-10-10 07:15:54

SysTick Software Timer的相关文章

Implementing Software Timers - Don Libes

在看APUE习题10.5的时候提示了这篇文章,讲的非常清晰,设计也非常巧妙,所以把原文放在这里.值得自己去实现. Title: Implementing Software Timers By: Don Libes Originally appeared in the Nov. 1990 "C User's Journal" and is also reprinted as Chapter 35 of "Obfuscated C and Other Mysteries"

Microsecond and Millisecond C# Timer[转]

文章转至:http://www.codeproject.com/Articles/98346/Microsecond-and-Millisecond-NET-Timer IntroductionAnyone who has used the .NET System.Timers.Timer class for low interval times will realise that it does not offer a very high resolution. The resolution

stm32F4各个库文件的作用分析

system_stm32f4xx.c:This file contains the system clock configuration for STM32F4xx devices. 1 /** 2 ****************************************************************************** 3 * @file system_stm32f4xx.c 4 * @author MCD Application Team 5 * @vers

RT-thread内核之定时器管理

一.前言 rt-thread采用软件定时器线程模式或硬件定时器中断模式来实现系统定时器管理.而rt-thread操作系统在默认情况下是采用的硬件定时器中断模式的方式,用户可以通过宏定义RT_USING_TIMER_SOFT来修改定时器管理模式. 硬件定时器中断模式是利用MCU芯片本身提供的硬件定时器功能,一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断(比如stm32的嘀嗒定时器中断),在硬件定时器中断服务中检查rt-

FREERTOS 手册阅读笔记

郑重声明,版权所有! 转载需说明. FREERTOS堆栈大小的单位是word,不是byte. 根据处理器架构优化系统的任务优先级不能超过32,If the architecture optimized method is used then configMAX_PRIORITIES cannot be greater than 32. vTaskDelay() delay from call the vTaskDelay vTaskDelayUntil delay from last wake

System and method for dynamically adjusting to CPU performance changes

FIELD OF THE INVENTION The present invention is related to computing systems, and more particularly to a system and method for adjusting to changes in processor performance. BACKGROUND INFORMATION Designers of mobile computing platforms are faced wit

RT-Thread

[email protected]:~$ python -V Python 2.7.10 [email protected]:~$ sudo apt-get install scons rt-thread-master/bsp/x86/rtconfig.h /* RT-Thread config file */ #ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__ /* RT_NAME_MAX*/ #define RT_NAME_MAX 8

JN519 --------- zigbee代码

队列: 需要创建3个标准队列(只创建不使用): ------Queue with handle zps_msgMlmeDcfmInd to receive IEEE 802.15.4 MACcommand packets from other nodes ------Queue with handle zps_msgMcpsDcfmInd to receive IEEE 802.15.4 MAC datapackets from other nodes ------Queue with hand

了解FreeRTOS源文件目录结构

参考文献: Understanding the FreeRTOS directory structure. 从官网下载下来的FreeRTOS源文件包,对于每一个已经移植完成的处理器,都有一个与之对应的Demo应用程序可供参考.强烈建议新手首先从Demo开始去学习如何使用FreeRTOS. 基本目录结构 针对各个处理器所做的移植,以及其对应的Demo,数目如此多的文件,全部都存放在同一个压缩文件里.这样做极大地简化了FreeRTOS的发布过程,但是面对这么多的源文件,也很可能会令新手望而生畏.其实