zoukankan      html  css  js  c++  java
  • 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( );
    }
  • 相关阅读:
    PAT 甲级 1074 Reversing Linked List (25 分)(链表部分逆置,结合使用双端队列和栈,其实使用vector更简单呐)
    (转载)文献可视化--vosviewer入门
    给出先序和中序,给一个数找到位置并输出它左子树里最大的数
    PAT 甲级 1073 Scientific Notation (20 分) (根据科学计数法写出数)
    python flask框架学习(三)——豆瓣微信小程序案例(二)整理封装block,模板的继承
    第一章 概述
    Mybatis最入门---数据库的下载与安装
    前端页面——Cookie与Session有什么差别
    有限状态机(FSM)的Java 演示
    windows使用技巧和工具(后面可能更新linux)
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4651357.html
Copyright © 2011-2022 走看看