Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
ns_timer.c
00001 /* 00002 * Copyright (c) 2014-2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "ns_types.h" 00018 #include "ns_list.h" 00019 #include "ns_timer.h" 00020 #include "eventOS_callback_timer.h" 00021 #include "platform/arm_hal_interrupt.h" 00022 #include "platform/arm_hal_timer.h" 00023 #include "nsdynmemLIB.h" 00024 00025 #ifndef NS_EXCLUDE_HIGHRES_TIMER 00026 typedef enum ns_timer_state_e { 00027 NS_TIMER_ACTIVE = 0, // Will run on the next HAL interrupt 00028 NS_TIMER_HOLD, // Will run on a later HAL interrupt 00029 NS_TIMER_RUN_INTERRUPT, // Running on the interrupt we're currently handling 00030 NS_TIMER_STOP // Timer not scheduled ("start" not called since last callback) 00031 } ns_timer_state_e; 00032 00033 typedef struct ns_timer_struct { 00034 int8_t ns_timer_id; 00035 ns_timer_state_e timer_state; 00036 uint16_t slots; 00037 uint16_t remaining_slots; 00038 void (*interrupt_handler)(int8_t, uint16_t); 00039 ns_list_link_t link; 00040 } ns_timer_struct; 00041 00042 static NS_LIST_DEFINE(ns_timer_list, ns_timer_struct, link); 00043 00044 00045 #define NS_TIMER_RUNNING 1 00046 static uint8_t ns_timer_state = 0; 00047 00048 #ifdef ATMEGA256RFR2 00049 #define COMPENSATION 3 00050 #define COMPENSATION_TUNE 1 00051 #else 00052 #define COMPENSATION 0 00053 #define COMPENSATION_TUNE 0 00054 #endif 00055 00056 static void ns_timer_interrupt_handler(void); 00057 static ns_timer_struct *ns_timer_get_pointer_to_timer_struct(int8_t timer_id); 00058 static bool ns_timer_initialized = 0; 00059 00060 int8_t eventOS_callback_timer_register(void (*timer_interrupt_handler)(int8_t, uint16_t)) 00061 { 00062 int8_t retval = -1; 00063 00064 if (!ns_timer_initialized) { 00065 /*Set interrupt handler in HAL driver*/ 00066 platform_timer_set_cb(ns_timer_interrupt_handler); 00067 ns_timer_initialized = 1; 00068 } 00069 00070 /*Find first free timer ID in timer list*/ 00071 /*(Note use of uint8_t to avoid overflow if we reach 0x7F)*/ 00072 for (uint8_t i = 0; i <= INT8_MAX; i++) { 00073 if (!ns_timer_get_pointer_to_timer_struct(i)) { 00074 retval = i; 00075 break; 00076 } 00077 } 00078 00079 if (retval == -1) { 00080 return -1; 00081 } 00082 00083 ns_timer_struct *new_timer = ns_dyn_mem_alloc(sizeof(ns_timer_struct)); 00084 if (!new_timer) { 00085 return -1; 00086 } 00087 00088 /*Initialise new timer*/ 00089 new_timer->ns_timer_id = retval; 00090 new_timer->timer_state = NS_TIMER_STOP; 00091 new_timer->remaining_slots = 0; 00092 new_timer->interrupt_handler = timer_interrupt_handler; 00093 00094 // Critical section sufficient as long as list can't be reordered from 00095 // interrupt, otherwise will need to cover whole routine 00096 platform_enter_critical(); 00097 ns_list_add_to_end(&ns_timer_list, new_timer); 00098 platform_exit_critical(); 00099 00100 /*Return timer ID*/ 00101 return retval; 00102 } 00103 00104 int8_t eventOS_callback_timer_unregister(int8_t ns_timer_id) 00105 { 00106 ns_timer_struct *current_timer; 00107 00108 current_timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); 00109 if (!current_timer) { 00110 return -1; 00111 } 00112 00113 // Critical section sufficient as long as list can't be reordered from 00114 // interrupt, otherwise will need to cover whole routine 00115 platform_enter_critical(); 00116 ns_list_remove(&ns_timer_list, current_timer); 00117 platform_exit_critical(); 00118 00119 ns_dyn_mem_free(current_timer); 00120 return 0; 00121 } 00122 00123 00124 static int8_t ns_timer_start_pl_timer(uint16_t pl_timer_start_slots) 00125 { 00126 /*Don't start timer with 0 slots*/ 00127 if (!pl_timer_start_slots) { 00128 pl_timer_start_slots = 1; 00129 } 00130 00131 /*Start HAL timer*/ 00132 platform_timer_start(pl_timer_start_slots); 00133 /*Set HAL timer state to running*/ 00134 ns_timer_state |= NS_TIMER_RUNNING; 00135 return 0; 00136 } 00137 00138 int8_t ns_timer_sleep(void) 00139 { 00140 int8_t ret_val = -1; 00141 if (ns_timer_state & NS_TIMER_RUNNING) { 00142 /*Start HAL timer*/ 00143 platform_timer_disable(); 00144 /*Set HAL timer state to running*/ 00145 ns_timer_state &= ~NS_TIMER_RUNNING; 00146 ret_val = 0; 00147 } 00148 return ret_val; 00149 } 00150 00151 static int8_t ns_timer_get_next_running_to(void) 00152 { 00153 uint8_t hold_count = 0; 00154 ns_timer_struct *first_timer = NULL; 00155 00156 /*Find hold-labelled timer with the least remaining slots*/ 00157 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00158 if (current_timer->timer_state == NS_TIMER_HOLD) { 00159 if (!first_timer || current_timer->remaining_slots < first_timer->remaining_slots) { 00160 first_timer = current_timer; 00161 } 00162 /*For optimisation, count the found timers*/ 00163 hold_count++; 00164 } 00165 } 00166 00167 if (!first_timer) { 00168 return 0; 00169 } 00170 00171 /*If hold-labelled timer found, set it active and start the HAL driver*/ 00172 hold_count--; 00173 first_timer->timer_state = NS_TIMER_ACTIVE; 00174 /*Compensate time spent in timer function*/ 00175 if (first_timer->remaining_slots > COMPENSATION) { 00176 first_timer->remaining_slots -= COMPENSATION; 00177 } 00178 /*Start HAL timer*/ 00179 ns_timer_start_pl_timer(first_timer->remaining_slots); 00180 00181 /*Update other hold-labelled timers*/ 00182 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00183 if (hold_count == 0) { // early termination optimisation 00184 break; 00185 } 00186 if (current_timer->timer_state == NS_TIMER_HOLD) { 00187 if (current_timer->remaining_slots == first_timer->remaining_slots) { 00188 current_timer->timer_state = NS_TIMER_ACTIVE; 00189 } else { 00190 current_timer->remaining_slots -= first_timer->remaining_slots; 00191 /*Compensate time spent in timer function*/ 00192 if (current_timer->remaining_slots > COMPENSATION) { 00193 current_timer->remaining_slots -= COMPENSATION; 00194 } 00195 } 00196 hold_count--; 00197 } 00198 } 00199 00200 return 0; 00201 } 00202 00203 00204 static ns_timer_struct *ns_timer_get_pointer_to_timer_struct(int8_t timer_id) 00205 { 00206 /*Find timer with the given ID*/ 00207 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00208 if (current_timer->ns_timer_id == timer_id) { 00209 return current_timer; 00210 } 00211 } 00212 return NULL; 00213 } 00214 00215 int8_t eventOS_callback_timer_start(int8_t ns_timer_id, uint16_t slots) 00216 { 00217 int8_t ret_val = 0; 00218 uint16_t pl_timer_remaining_slots; 00219 ns_timer_struct *timer; 00220 platform_enter_critical(); 00221 00222 /*Find timer to be activated*/ 00223 timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); 00224 if (!timer) { 00225 ret_val = -1; 00226 goto exit; 00227 } 00228 00229 // XXX this assumes the timer currently isn't running? 00230 // Is event.c relying on this restarting HAL timer after ns_timer_sleep()? 00231 00232 /*If any timers are active*/ 00233 if (ns_timer_state & NS_TIMER_RUNNING) { 00234 /*Get remaining slots of the currently activated timeout*/ 00235 pl_timer_remaining_slots = platform_timer_get_remaining_slots(); 00236 00237 /*New timeout is shorter than currently enabled timeout*/ 00238 if (pl_timer_remaining_slots > slots) { 00239 /*Start HAL timer*/ 00240 ns_timer_start_pl_timer(slots - 0); 00241 00242 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00243 /*Switch active timers to hold*/ 00244 if (current_timer->timer_state == NS_TIMER_ACTIVE) { 00245 current_timer->timer_state = NS_TIMER_HOLD; 00246 current_timer->remaining_slots = 0; 00247 } 00248 /*Update hold-labelled timers*/ 00249 if (current_timer->timer_state == NS_TIMER_HOLD) { 00250 current_timer->remaining_slots += (pl_timer_remaining_slots - slots); 00251 /*Compensate time spent in timer function*/ 00252 if (current_timer->remaining_slots > (COMPENSATION - COMPENSATION_TUNE)) { 00253 current_timer->remaining_slots -= (COMPENSATION - COMPENSATION_TUNE); 00254 } 00255 } 00256 } 00257 /*Mark active and start the timer*/ 00258 timer->timer_state = NS_TIMER_ACTIVE; 00259 timer->slots = slots; 00260 timer->remaining_slots = slots; 00261 } 00262 00263 /*New timeout is longer than currently enabled timeout*/ 00264 else if (pl_timer_remaining_slots < slots) { 00265 /*Mark hold and update remaining slots*/ 00266 timer->timer_state = NS_TIMER_HOLD; 00267 timer->slots = slots; 00268 timer->remaining_slots = (slots - pl_timer_remaining_slots); 00269 } 00270 /*New timeout is equal to currently enabled timeout*/ 00271 else { 00272 /*Mark it active and it will be handled in next interrupt*/ 00273 timer->timer_state = NS_TIMER_ACTIVE; 00274 timer->slots = slots; 00275 timer->remaining_slots = slots; 00276 } 00277 } else { 00278 /*No timers running*/ 00279 timer->timer_state = NS_TIMER_HOLD; 00280 timer->slots = slots; 00281 timer->remaining_slots = slots; 00282 /*Start next timeout*/ 00283 ns_timer_get_next_running_to(); 00284 } 00285 exit: 00286 platform_exit_critical(); 00287 return ret_val; 00288 } 00289 00290 static void ns_timer_interrupt_handler(void) 00291 { 00292 uint8_t i = 0; 00293 00294 platform_enter_critical(); 00295 /*Clear timer running state*/ 00296 ns_timer_state &= ~NS_TIMER_RUNNING; 00297 /*Mark active timers as NS_TIMER_RUN_INTERRUPT, interrupt functions are called at the end of this function*/ 00298 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00299 if (current_timer->timer_state == NS_TIMER_ACTIVE) { 00300 current_timer->timer_state = NS_TIMER_RUN_INTERRUPT; 00301 /*For optimisation, count the found timers*/ 00302 i++; 00303 } 00304 } 00305 00306 /*Start next timeout*/ 00307 ns_timer_get_next_running_to(); 00308 00309 /*Call interrupt functions*/ 00310 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00311 if (i == 0) { 00312 break; 00313 } 00314 if (current_timer->timer_state == NS_TIMER_RUN_INTERRUPT) { 00315 current_timer->timer_state = NS_TIMER_STOP; 00316 current_timer->interrupt_handler(current_timer->ns_timer_id, current_timer->slots); 00317 i--; 00318 } 00319 } 00320 00321 platform_exit_critical(); 00322 } 00323 00324 int8_t eventOS_callback_timer_stop(int8_t ns_timer_id) 00325 { 00326 uint16_t pl_timer_remaining_slots; 00327 bool active_timer_found = false; 00328 ns_timer_struct *current_timer; 00329 ns_timer_struct *first_timer = NULL; 00330 int8_t retval = -1; 00331 00332 platform_enter_critical(); 00333 /*Find timer with given timer ID*/ 00334 current_timer = ns_timer_get_pointer_to_timer_struct(ns_timer_id); 00335 if (!current_timer) { 00336 goto exit; 00337 } 00338 00339 retval = 0; 00340 00341 /*Check if already stopped*/ 00342 if (current_timer->timer_state == NS_TIMER_STOP) { 00343 goto exit; 00344 } 00345 00346 current_timer->timer_state = NS_TIMER_STOP; 00347 current_timer->remaining_slots = 0; 00348 00349 /*Check if some timer is already active*/ 00350 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00351 if (current_timer->timer_state == NS_TIMER_ACTIVE) { 00352 active_timer_found = true; 00353 break; 00354 } 00355 } 00356 /*If no active timers found, start one*/ 00357 if (!active_timer_found) { 00358 pl_timer_remaining_slots = platform_timer_get_remaining_slots(); 00359 /*Find hold-labelled timer with the least remaining slots*/ 00360 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00361 if (current_timer->timer_state == NS_TIMER_HOLD) { 00362 current_timer->remaining_slots += pl_timer_remaining_slots; 00363 00364 if (!first_timer || current_timer->remaining_slots < first_timer->remaining_slots) { 00365 first_timer = current_timer; 00366 } 00367 } 00368 } 00369 /*If hold-labelled timer found, set it active and start the HAL driver*/ 00370 if (first_timer) { 00371 first_timer->timer_state = NS_TIMER_ACTIVE; 00372 /*Start HAL timer*/ 00373 ns_timer_start_pl_timer(first_timer->remaining_slots); 00374 /*If some of the other hold-labelled timers have the same remaining slots as the timer_tmp, mark them active*/ 00375 ns_list_foreach(ns_timer_struct, current_timer, &ns_timer_list) { 00376 if (current_timer->timer_state == NS_TIMER_HOLD) { 00377 if (current_timer->remaining_slots == first_timer->remaining_slots) { 00378 current_timer->timer_state = NS_TIMER_ACTIVE; 00379 } else { 00380 current_timer->remaining_slots -= first_timer->remaining_slots; 00381 } 00382 } 00383 } 00384 } 00385 } 00386 00387 exit: 00388 platform_exit_critical(); 00389 00390 return retval; 00391 } 00392 #endif // NS_EXCLUDE_HIGHRES_TIMER
Generated on Tue Jul 12 2022 11:02:48 by
