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