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( );
}

 

posted @ 2015-07-16 14:58  IAmAProgrammer  阅读(949)  评论(0编辑  收藏  举报