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