/*\r
* Perform any hardware configuration necessary to generate the tick interrupt.\r
*/\r
-void vPortSystemTickHandler( int ) __attribute__((longcall));\r
+static void prvSystemTickHandler( int ) __attribute__((longcall));\r
static void prvSetupTimerInterrupt( void );\r
\r
/*\r
/* This reference is required by the save/restore context macros. */\r
extern volatile unsigned long *pxCurrentTCB;\r
\r
+/* Precalculate the compare match value at compile time. */\r
+static const unsigned long ulCompareMatchValue = ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ );\r
+\r
/*-----------------------------------------------------------*/\r
\r
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE * pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )\r
}\r
lock_wdtcon();\r
\r
- /* Set-up the Compare value. Determine how many bits are used. */\r
- STM_CMCON.reg = ( 0x1fUL - __CLZ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ ) );\r
+ /* Determine how many bits are used without changing other bits in the CMCON register. */\r
+ STM_CMCON.reg &= ~( 0x1fUL );\r
+ STM_CMCON.reg |= ( 0x1fUL - __CLZ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ ) );\r
\r
/* Take into account the current time so a tick doesn't happen immediately. */\r
- STM_CMP0.reg = ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ ) + STM_TIM0.reg;\r
+ STM_CMP0.reg = ulCompareMatchValue + STM_TIM0.reg;\r
\r
- if( 0 != _install_int_handler( configKERNEL_INTERRUPT_PRIORITY, vPortSystemTickHandler, 0 ) )\r
+ if( 0 != _install_int_handler( configKERNEL_INTERRUPT_PRIORITY, prvSystemTickHandler, 0 ) )\r
{\r
/* Set-up the interrupt. */\r
STM_SRC0.reg = ( configKERNEL_INTERRUPT_PRIORITY | 0x00005000UL );\r
\r
/* Enable the Interrupt. */\r
- STM_ISRR.reg = 0x1UL;\r
- STM_ICR.reg = 0x1UL;\r
+ STM_ISRR.reg &= ~( 0x03UL );\r
+ STM_ISRR.reg |= 0x1UL;\r
+ STM_ISRR.reg &= ~( 0x07UL );\r
+ STM_ICR.reg |= 0x1UL;\r
}\r
else\r
{\r
}\r
/*-----------------------------------------------------------*/\r
\r
-void vPortSystemTickHandler( int iArg )\r
+static void prvSystemTickHandler( int iArg )\r
{\r
unsigned long ulSavedInterruptMask;\r
\r
/* Clear the interrupt source. */\r
STM_ISRR.reg = 1UL;\r
\r
- /* Reload the Compare Match register for X ticks into the future. */\r
- STM_CMP0.reg += ( configPERIPHERAL_CLOCK_HZ / configTICK_RATE_HZ );\r
+ /* Reload the Compare Match register for X ticks into the future.\r
+\r
+ If critical section or interrupt nesting budgets are exceeded, then\r
+ it is possible that the calculated next compare match value is in the\r
+ past. If this occurs (unlikely), it is possible that the resulting\r
+ time slippage will exceed a single tick period. Any adverse effect of\r
+ this is time bounded by the fact that only the first n bits of the 56 bit\r
+ STM timer are being used for a compare match, so another compare match\r
+ will occur after an overflow in just those n bits (not the entire 56 bits).\r
+ As an example, if the peripheral clock is 75MHz, and the tick rate is 1KHz,\r
+ a missed tick could result in the next tick interrupt occurring within a\r
+ time that is 1.7 times the desired period. The fact that this is greater\r
+ than a single tick period is an effect of using a timer that cannot be\r
+ automatically reset, in hardware, by the occurrence of a tick interrupt.\r
+ Changing the tick source to a timer that has an automatic reset on compare\r
+ match (such as a GPTA timer) will reduce the maximum possible additional\r
+ period to exactly 1 times the desired period. */\r
+ STM_CMP0.reg += ulCompareMatchValue;\r
\r
/* Kernel API calls require Critical Sections. */\r
ulSavedInterruptMask = portSET_INTERRUPT_MASK_FROM_ISR();\r