drivers/service/MicoTimerService.c

Fri, 13 Aug 2010 10:49:23 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Fri, 13 Aug 2010 10:49:23 +0100
changeset 0
396b0bd970d3
permissions
-rw-r--r--

Initial import, Timer v3.0

philpem@0 1 /****************************************************************************
philpem@0 2 **
philpem@0 3 ** Name: MicoTimerService.c
philpem@0 4 **
philpem@0 5 ** Description:
philpem@0 6 ** Implements timer service functionality:
philpem@0 7 ** -- registering a timer as a system timer (64-bit)
philpem@0 8 ** and retrieving the system tick
philpem@0 9 **
philpem@0 10 ** -- registering a timer as a "lookup-able" device
philpem@0 11 ** (user does not have to work with these functions)
philpem@0 12 **
philpem@0 13 ** $Revision: $
philpem@0 14 **
philpem@0 15 ** Disclaimer:
philpem@0 16 **
philpem@0 17 ** This source code is intended as a design reference which
philpem@0 18 ** illustrates how these types of functions can be implemented. It
philpem@0 19 ** is the user's responsibility to verify their design for
philpem@0 20 ** consistency and functionality through the use of formal
philpem@0 21 ** verification methods. Lattice Semiconductor provides no warranty
philpem@0 22 ** regarding the use or functionality of this code.
philpem@0 23 **
philpem@0 24 ** --------------------------------------------------------------------
philpem@0 25 **
philpem@0 26 ** Lattice Semiconductor Corporation
philpem@0 27 ** 5555 NE Moore Court
philpem@0 28 ** Hillsboro, OR 97214
philpem@0 29 ** U.S.A
philpem@0 30 **
philpem@0 31 ** TEL: 1-800-Lattice (USA and Canada)
philpem@0 32 ** (503)268-8001 (other locations)
philpem@0 33 **
philpem@0 34 ** web: http://www.latticesemi.com
philpem@0 35 ** email: techsupport@latticesemi.com
philpem@0 36 **
philpem@0 37 ** --------------------------------------------------------------------------
philpem@0 38 **
philpem@0 39 ** Change History (Latest changes on top)
philpem@0 40 **
philpem@0 41 ** Ver Date Description
philpem@0 42 ** --------------------------------------------------------------------------
philpem@0 43 **
philpem@0 44 ** 3.0 Mar-25-2008 Added Header
philpem@0 45 **
philpem@0 46 **---------------------------------------------------------------------------
philpem@0 47 *****************************************************************************/
philpem@0 48
philpem@0 49 #include "MicoTimerService.h"
philpem@0 50 #include "MicoUtils.h"
philpem@0 51 #include "MicoMacros.h"
philpem@0 52 #include "MicoInterrupts.h"
philpem@0 53 #include "LookupServices.h"
philpem@0 54
philpem@0 55
philpem@0 56 #ifdef __cplusplus
philpem@0 57 extern "C"
philpem@0 58 {
philpem@0 59 #endif /* __cplusplus */
philpem@0 60
philpem@0 61
philpem@0 62 /******************************************************************************
philpem@0 63 * Type-definitions and manifest constants and structures *
philpem@0 64 ******************************************************************************/
philpem@0 65 typedef struct st_ActivityListEntry{
philpem@0 66 void *ctx;
philpem@0 67 MicoSysTimerActivity_t activity;
philpem@0 68 }ActivityListEntry_t;
philpem@0 69
philpem@0 70
philpem@0 71 /******************************************************************************
philpem@0 72 * data memebers *
philpem@0 73 ******************************************************************************/
philpem@0 74 static ActivityListEntry_t s_SysTimerActivity = {0,0};
philpem@0 75 static MicoTimerCtx_t *s_MicoSystemTimer = 0;
philpem@0 76 static unsigned long long int s_MicoCPUTicks;
philpem@0 77 static unsigned int s_MicoSysTicks;
philpem@0 78
philpem@0 79 #ifdef __cplusplus
philpem@0 80 }
philpem@0 81 #endif /* __cplusplus */
philpem@0 82
philpem@0 83 /******************************************************************************
philpem@0 84 * debug routines *
philpem@0 85 ******************************************************************************/
philpem@0 86 #ifdef _MICO_TIMER_SERVICES_DEBUG_ENABLED_
philpem@0 87
philpem@0 88 void DumpMicoTimerServicesActivityList()
philpem@0 89 {
philpem@0 90 /* ToDo */
philpem@0 91 }
philpem@0 92
philpem@0 93
philpem@0 94 void DumpMicoTimerServicesRegisteredTimers()
philpem@0 95 {
philpem@0 96 /* ToDo */
philpem@0 97 }
philpem@0 98
philpem@0 99 #endif
philpem@0 100
philpem@0 101
philpem@0 102 /******************************************************************************
philpem@0 103 * system-timer ISR *
philpem@0 104 ******************************************************************************/
philpem@0 105 static void MicoTimerServicesSysTimerISR(void *pContext)
philpem@0 106 {
philpem@0 107 MicoSysTimerActivity_t activity;
philpem@0 108
philpem@0 109 /* increment CPU ticks */
philpem@0 110 s_MicoCPUTicks += s_MicoSysTicks;
philpem@0 111
philpem@0 112 /* if there's an activity registered for system-tick, invoke it */
philpem@0 113 if(s_SysTimerActivity.activity != 0){
philpem@0 114 activity = s_SysTimerActivity.activity;
philpem@0 115 activity(s_SysTimerActivity.ctx);
philpem@0 116 };
philpem@0 117
philpem@0 118 return;
philpem@0 119 }
philpem@0 120
philpem@0 121
philpem@0 122
philpem@0 123 /******************************************************************************
philpem@0 124 * Initializes TimerServices *
philpem@0 125 ******************************************************************************/
philpem@0 126 static void MicoTimerServicesInit()
philpem@0 127 {
philpem@0 128 static int s_Initialized = 0;
philpem@0 129 if(s_Initialized == 0) {
philpem@0 130 s_Initialized = 1;
philpem@0 131 s_SysTimerActivity.activity = 0;
philpem@0 132 s_MicoSystemTimer = 0;
philpem@0 133 s_MicoCPUTicks = 0;
philpem@0 134 }
philpem@0 135 }
philpem@0 136
philpem@0 137
philpem@0 138 /******************************************************************************
philpem@0 139 * registers a system-timer if one isn't already registered.. *
philpem@0 140 ******************************************************************************/
philpem@0 141 MicoTimerCtx_t* RegisterSystemTimer(MicoTimerCtx_t *pTimer, unsigned int TicksInMS)
philpem@0 142 {
philpem@0 143 MicoTimerServicesInit();
philpem@0 144
philpem@0 145 /*
philpem@0 146 * If there's a system-timer registered, don't modify it but simply
philpem@0 147 * return its context information
philpem@0 148 */
philpem@0 149 if(s_MicoSystemTimer != 0)
philpem@0 150 return(s_MicoSystemTimer);
philpem@0 151
philpem@0 152 /*
philpem@0 153 * there's none, so register this one as the system-timer
philpem@0 154 */
philpem@0 155 if(pTimer != 0){
philpem@0 156 s_MicoSystemTimer = pTimer;
philpem@0 157 if(TicksInMS == 0)
philpem@0 158 TicksInMS = 1;
philpem@0 159 s_MicoSysTicks = (TicksInMS * (MICO32_CPU_CLOCK_MHZ/1000));
philpem@0 160 MicoTimerStart( s_MicoSystemTimer,
philpem@0 161 MicoTimerServicesSysTimerISR,
philpem@0 162 0,
philpem@0 163 s_MicoSysTicks-1,
philpem@0 164 1);
philpem@0 165 }
philpem@0 166
philpem@0 167 return(s_MicoSystemTimer);
philpem@0 168 }
philpem@0 169
philpem@0 170
philpem@0 171
philpem@0 172 /******************************************************************************
philpem@0 173 * get cpu-ticks *
philpem@0 174 ******************************************************************************/
philpem@0 175 void MicoGetCPUTicks(unsigned long long int *ticks)
philpem@0 176 {
philpem@0 177 /*
philpem@0 178 * We need to get a finer resolution than the system-tick and also
philpem@0 179 * account for a possible roll-over just after we read the snaphot.
philpem@0 180 * We're definitely not going to be exact on the dot but we'll be
philpem@0 181 * pretty darn close; higher the clock-speed, less the error (in
philpem@0 182 * seconds).
philpem@0 183 */
philpem@0 184 unsigned long long int cpuTicks = 0;
philpem@0 185 unsigned int intrMask;
philpem@0 186 unsigned int snapshot;
philpem@0 187
philpem@0 188 if(s_MicoSystemTimer != 0) {
philpem@0 189
philpem@0 190 /* disable interrupts and read the gross resolution tick-count */
philpem@0 191 intrMask = MicoDisableInterrupts();
philpem@0 192 cpuTicks = s_MicoCPUTicks;
philpem@0 193
philpem@0 194
philpem@0 195 /* read the snapshot to get a finer tuning */
philpem@0 196 snapshot = MicoTimerSnapshot(s_MicoSystemTimer);
philpem@0 197
philpem@0 198
philpem@0 199 /*
philpem@0 200 * Since the timer is an external peripheral over a bus, there may be
philpem@0 201 * contention and we may not get the right reading. So allow another
philpem@0 202 * interrupt if it happened, to make our tick-reading as accurate
philpem@0 203 * as possible.
philpem@0 204 */
philpem@0 205 MicoEnableInterrupt(s_MicoSystemTimer->intrLevel);
philpem@0 206
philpem@0 207
philpem@0 208 /* we're done; decide what our reading should be */
philpem@0 209 MicoDisableInterrupts();
philpem@0 210 if(cpuTicks == s_MicoCPUTicks)
philpem@0 211 cpuTicks += (s_MicoSysTicks - snapshot -1);
philpem@0 212 else
philpem@0 213 cpuTicks = s_MicoCPUTicks;
philpem@0 214
philpem@0 215
philpem@0 216 /* restore interrupts */
philpem@0 217 MicoEnableInterrupts(intrMask);
philpem@0 218 }
philpem@0 219
philpem@0 220 if(ticks != 0)
philpem@0 221 *ticks = cpuTicks;
philpem@0 222
philpem@0 223 return;
philpem@0 224 }
philpem@0 225
philpem@0 226
philpem@0 227 /******************************************************************************
philpem@0 228 * Registers a periodic-activity (system-timer ticks) *
philpem@0 229 *----------------------------------------------------------------------------*
philpem@0 230 * System-timer must exist for this to function correctly. *
philpem@0 231 ******************************************************************************/
philpem@0 232 void MicoRegisterActivity(MicoSysTimerActivity_t activity, void *ctx)
philpem@0 233 {
philpem@0 234 MicoTimerServicesInit();
philpem@0 235
philpem@0 236 if(s_MicoSystemTimer == 0)
philpem@0 237 return;
philpem@0 238
philpem@0 239 MicoDisableInterrupt(s_MicoSystemTimer->intrLevel);
philpem@0 240
philpem@0 241 s_SysTimerActivity.ctx = ctx;
philpem@0 242 s_SysTimerActivity.activity = activity;
philpem@0 243
philpem@0 244 MicoEnableInterrupt(s_MicoSystemTimer->intrLevel);
philpem@0 245
philpem@0 246 return;
philpem@0 247 }
philpem@0 248