robo 8080
/
BLE_TEST_konashi
konashi/SBBLEのテスト
Fork of BLE_LoopbackUART by
Embed:
(wiki syntax)
Show/hide line numbers
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 20:35:45 by 1.7.2