/**@brief Function for updating the Capture Compare register. */ static void compare_reg_update(app_timer_id_t timer_id_head_old) { // Setup the timeout for timers on the head of the list if (m_timer_id_head != TIMER_NULL) { uint32_t ticks_to_expire = mp_nodes[m_timer_id_head].ticks_to_expire; uint32_t counter = rtc1_counter_get(); uint32_t cc = m_ticks_latest; uint32_t ticks_elapsed = ticks_diff_get(counter, cc) + RTC_COMPARE_OFFSET_MIN; if (timer_id_head_old == TIMER_NULL) { // No timers were already running, start RTC rtc1_start(); } cc += (ticks_elapsed < ticks_to_expire) ? ticks_to_expire : ticks_elapsed; cc &= MAX_RTC_CNT; rtc1_compare0_set(cc); if (ticks_diff_get(rtc1_counter_get(), counter) > ticks_diff_get(cc, counter)) { timer_timeouts_check_sched(); } } else { // No timers are running, stop RTC rtc1_stop(); } }
uint32_t app_timer_cnt_diff_compute(uint32_t ticks_to, uint32_t ticks_from, uint32_t * p_ticks_diff) { *p_ticks_diff = ticks_diff_get(ticks_to, ticks_from); return NRF_SUCCESS; }
/**@brief Function for updating the Capture Compare register. */ static void compare_reg_update(timer_node_t * p_timer_id_head_old) { // Setup the timeout for timers on the head of the list if (mp_timer_id_head != NULL) { uint32_t ticks_to_expire = mp_timer_id_head->ticks_to_expire; uint32_t pre_counter_val = rtc1_counter_get(); uint32_t cc = m_ticks_latest; uint32_t ticks_elapsed = ticks_diff_get(pre_counter_val, cc) + RTC_COMPARE_OFFSET_MIN; if (!m_rtc1_running) { // No timers were already running, start RTC rtc1_start(); } cc += (ticks_elapsed < ticks_to_expire) ? ticks_to_expire : ticks_elapsed; cc &= MAX_RTC_COUNTER_VAL; rtc1_compare0_set(cc); uint32_t post_counter_val = rtc1_counter_get(); if ( (ticks_diff_get(post_counter_val, pre_counter_val) + RTC_COMPARE_OFFSET_MIN) > ticks_diff_get(cc, pre_counter_val) ) { // When this happens the COMPARE event may not be triggered by the RTC. // The nRF51 Series User Specification states that if the COUNTER value is N // (i.e post_counter_val = N), writing N or N + 1 to a CC register may not trigger a // COMPARE event. Hence the RTC interrupt is forcefully pended by calling the following // function. rtc1_compare0_set(rtc1_counter_get()); // this should prevent CC to fire again in the background while the code is in RTC-ISR nrf_delay_us(MAX_RTC_TASKS_DELAY); timer_timeouts_check_sched(); } } else { #if (APP_TIMER_KEEPS_RTC_ACTIVE == 0) // No timers are running, stop RTC rtc1_stop(); #endif //(APP_TIMER_KEEPS_RTC_ACTIVE == 0) } }
/**@brief Function for updating the Capture Compare register. */ static void compare_reg_update(app_timer_id_t timer_id_head_old) { // Setup the timeout for timers on the head of the list if (m_timer_id_head != TIMER_NULL) { uint32_t ticks_to_expire = mp_nodes[m_timer_id_head].ticks_to_expire; uint32_t pre_counter_val = rtc1_counter_get(); uint32_t cc = m_ticks_latest; uint32_t ticks_elapsed = ticks_diff_get(pre_counter_val, cc) + RTC_COMPARE_OFFSET_MIN; if (timer_id_head_old == TIMER_NULL) { // No timers were already running, start RTC rtc1_start(); } cc += (ticks_elapsed < ticks_to_expire) ? ticks_to_expire : ticks_elapsed; cc &= MAX_RTC_COUNTER_VAL; rtc1_compare0_set(cc); uint32_t post_counter_val = rtc1_counter_get(); if ( (ticks_diff_get(post_counter_val, pre_counter_val) + RTC_COMPARE_OFFSET_MIN) > ticks_diff_get(cc, pre_counter_val) ) { // When this happens the COMPARE event may not be triggered by the RTC. // The nRF51 Series User Specification states that if the COUNTER value is N // (i.e post_counter_val = N), writing N or N+1 to a CC register may not trigger a // COMPARE event. Hence the RTC interrupt is forcefully pended by calling the following // function. timer_timeouts_check_sched(); } } else { // No timers are running, stop RTC rtc1_stop(); } }
/**@brief Function for handling timer list insertions. * * @param[in] p_restart_list_head List of repeating timers to be restarted. * * @return TRUE if Capture Compare register must be updated, FALSE otherwise. */ static bool list_insertions_handler(timer_node_t * p_restart_list_head) { timer_node_t * p_timer_id_old_head; uint8_t user_id; // Remember the old head, so as to decide if new compare needs to be set. p_timer_id_old_head = mp_timer_id_head; user_id = m_user_array_size; while (user_id--) { timer_user_t * p_user = &mp_users[user_id]; // Handle insertions of timers. while ((p_restart_list_head != NULL) || (p_user->first != p_user->last)) { timer_node_t * p_timer; if (p_restart_list_head != NULL) { p_timer = p_restart_list_head; p_restart_list_head = p_timer->next; } else { timer_user_op_t * p_user_op = &p_user->p_user_op_queue[p_user->first]; p_user->first++; if (p_user->first == p_user->user_op_queue_size) { p_user->first = 0; } p_timer = p_user_op->p_node; if ((p_user_op->op_type != TIMER_USER_OP_TYPE_START) || p_timer->is_running) { continue; } p_timer->ticks_at_start = p_user_op->params.start.ticks_at_start; p_timer->ticks_first_interval = p_user_op->params.start.ticks_first_interval; p_timer->ticks_periodic_interval = p_user_op->params.start.ticks_periodic_interval; p_timer->p_context = p_user_op->params.start.p_context; if (m_rtc1_reset) { p_timer->ticks_at_start = 0; } } // Prepare the node to be inserted. if ( ((p_timer->ticks_at_start - m_ticks_latest) & MAX_RTC_COUNTER_VAL) < (MAX_RTC_COUNTER_VAL / 2) ) { p_timer->ticks_to_expire = ticks_diff_get(p_timer->ticks_at_start, m_ticks_latest) + p_timer->ticks_first_interval; } else { uint32_t delta_current_start; delta_current_start = ticks_diff_get(m_ticks_latest, p_timer->ticks_at_start); if (p_timer->ticks_first_interval > delta_current_start) { p_timer->ticks_to_expire = p_timer->ticks_first_interval - delta_current_start; } else { p_timer->ticks_to_expire = 0; } } p_timer->ticks_at_start = 0; p_timer->ticks_first_interval = 0; p_timer->is_running = true; p_timer->next = NULL; // Insert into list timer_list_insert(p_timer); } } return (mp_timer_id_head != p_timer_id_old_head); }
/**@brief Function for checking for expired timers. */ static void timer_timeouts_check(void) { // Handle expired of timer if (mp_timer_id_head != NULL) { timer_node_t * p_timer; timer_node_t * p_previous_timer; uint32_t ticks_elapsed; uint32_t ticks_expired; // Initialize actual elapsed ticks being consumed to 0. ticks_expired = 0; // ticks_elapsed is collected here, job will use it. ticks_elapsed = ticks_diff_get(rtc1_counter_get(), m_ticks_latest); // Auto variable containing the head of timers expiring. p_timer = mp_timer_id_head; // Expire all timers within ticks_elapsed and collect ticks_expired. while (p_timer != NULL) { // Do nothing if timer did not expire. if (ticks_elapsed < p_timer->ticks_to_expire) { break; } // Decrement ticks_elapsed and collect expired ticks. ticks_elapsed -= p_timer->ticks_to_expire; ticks_expired += p_timer->ticks_to_expire; // Move to next timer. p_previous_timer = p_timer; p_timer = p_timer->next; // Execute Task. timeout_handler_exec(p_previous_timer); } // Prepare to queue the ticks expired in the m_ticks_elapsed queue. if (m_ticks_elapsed_q_read_ind == m_ticks_elapsed_q_write_ind) { // The read index of the queue is equal to the write index. This means the new // value of ticks_expired should be stored at a new location in the m_ticks_elapsed // queue (which is implemented as a double buffer). // Check if there will be a queue overflow. if (++m_ticks_elapsed_q_write_ind == CONTEXT_QUEUE_SIZE_MAX) { // There will be a queue overflow. Hence the write index should point to the start // of the queue. m_ticks_elapsed_q_write_ind = 0; } } // Queue the ticks expired. m_ticks_elapsed[m_ticks_elapsed_q_write_ind] = ticks_expired; timer_list_handler_sched(); } }
/**@brief Function for checking for expired timers. */ static void timer_timeouts_check(void) { // Handle expired of timer if (m_timer_id_head != TIMER_NULL) { uint32_t ticks_expired; uint8_t ticks_elapsed_last; // Initialize actual elapsed ticks being consumed to 0 ticks_expired = 0; // Queue the ticks elapsed (to make the value context safe) ticks_elapsed_last = m_ticks_elapsed_last + 1; if (ticks_elapsed_last == CONTEXT_QUEUE_SIZE_MAX) { ticks_elapsed_last = 0; } if (ticks_elapsed_last != m_ticks_elapsed_first) { app_timer_id_t timer_id; uint32_t ticks_elapsed; // Ticks_elapsed is collected here, job will use it ticks_elapsed = ticks_diff_get(rtc1_counter_get(), m_ticks_latest); // Auto variable containing the head of timers expiring timer_id = m_timer_id_head; // Expire all timers within ticks_elapsed and collect ticks_expired while (timer_id != TIMER_NULL) { timer_node_t * p_timer; // Auto variable for current timer node p_timer = &mp_nodes[timer_id]; // Do nothing if timer did not expire if (ticks_elapsed < p_timer->ticks_to_expire) { break; } // Decrement ticks_elapsed and collect expired ticks ticks_elapsed -= p_timer->ticks_to_expire; ticks_expired += p_timer->ticks_to_expire; // Move to next timer timer_id = p_timer->next; // Execute Task timeout_handler_exec(p_timer); } } // Queue the elapsed value m_ticks_elapsed[m_ticks_elapsed_last] = ticks_expired; m_ticks_elapsed_last = ticks_elapsed_last; timer_list_handler_sched(); } }