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.
Fork of BLE_RCBController by
app_timer.cpp
00001 /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. 00002 * 00003 * The information contained herein is property of Nordic Semiconductor ASA. 00004 * Terms and conditions of usage are described in detail in NORDIC 00005 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 00006 * 00007 * Licensees are granted free, non-transferable use of the information. NO 00008 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 00009 * the file. 00010 * 00011 */ 00012 00013 #include "app_timer.h " 00014 #include <stdlib.h> 00015 #include "nrf51.h" 00016 #include "nrf51_bitfields.h" 00017 #include "nrf_soc.h" 00018 #include "app_error.h " 00019 //#include "nrf_delay.h" 00020 #include "mbed.h" 00021 #include "app_util.h " 00022 #include "app_util_platform.h " 00023 00024 00025 #define RTC1_IRQ_PRI APP_IRQ_PRIORITY_LOW /**< Priority of the RTC1 interrupt (used for checking for timeouts and executing timeout handlers). */ 00026 #define SWI0_IRQ_PRI APP_IRQ_PRIORITY_LOW /**< Priority of the SWI0 interrupt (used for updating the timer list). */ 00027 00028 // The current design assumes that both interrupt handlers run at the same interrupt level. 00029 // If this is to be changed, protection must be added to prevent them from interrupting each other 00030 // (e.g. by using guard/trigger flags). 00031 STATIC_ASSERT(RTC1_IRQ_PRI == SWI0_IRQ_PRI); 00032 00033 #define MAX_RTC_COUNTER_VAL 0x00FFFFFF /**< Maximum value of the RTC counter. */ 00034 00035 #define APP_HIGH_USER_ID 0 /**< User Id for the Application High "user". */ 00036 #define APP_LOW_USER_ID 1 /**< User Id for the Application Low "user". */ 00037 #define THREAD_MODE_USER_ID 2 /**< User Id for the Thread Mode "user". */ 00038 00039 #define RTC_COMPARE_OFFSET_MIN 3 /**< Minimum offset between the current RTC counter value and the Capture Compare register. Although the nRF51 Series User Specification recommends this value to be 2, we use 3 to be safer.*/ 00040 00041 #define MAX_RTC_TASKS_DELAY 47 /**< Maximum delay until an RTC task is executed. */ 00042 00043 /**@brief Timer allocation state type. */ 00044 typedef enum 00045 { 00046 STATE_FREE, /**< The timer node is available. */ 00047 STATE_ALLOCATED /**< The timer node has been allocated. */ 00048 } timer_alloc_state_t; 00049 00050 /**@brief Timer node type. The nodes will be used form a linked list of running timers. */ 00051 typedef struct 00052 { 00053 timer_alloc_state_t state; /**< Timer allocation state. */ 00054 app_timer_mode_t mode; /**< Timer mode. */ 00055 uint32_t ticks_to_expire; /**< Number of ticks from previous timer interrupt to timer expiry. */ 00056 uint32_t ticks_at_start; /**< Current RTC counter value when the timer was started. */ 00057 uint32_t ticks_first_interval; /**< Number of ticks in the first timer interval. */ 00058 uint32_t ticks_periodic_interval; /**< Timer period (for repeating timers). */ 00059 bool is_running; /**< True if timer is running, False otherwise. */ 00060 app_timer_timeout_handler_t p_timeout_handler; /**< Pointer to function to be executed when the timer expires. */ 00061 void * p_context; /**< General purpose pointer. Will be passed to the timeout handler when the timer expires. */ 00062 app_timer_id_t next; /**< Id of next timer in list of running timers. */ 00063 } timer_node_t; 00064 00065 STATIC_ASSERT(sizeof(timer_node_t) <= APP_TIMER_NODE_SIZE); 00066 STATIC_ASSERT(sizeof(timer_node_t) % 4 == 0); 00067 00068 /**@brief Set of available timer operation types. */ 00069 typedef enum 00070 { 00071 TIMER_USER_OP_TYPE_NONE, /**< Invalid timer operation type. */ 00072 TIMER_USER_OP_TYPE_START, /**< Timer operation type Start. */ 00073 TIMER_USER_OP_TYPE_STOP, /**< Timer operation type Stop. */ 00074 TIMER_USER_OP_TYPE_STOP_ALL /**< Timer operation type Stop All. */ 00075 } timer_user_op_type_t; 00076 00077 /**@brief Structure describing a timer start operation. */ 00078 typedef struct 00079 { 00080 uint32_t ticks_at_start; /**< Current RTC counter value when the timer was started. */ 00081 uint32_t ticks_first_interval; /**< Number of ticks in the first timer interval. */ 00082 uint32_t ticks_periodic_interval; /**< Timer period (for repeating timers). */ 00083 void * p_context; /**< General purpose pointer. Will be passed to the timeout handler when the timer expires. */ 00084 } timer_user_op_start_t; 00085 00086 /**@brief Structure describing a timer operation. */ 00087 typedef struct 00088 { 00089 timer_user_op_type_t op_type; /**< Timer operation type. */ 00090 app_timer_id_t timer_id; /**< Id of timer on which the operation is to be performed. */ 00091 union 00092 { 00093 timer_user_op_start_t start; /**< Structure describing a timer start operation. */ 00094 } params; 00095 } timer_user_op_t; 00096 00097 STATIC_ASSERT(sizeof(timer_user_op_t) <= APP_TIMER_USER_OP_SIZE); 00098 STATIC_ASSERT(sizeof(timer_user_op_t) % 4 == 0); 00099 00100 /**@brief Structure describing a timer user. 00101 * 00102 * @details For each user of the timer module, there will be a timer operations queue. This queue 00103 * will hold timer operations issued by this user until the timer interrupt handler 00104 * processes these operations. For the current implementation, there will be one user for 00105 * each interrupt level available to the application (APP_HIGH, APP_LOW and THREAD_MODE), 00106 * but the module can easily be modified to e.g. have one queue per process when using an 00107 * RTOS. The purpose of the queues is to be able to have a completely lockless timer 00108 * implementation. 00109 */ 00110 typedef struct 00111 { 00112 uint8_t first; /**< Index of first entry to have been inserted in the queue (i.e. the next entry to be executed). */ 00113 uint8_t last; /**< Index of last entry to have been inserted in the queue. */ 00114 uint8_t user_op_queue_size; /**< Queue size. */ 00115 timer_user_op_t * p_user_op_queue; /**< Queue buffer. */ 00116 } timer_user_t; 00117 00118 STATIC_ASSERT(sizeof(timer_user_t) == APP_TIMER_USER_SIZE); 00119 STATIC_ASSERT(sizeof(timer_user_t) % 4 == 0); 00120 00121 /**@brief User id type. 00122 * 00123 * @details In the current implementation, this will automatically be generated from the current 00124 * interrupt level. 00125 */ 00126 typedef uint32_t timer_user_id_t; 00127 00128 #define TIMER_NULL ((app_timer_id_t)(0 - 1)) /**< Invalid timer id. */ 00129 #define CONTEXT_QUEUE_SIZE_MAX (2) /**< Timer internal elapsed ticks queue size. */ 00130 00131 static uint8_t m_node_array_size; /**< Size of timer node array. */ 00132 static timer_node_t * mp_nodes = NULL; /**< Array of timer nodes. */ 00133 static uint8_t m_user_array_size; /**< Size of timer user array. */ 00134 static timer_user_t * mp_users; /**< Array of timer users. */ 00135 static app_timer_id_t m_timer_id_head; /**< First timer in list of running timers. */ 00136 static uint32_t m_ticks_latest; /**< Last known RTC counter value. */ 00137 static uint32_t m_ticks_elapsed[CONTEXT_QUEUE_SIZE_MAX]; /**< Timer internal elapsed ticks queue. */ 00138 static uint8_t m_ticks_elapsed_q_read_ind; /**< Timer internal elapsed ticks queue read index. */ 00139 static uint8_t m_ticks_elapsed_q_write_ind; /**< Timer internal elapsed ticks queue write index. */ 00140 static app_timer_evt_schedule_func_t m_evt_schedule_func; /**< Pointer to function for propagating timeout events to the scheduler. */ 00141 00142 00143 /**@brief Function for initializing the RTC1 counter. 00144 * 00145 * @param[in] prescaler Value of the RTC1 PRESCALER register. Set to 0 for no prescaling. 00146 */ 00147 static void rtc1_init(uint32_t prescaler) 00148 { 00149 NRF_RTC1->PRESCALER = prescaler; 00150 NVIC_SetPriority(RTC1_IRQn, RTC1_IRQ_PRI); 00151 } 00152 00153 00154 /**@brief Function for starting the RTC1 timer. 00155 */ 00156 static void rtc1_start(void) 00157 { 00158 NRF_RTC1->EVTENSET = RTC_EVTEN_COMPARE0_Msk; 00159 NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk; 00160 00161 NVIC_ClearPendingIRQ(RTC1_IRQn); 00162 NVIC_EnableIRQ(RTC1_IRQn); 00163 00164 NRF_RTC1->TASKS_START = 1; 00165 wait(0.0000001 * MAX_RTC_TASKS_DELAY); 00166 } 00167 00168 00169 /**@brief Function for stopping the RTC1 timer. 00170 */ 00171 static void rtc1_stop(void) 00172 { 00173 NVIC_DisableIRQ(RTC1_IRQn); 00174 00175 NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk; 00176 NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk; 00177 00178 NRF_RTC1->TASKS_STOP = 1; 00179 wait(0.0000001 * MAX_RTC_TASKS_DELAY); 00180 } 00181 00182 00183 /**@brief Function for returning the current value of the RTC1 counter. 00184 * 00185 * @return Current value of the RTC1 counter. 00186 */ 00187 static __INLINE uint32_t rtc1_counter_get(void) 00188 { 00189 return NRF_RTC1->COUNTER; 00190 } 00191 00192 00193 /**@brief Function for computing the difference between two RTC1 counter values. 00194 * 00195 * @return Number of ticks elapsed from ticks_old to ticks_now. 00196 */ 00197 static __INLINE uint32_t ticks_diff_get(uint32_t ticks_now, uint32_t ticks_old) 00198 { 00199 return ((ticks_now - ticks_old) & MAX_RTC_COUNTER_VAL); 00200 } 00201 00202 00203 /**@brief Function for setting the RTC1 Capture Compare register 0, and enabling the corresponding 00204 * event. 00205 * 00206 * @param[in] value New value of Capture Compare register 0. 00207 */ 00208 static __INLINE void rtc1_compare0_set(uint32_t value) 00209 { 00210 NRF_RTC1->CC[0] = value; 00211 } 00212 00213 00214 /**@brief Function for inserting a timer in the timer list. 00215 * 00216 * @param[in] timer_id Id of timer to insert. 00217 */ 00218 static void timer_list_insert(app_timer_id_t timer_id) 00219 { 00220 timer_node_t * p_timer = &mp_nodes[timer_id]; 00221 00222 if (m_timer_id_head == TIMER_NULL) 00223 { 00224 m_timer_id_head = timer_id; 00225 } 00226 else 00227 { 00228 if (p_timer->ticks_to_expire <= mp_nodes[m_timer_id_head].ticks_to_expire) 00229 { 00230 mp_nodes[m_timer_id_head].ticks_to_expire -= p_timer->ticks_to_expire; 00231 00232 p_timer->next = m_timer_id_head; 00233 m_timer_id_head = timer_id; 00234 } 00235 else 00236 { 00237 app_timer_id_t previous; 00238 app_timer_id_t current; 00239 uint32_t ticks_to_expire; 00240 00241 ticks_to_expire = p_timer->ticks_to_expire; 00242 previous = m_timer_id_head; 00243 current = m_timer_id_head; 00244 00245 while ((current != TIMER_NULL) && (ticks_to_expire > mp_nodes[current].ticks_to_expire)) 00246 { 00247 ticks_to_expire -= mp_nodes[current].ticks_to_expire; 00248 previous = current; 00249 current = mp_nodes[current].next; 00250 } 00251 00252 if (current != TIMER_NULL) 00253 { 00254 mp_nodes[current].ticks_to_expire -= ticks_to_expire; 00255 } 00256 00257 p_timer->ticks_to_expire = ticks_to_expire; 00258 p_timer->next = current; 00259 mp_nodes[previous].next = timer_id; 00260 } 00261 } 00262 } 00263 00264 00265 /**@brief Function for removing a timer from the timer queue. 00266 * 00267 * @param[in] timer_id Id of timer to remove. 00268 */ 00269 static void timer_list_remove(app_timer_id_t timer_id) 00270 { 00271 app_timer_id_t previous; 00272 app_timer_id_t current; 00273 uint32_t timeout; 00274 00275 // Find the timer's position in timer list 00276 previous = m_timer_id_head; 00277 current = previous; 00278 00279 while (current != TIMER_NULL) 00280 { 00281 if (current == timer_id) 00282 { 00283 break; 00284 } 00285 previous = current; 00286 current = mp_nodes[current].next; 00287 } 00288 00289 // Timer not in active list 00290 if (current == TIMER_NULL) 00291 { 00292 return; 00293 } 00294 00295 // Timer is the first in the list 00296 if (previous == current) 00297 { 00298 m_timer_id_head = mp_nodes[m_timer_id_head].next; 00299 } 00300 00301 // Remaining timeout between next timeout 00302 timeout = mp_nodes[current].ticks_to_expire; 00303 00304 // Link previous timer with next of this timer, i.e. removing the timer from list 00305 mp_nodes[previous].next = mp_nodes[current].next; 00306 00307 // If this is not the last timer, increment the next timer by this timer timeout 00308 current = mp_nodes[previous].next; 00309 if (current != TIMER_NULL) 00310 { 00311 mp_nodes[current].ticks_to_expire += timeout; 00312 } 00313 } 00314 00315 00316 /**@brief Function for scheduling a check for timeouts by generating a RTC1 interrupt. 00317 */ 00318 static void timer_timeouts_check_sched(void) 00319 { 00320 NVIC_SetPendingIRQ(RTC1_IRQn); 00321 } 00322 00323 00324 /**@brief Function for scheduling a timer list update by generating a SWI0 interrupt. 00325 */ 00326 static void timer_list_handler_sched(void) 00327 { 00328 NVIC_SetPendingIRQ(SWI0_IRQn); 00329 } 00330 00331 00332 /**@brief Function for executing an application timeout handler, either by calling it directly, or 00333 * by passing an event to the @ref app_scheduler. 00334 * 00335 * @param[in] p_timer Pointer to expired timer. 00336 */ 00337 static void timeout_handler_exec(timer_node_t * p_timer) 00338 { 00339 if (m_evt_schedule_func != NULL) 00340 { 00341 uint32_t err_code = m_evt_schedule_func(p_timer->p_timeout_handler, p_timer->p_context); 00342 APP_ERROR_CHECK(err_code); 00343 } 00344 else 00345 { 00346 p_timer->p_timeout_handler(p_timer->p_context); 00347 } 00348 } 00349 00350 00351 /**@brief Function for checking for expired timers. 00352 */ 00353 static void timer_timeouts_check(void) 00354 { 00355 // Handle expired of timer 00356 if (m_timer_id_head != TIMER_NULL) 00357 { 00358 app_timer_id_t timer_id; 00359 uint32_t ticks_elapsed; 00360 uint32_t ticks_expired; 00361 00362 // Initialize actual elapsed ticks being consumed to 0 00363 ticks_expired = 0; 00364 00365 // ticks_elapsed is collected here, job will use it 00366 ticks_elapsed = ticks_diff_get(rtc1_counter_get(), m_ticks_latest); 00367 00368 // Auto variable containing the head of timers expiring 00369 timer_id = m_timer_id_head; 00370 00371 // Expire all timers within ticks_elapsed and collect ticks_expired 00372 while (timer_id != TIMER_NULL) 00373 { 00374 timer_node_t * p_timer; 00375 00376 // Auto variable for current timer node 00377 p_timer = &mp_nodes[timer_id]; 00378 00379 // Do nothing if timer did not expire 00380 if (ticks_elapsed < p_timer->ticks_to_expire) 00381 { 00382 break; 00383 } 00384 00385 // Decrement ticks_elapsed and collect expired ticks 00386 ticks_elapsed -= p_timer->ticks_to_expire; 00387 ticks_expired += p_timer->ticks_to_expire; 00388 00389 // Move to next timer 00390 timer_id = p_timer->next; 00391 00392 // Execute Task 00393 timeout_handler_exec(p_timer); 00394 } 00395 00396 // Prepare to queue the ticks expired in the m_ticks_elapsed queue. 00397 if (m_ticks_elapsed_q_read_ind == m_ticks_elapsed_q_write_ind) 00398 { 00399 // The read index of the queue is equal to the write index. This means the new 00400 // value of ticks_expired should be stored at a new location in the m_ticks_elapsed 00401 // queue (which is implemented as a double buffer). 00402 00403 // Check if there will be a queue overflow. 00404 if (++m_ticks_elapsed_q_write_ind == CONTEXT_QUEUE_SIZE_MAX) 00405 { 00406 // There will be a queue overflow. Hence the write index should point to the start 00407 // of the queue. 00408 m_ticks_elapsed_q_write_ind = 0; 00409 } 00410 } 00411 00412 // Queue the ticks expired. 00413 m_ticks_elapsed[m_ticks_elapsed_q_write_ind] = ticks_expired; 00414 00415 timer_list_handler_sched(); 00416 } 00417 } 00418 00419 00420 /**@brief Function for acquiring the number of ticks elapsed. 00421 * 00422 * @param[out] p_ticks_elapsed Number of ticks elapsed. 00423 * 00424 * @return TRUE if elapsed ticks was read from queue, FALSE otherwise. 00425 */ 00426 static bool elapsed_ticks_acquire(uint32_t * p_ticks_elapsed) 00427 { 00428 // Pick the elapsed value from queue 00429 if (m_ticks_elapsed_q_read_ind != m_ticks_elapsed_q_write_ind) 00430 { 00431 // Dequeue elapsed value 00432 m_ticks_elapsed_q_read_ind++; 00433 if (m_ticks_elapsed_q_read_ind == CONTEXT_QUEUE_SIZE_MAX) 00434 { 00435 m_ticks_elapsed_q_read_ind = 0; 00436 } 00437 00438 *p_ticks_elapsed = m_ticks_elapsed[m_ticks_elapsed_q_read_ind]; 00439 00440 m_ticks_latest += *p_ticks_elapsed; 00441 m_ticks_latest &= MAX_RTC_COUNTER_VAL; 00442 00443 return true; 00444 } 00445 else 00446 { 00447 // No elapsed value in queue 00448 *p_ticks_elapsed = 0; 00449 return false; 00450 } 00451 } 00452 00453 00454 /**@brief Function for handling the timer list deletions. 00455 * 00456 * @return TRUE if Capture Compare register must be updated, FALSE otherwise. 00457 */ 00458 static bool list_deletions_handler(void) 00459 { 00460 app_timer_id_t timer_id_old_head; 00461 uint8_t user_id; 00462 00463 // Remember the old head, so as to decide if new compare needs to be set 00464 timer_id_old_head = m_timer_id_head; 00465 00466 user_id = m_user_array_size; 00467 while (user_id--) 00468 { 00469 timer_user_t * p_user = &mp_users[user_id]; 00470 uint8_t user_ops_first = p_user->first; 00471 00472 while (user_ops_first != p_user->last) 00473 { 00474 timer_node_t * p_timer; 00475 timer_user_op_t * p_user_op = &p_user->p_user_op_queue[user_ops_first]; 00476 00477 // Traverse to next operation in queue 00478 user_ops_first++; 00479 if (user_ops_first == p_user->user_op_queue_size) 00480 { 00481 user_ops_first = 0; 00482 } 00483 00484 switch (p_user_op->op_type) 00485 { 00486 case TIMER_USER_OP_TYPE_STOP: 00487 // Delete node if timer is running 00488 p_timer = &mp_nodes[p_user_op->timer_id]; 00489 if (p_timer->is_running) 00490 { 00491 timer_list_remove(p_user_op->timer_id); 00492 p_timer->is_running = false; 00493 } 00494 break; 00495 00496 case TIMER_USER_OP_TYPE_STOP_ALL: 00497 // Delete list of running timers, and mark all timers as not running 00498 while (m_timer_id_head != TIMER_NULL) 00499 { 00500 timer_node_t * p_head = &mp_nodes[m_timer_id_head]; 00501 00502 p_head->is_running = false; 00503 m_timer_id_head = p_head->next; 00504 } 00505 break; 00506 00507 default: 00508 // No implementation needed. 00509 break; 00510 } 00511 } 00512 } 00513 00514 // Detect change in head of the list 00515 return (m_timer_id_head != timer_id_old_head); 00516 } 00517 00518 00519 /**@brief Function for updating the timer list for expired timers. 00520 * 00521 * @param[in] ticks_elapsed Number of elapsed ticks. 00522 * @param[in] ticks_previous Previous known value of the RTC counter. 00523 * @param[out] p_restart_list_head List of repeating timers to be restarted. 00524 */ 00525 static void expired_timers_handler(uint32_t ticks_elapsed, 00526 uint32_t ticks_previous, 00527 app_timer_id_t * p_restart_list_head) 00528 { 00529 uint32_t ticks_expired = 0; 00530 00531 while (m_timer_id_head != TIMER_NULL) 00532 { 00533 timer_node_t * p_timer; 00534 app_timer_id_t id_expired; 00535 00536 // Auto variable for current timer node 00537 p_timer = &mp_nodes[m_timer_id_head]; 00538 00539 // Do nothing if timer did not expire 00540 if (ticks_elapsed < p_timer->ticks_to_expire) 00541 { 00542 p_timer->ticks_to_expire -= ticks_elapsed; 00543 break; 00544 } 00545 00546 // Decrement ticks_elapsed and collect expired ticks 00547 ticks_elapsed -= p_timer->ticks_to_expire; 00548 ticks_expired += p_timer->ticks_to_expire; 00549 00550 // Timer expired, set ticks_to_expire zero 00551 p_timer->ticks_to_expire = 0; 00552 p_timer->is_running = false; 00553 00554 // Remove the expired timer from head 00555 id_expired = m_timer_id_head; 00556 m_timer_id_head = p_timer->next; 00557 00558 // Timer will be restarted if periodic 00559 if (p_timer->ticks_periodic_interval != 0) 00560 { 00561 p_timer->ticks_at_start = (ticks_previous + ticks_expired) & MAX_RTC_COUNTER_VAL; 00562 p_timer->ticks_first_interval = p_timer->ticks_periodic_interval; 00563 p_timer->next = *p_restart_list_head; 00564 *p_restart_list_head = id_expired; 00565 } 00566 } 00567 } 00568 00569 00570 /**@brief Function for handling timer list insertions. 00571 * 00572 * @param[in] p_restart_list_head List of repeating timers to be restarted. 00573 * 00574 * @return TRUE if Capture Compare register must be updated, FALSE otherwise. 00575 */ 00576 static bool list_insertions_handler(app_timer_id_t restart_list_head) 00577 { 00578 app_timer_id_t timer_id_old_head; 00579 uint8_t user_id; 00580 00581 // Remember the old head, so as to decide if new compare needs to be set 00582 timer_id_old_head = m_timer_id_head; 00583 00584 user_id = m_user_array_size; 00585 while (user_id--) 00586 { 00587 timer_user_t * p_user = &mp_users[user_id]; 00588 00589 // Handle insertions of timers 00590 while ((restart_list_head != TIMER_NULL) || (p_user->first != p_user->last)) 00591 { 00592 app_timer_id_t id_start; 00593 timer_node_t * p_timer; 00594 00595 if (restart_list_head != TIMER_NULL) 00596 { 00597 id_start = restart_list_head; 00598 p_timer = &mp_nodes[id_start]; 00599 restart_list_head = p_timer->next; 00600 } 00601 else 00602 { 00603 timer_user_op_t * p_user_op = &p_user->p_user_op_queue[p_user->first]; 00604 00605 p_user->first++; 00606 if (p_user->first == p_user->user_op_queue_size) 00607 { 00608 p_user->first = 0; 00609 } 00610 00611 id_start = p_user_op->timer_id; 00612 p_timer = &mp_nodes[id_start]; 00613 00614 if ((p_user_op->op_type != TIMER_USER_OP_TYPE_START) || p_timer->is_running) 00615 { 00616 continue; 00617 } 00618 00619 p_timer->ticks_at_start = p_user_op->params.start.ticks_at_start; 00620 p_timer->ticks_first_interval = p_user_op->params.start.ticks_first_interval; 00621 p_timer->ticks_periodic_interval = p_user_op->params.start.ticks_periodic_interval; 00622 p_timer->p_context = p_user_op->params.start.p_context; 00623 } 00624 00625 // Prepare the node to be inserted 00626 if ( 00627 ((p_timer->ticks_at_start - m_ticks_latest) & MAX_RTC_COUNTER_VAL) 00628 < 00629 (MAX_RTC_COUNTER_VAL / 2) 00630 ) 00631 { 00632 p_timer->ticks_to_expire = ticks_diff_get(p_timer->ticks_at_start, m_ticks_latest) + 00633 p_timer->ticks_first_interval; 00634 } 00635 else 00636 { 00637 uint32_t delta_current_start; 00638 00639 delta_current_start = ticks_diff_get(m_ticks_latest, p_timer->ticks_at_start); 00640 if (p_timer->ticks_first_interval > delta_current_start) 00641 { 00642 p_timer->ticks_to_expire = p_timer->ticks_first_interval - delta_current_start; 00643 } 00644 else 00645 { 00646 p_timer->ticks_to_expire = 0; 00647 } 00648 } 00649 00650 p_timer->ticks_at_start = 0; 00651 p_timer->ticks_first_interval = 0; 00652 p_timer->is_running = true; 00653 p_timer->next = TIMER_NULL; 00654 00655 // Insert into list 00656 timer_list_insert(id_start); 00657 } 00658 } 00659 00660 return (m_timer_id_head != timer_id_old_head); 00661 } 00662 00663 00664 /**@brief Function for updating the Capture Compare register. 00665 */ 00666 static void compare_reg_update(app_timer_id_t timer_id_head_old) 00667 { 00668 // Setup the timeout for timers on the head of the list 00669 if (m_timer_id_head != TIMER_NULL) 00670 { 00671 uint32_t ticks_to_expire = mp_nodes[m_timer_id_head].ticks_to_expire; 00672 uint32_t pre_counter_val = rtc1_counter_get(); 00673 uint32_t cc = m_ticks_latest; 00674 uint32_t ticks_elapsed = ticks_diff_get(pre_counter_val, cc) + RTC_COMPARE_OFFSET_MIN; 00675 00676 if (timer_id_head_old == TIMER_NULL) 00677 { 00678 // No timers were already running, start RTC 00679 rtc1_start(); 00680 } 00681 00682 cc += (ticks_elapsed < ticks_to_expire) ? ticks_to_expire : ticks_elapsed; 00683 cc &= MAX_RTC_COUNTER_VAL; 00684 00685 rtc1_compare0_set(cc); 00686 00687 uint32_t post_counter_val = rtc1_counter_get(); 00688 00689 if ( 00690 (ticks_diff_get(post_counter_val, pre_counter_val) + RTC_COMPARE_OFFSET_MIN) 00691 > 00692 ticks_diff_get(cc, pre_counter_val) 00693 ) 00694 { 00695 // When this happens the COMPARE event may not be triggered by the RTC. 00696 // The nRF51 Series User Specification states that if the COUNTER value is N 00697 // (i.e post_counter_val = N), writing N or N+1 to a CC register may not trigger a 00698 // COMPARE event. Hence the RTC interrupt is forcefully pended by calling the following 00699 // function. 00700 timer_timeouts_check_sched(); 00701 } 00702 } 00703 else 00704 { 00705 // No timers are running, stop RTC 00706 rtc1_stop(); 00707 } 00708 } 00709 00710 00711 /**@brief Function for handling changes to the timer list. 00712 */ 00713 static void timer_list_handler(void) 00714 { 00715 app_timer_id_t restart_list_head = TIMER_NULL; 00716 uint32_t ticks_elapsed; 00717 uint32_t ticks_previous; 00718 bool ticks_have_elapsed; 00719 bool compare_update; 00720 app_timer_id_t timer_id_head_old; 00721 00722 // Back up the previous known tick and previous list head 00723 ticks_previous = m_ticks_latest; 00724 timer_id_head_old = m_timer_id_head; 00725 00726 // Get number of elapsed ticks 00727 ticks_have_elapsed = elapsed_ticks_acquire(&ticks_elapsed); 00728 00729 // Handle list deletions 00730 compare_update = list_deletions_handler(); 00731 00732 // Handle expired timers 00733 if (ticks_have_elapsed) 00734 { 00735 expired_timers_handler(ticks_elapsed, ticks_previous, &restart_list_head); 00736 compare_update = true; 00737 } 00738 00739 // Handle list insertions 00740 if (list_insertions_handler(restart_list_head)) 00741 { 00742 compare_update = true; 00743 } 00744 00745 // Update compare register if necessary 00746 if (compare_update) 00747 { 00748 compare_reg_update(timer_id_head_old); 00749 } 00750 } 00751 00752 00753 /**@brief Function for enqueueing a new operations queue entry. 00754 * 00755 * @param[in] p_user User that the entry is to be enqueued for. 00756 * @param[in] last_index Index of the next last index to be enqueued. 00757 */ 00758 static void user_op_enque(timer_user_t * p_user, app_timer_id_t last_index) 00759 { 00760 p_user->last = last_index; 00761 } 00762 00763 00764 /**@brief Function for allocating a new operations queue entry. 00765 * 00766 * @param[in] p_user User that the entry is to be allocated for. 00767 * @param[out] p_last_index Index of the next last index to be enqueued. 00768 * 00769 * @return Pointer to allocated queue entry, or NULL if queue is full. 00770 */ 00771 static timer_user_op_t * user_op_alloc(timer_user_t * p_user, app_timer_id_t * p_last_index) 00772 { 00773 app_timer_id_t last; 00774 timer_user_op_t * p_user_op; 00775 00776 last = p_user->last + 1; 00777 if (last == p_user->user_op_queue_size) 00778 { 00779 // Overflow case. 00780 last = 0; 00781 } 00782 if (last == p_user->first) 00783 { 00784 // Queue is full. 00785 return NULL; 00786 } 00787 00788 *p_last_index = last; 00789 p_user_op = &p_user->p_user_op_queue[p_user->last]; 00790 00791 return p_user_op; 00792 } 00793 00794 00795 /**@brief Function for scheduling a Timer Start operation. 00796 * 00797 * @param[in] user_id Id of user calling this function. 00798 * @param[in] timer_id Id of timer to start. 00799 * @param[in] timeout_initial Time (in ticks) to first timer expiry. 00800 * @param[in] timeout_periodic Time (in ticks) between periodic expiries. 00801 * @param[in] p_context General purpose pointer. Will be passed to the timeout handler when 00802 * the timer expires. 00803 * @return NRF_SUCCESS on success, otherwise an error code. 00804 */ 00805 static uint32_t timer_start_op_schedule(timer_user_id_t user_id, 00806 app_timer_id_t timer_id, 00807 uint32_t timeout_initial, 00808 uint32_t timeout_periodic, 00809 void * p_context) 00810 { 00811 app_timer_id_t last_index; 00812 00813 timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index); 00814 if (p_user_op == NULL) 00815 { 00816 return NRF_ERROR_NO_MEM; 00817 } 00818 00819 p_user_op->op_type = TIMER_USER_OP_TYPE_START; 00820 p_user_op->timer_id = timer_id; 00821 p_user_op->params.start.ticks_at_start = rtc1_counter_get(); 00822 p_user_op->params.start.ticks_first_interval = timeout_initial; 00823 p_user_op->params.start.ticks_periodic_interval = timeout_periodic; 00824 p_user_op->params.start.p_context = p_context; 00825 00826 user_op_enque(&mp_users[user_id], last_index); 00827 00828 timer_list_handler_sched(); 00829 00830 return NRF_SUCCESS; 00831 } 00832 00833 00834 /**@brief Function for scheduling a Timer Stop operation. 00835 * 00836 * @param[in] user_id Id of user calling this function. 00837 * @param[in] timer_id Id of timer to stop. 00838 * 00839 * @return NRF_SUCCESS on successful scheduling a timer stop operation. NRF_ERROR_NO_MEM when there 00840 * is no memory left to schedule the timer stop operation. 00841 */ 00842 static uint32_t timer_stop_op_schedule(timer_user_id_t user_id, app_timer_id_t timer_id) 00843 { 00844 app_timer_id_t last_index; 00845 00846 timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index); 00847 if (p_user_op == NULL) 00848 { 00849 return NRF_ERROR_NO_MEM; 00850 } 00851 00852 p_user_op->op_type = TIMER_USER_OP_TYPE_STOP; 00853 p_user_op->timer_id = timer_id; 00854 00855 user_op_enque(&mp_users[user_id], last_index); 00856 00857 timer_list_handler_sched(); 00858 00859 return NRF_SUCCESS; 00860 } 00861 00862 00863 /**@brief Function for scheduling a Timer Stop All operation. 00864 * 00865 * @param[in] user_id Id of user calling this function. 00866 */ 00867 static uint32_t timer_stop_all_op_schedule(timer_user_id_t user_id) 00868 { 00869 app_timer_id_t last_index; 00870 00871 timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index); 00872 if (p_user_op == NULL) 00873 { 00874 return NRF_ERROR_NO_MEM; 00875 } 00876 00877 p_user_op->op_type = TIMER_USER_OP_TYPE_STOP_ALL; 00878 p_user_op->timer_id = TIMER_NULL; 00879 00880 user_op_enque(&mp_users[user_id], last_index); 00881 00882 timer_list_handler_sched(); 00883 00884 return NRF_SUCCESS; 00885 } 00886 00887 00888 /**@brief Function for handling the RTC1 interrupt. 00889 * 00890 * @details Checks for timeouts, and executes timeout handlers for expired timers. 00891 */ 00892 extern "C" void RTC1_IRQHandler(void) 00893 { 00894 // Clear all events (also unexpected ones) 00895 NRF_RTC1->EVENTS_COMPARE[0] = 0; 00896 NRF_RTC1->EVENTS_COMPARE[1] = 0; 00897 NRF_RTC1->EVENTS_COMPARE[2] = 0; 00898 NRF_RTC1->EVENTS_COMPARE[3] = 0; 00899 NRF_RTC1->EVENTS_TICK = 0; 00900 NRF_RTC1->EVENTS_OVRFLW = 0; 00901 00902 // Check for expired timers 00903 timer_timeouts_check(); 00904 } 00905 00906 /**@brief Function for handling the SWI0 interrupt. 00907 * 00908 * @details Performs all updates to the timer list. 00909 */ 00910 extern "C" void SWI0_IRQHandler(void) 00911 { 00912 timer_list_handler(); 00913 } 00914 00915 uint32_t app_timer_init(uint32_t prescaler, 00916 uint8_t max_timers, 00917 uint8_t op_queues_size, 00918 void * p_buffer, 00919 app_timer_evt_schedule_func_t evt_schedule_func) 00920 { 00921 int i; 00922 00923 // Check that buffer is correctly aligned 00924 if (!is_word_aligned(p_buffer)) 00925 { 00926 return NRF_ERROR_INVALID_PARAM; 00927 } 00928 // Check for NULL buffer 00929 if (p_buffer == NULL) 00930 { 00931 return NRF_ERROR_INVALID_PARAM; 00932 } 00933 00934 // Stop RTC to prevent any running timers from expiring (in case of reinitialization) 00935 rtc1_stop(); 00936 00937 m_evt_schedule_func = evt_schedule_func; 00938 00939 // Initialize timer node array 00940 m_node_array_size = max_timers; 00941 mp_nodes = (timer_node_t *) p_buffer; 00942 00943 for (i = 0; i < max_timers; i++) 00944 { 00945 mp_nodes[i].state = STATE_FREE; 00946 mp_nodes[i].is_running = false; 00947 } 00948 00949 // Skip timer node array 00950 p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)]; 00951 00952 // Initialize users array 00953 m_user_array_size = APP_TIMER_INT_LEVELS; 00954 mp_users = (timer_user_t *) p_buffer; 00955 00956 // Skip user array 00957 p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)]; 00958 00959 // Initialize operation queues 00960 for (i = 0; i < APP_TIMER_INT_LEVELS; i++) 00961 { 00962 timer_user_t * p_user = &mp_users[i]; 00963 00964 p_user->first = 0; 00965 p_user->last = 0; 00966 p_user->user_op_queue_size = op_queues_size; 00967 p_user->p_user_op_queue = (timer_user_op_t *) p_buffer; 00968 00969 // Skip operation queue 00970 p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)]; 00971 } 00972 00973 m_timer_id_head = TIMER_NULL; 00974 m_ticks_elapsed_q_read_ind = 0; 00975 m_ticks_elapsed_q_write_ind = 0; 00976 00977 NVIC_ClearPendingIRQ(SWI0_IRQn); 00978 NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI); 00979 NVIC_EnableIRQ(SWI0_IRQn); 00980 00981 rtc1_init(prescaler); 00982 00983 m_ticks_latest = rtc1_counter_get(); 00984 00985 return NRF_SUCCESS; 00986 } 00987 00988 00989 uint32_t app_timer_create(app_timer_id_t * p_timer_id, 00990 app_timer_mode_t mode, 00991 app_timer_timeout_handler_t timeout_handler) 00992 { 00993 int i; 00994 00995 // Check state and parameters 00996 if (mp_nodes == NULL) 00997 { 00998 return NRF_ERROR_INVALID_STATE; 00999 } 01000 if (timeout_handler == NULL) 01001 { 01002 return NRF_ERROR_INVALID_PARAM; 01003 } 01004 if (p_timer_id == NULL) 01005 { 01006 return NRF_ERROR_INVALID_PARAM; 01007 } 01008 01009 // Find free timer 01010 for (i = 0; i < m_node_array_size; i++) 01011 { 01012 if (mp_nodes[i].state == STATE_FREE) 01013 { 01014 mp_nodes[i].state = STATE_ALLOCATED; 01015 mp_nodes[i].mode = mode; 01016 mp_nodes[i].p_timeout_handler = timeout_handler; 01017 01018 *p_timer_id = i; 01019 return NRF_SUCCESS; 01020 } 01021 } 01022 01023 return NRF_ERROR_NO_MEM; 01024 } 01025 01026 01027 /**@brief Function for creating a timer user id from the current interrupt level. 01028 * 01029 * @return Timer user id. 01030 */ 01031 static timer_user_id_t user_id_get(void) 01032 { 01033 timer_user_id_t ret; 01034 01035 STATIC_ASSERT(APP_TIMER_INT_LEVELS == 3); 01036 01037 switch (current_int_priority_get()) 01038 { 01039 case APP_IRQ_PRIORITY_HIGH: 01040 ret = APP_HIGH_USER_ID; 01041 break; 01042 01043 case APP_IRQ_PRIORITY_LOW: 01044 ret = APP_LOW_USER_ID; 01045 break; 01046 01047 default: 01048 ret = THREAD_MODE_USER_ID; 01049 break; 01050 } 01051 01052 return ret; 01053 } 01054 01055 01056 uint32_t app_timer_start(app_timer_id_t timer_id, uint32_t timeout_ticks, void * p_context) 01057 { 01058 uint32_t timeout_periodic; 01059 01060 // Check state and parameters 01061 if (mp_nodes == NULL) 01062 { 01063 return NRF_ERROR_INVALID_STATE; 01064 } 01065 if ((timer_id >= m_node_array_size) || (timeout_ticks < APP_TIMER_MIN_TIMEOUT_TICKS)) 01066 { 01067 return NRF_ERROR_INVALID_PARAM; 01068 } 01069 if (mp_nodes[timer_id].state != STATE_ALLOCATED) 01070 { 01071 return NRF_ERROR_INVALID_STATE; 01072 } 01073 01074 // Schedule timer start operation 01075 timeout_periodic = (mp_nodes[timer_id].mode == APP_TIMER_MODE_REPEATED) ? timeout_ticks : 0; 01076 01077 return timer_start_op_schedule(user_id_get(), 01078 timer_id, 01079 timeout_ticks, 01080 timeout_periodic, 01081 p_context); 01082 } 01083 01084 01085 uint32_t app_timer_stop(app_timer_id_t timer_id) 01086 { 01087 // Check state and parameters 01088 if (mp_nodes == NULL) 01089 { 01090 return NRF_ERROR_INVALID_STATE; 01091 } 01092 if (timer_id >= m_node_array_size) 01093 { 01094 return NRF_ERROR_INVALID_PARAM; 01095 } 01096 if (mp_nodes[timer_id].state != STATE_ALLOCATED) 01097 { 01098 return NRF_ERROR_INVALID_STATE; 01099 } 01100 01101 // Schedule timer stop operation 01102 return timer_stop_op_schedule(user_id_get(), timer_id); 01103 } 01104 01105 01106 uint32_t app_timer_stop_all(void) 01107 { 01108 // Check state 01109 if (mp_nodes == NULL) 01110 { 01111 return NRF_ERROR_INVALID_STATE; 01112 } 01113 01114 return timer_stop_all_op_schedule(user_id_get()); 01115 } 01116 01117 01118 uint32_t app_timer_cnt_get(uint32_t * p_ticks) 01119 { 01120 *p_ticks = rtc1_counter_get(); 01121 return NRF_SUCCESS; 01122 } 01123 01124 01125 uint32_t app_timer_cnt_diff_compute(uint32_t ticks_to, 01126 uint32_t ticks_from, 01127 uint32_t * p_ticks_diff) 01128 { 01129 *p_ticks_diff = ticks_diff_get(ticks_to, ticks_from); 01130 return NRF_SUCCESS; 01131 }
Generated on Tue Jul 12 2022 19:06:03 by
