Fri, 13 Aug 2010 10:49:23 +0100
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 |