/**@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_init(uint32_t prescaler, uint8_t op_queues_size, void * p_buffer, app_timer_evt_schedule_func_t evt_schedule_func) { int i; // Check that buffer is correctly aligned if (!is_word_aligned(p_buffer)) { return NRF_ERROR_INVALID_PARAM; } // Check for NULL buffer if (p_buffer == NULL) { mp_users = NULL; return NRF_ERROR_INVALID_PARAM; } // Stop RTC to prevent any running timers from expiring (in case of reinitialization) rtc1_stop(); m_evt_schedule_func = evt_schedule_func; // Initialize users array m_user_array_size = APP_TIMER_INT_LEVELS; mp_users = p_buffer; // Skip user array p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)]; // Initialize operation queues for (i = 0; i < APP_TIMER_INT_LEVELS; i++) { timer_user_t * p_user = &mp_users[i]; p_user->first = 0; p_user->last = 0; p_user->user_op_queue_size = op_queues_size; p_user->p_user_op_queue = p_buffer; // Skip operation queue p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)]; } mp_timer_id_head = NULL; m_ticks_elapsed_q_read_ind = 0; m_ticks_elapsed_q_write_ind = 0; NVIC_ClearPendingIRQ(SWI_IRQn); NVIC_SetPriority(SWI_IRQn, SWI_IRQ_PRI); NVIC_EnableIRQ(SWI_IRQn); rtc1_init(prescaler); m_ticks_latest = rtc1_counter_get(); return NRF_SUCCESS; }
/**@brief Function for removing a timer from the timer queue. * * @param[in] timer_id Id of timer to remove. */ static void timer_list_remove(app_timer_id_t timer_id) { app_timer_id_t previous; app_timer_id_t current; uint32_t timeout; // Find the timer's position in timer list. previous = m_timer_id_head; current = previous; while (current != TIMER_NULL) { if (current == timer_id) { break; } previous = current; current = mp_nodes[current].next; } // Timer not in active list. if (current == TIMER_NULL) { return; } // Timer is the first in the list if (previous == current) { m_timer_id_head = mp_nodes[m_timer_id_head].next; // No more timers in the list. Disable RTC1. if (m_timer_id_head == TIMER_NULL) { rtc1_stop(); } } // Remaining timeout between next timeout. timeout = mp_nodes[current].ticks_to_expire; // Link previous timer with next of this timer, i.e. removing the timer from list. mp_nodes[previous].next = mp_nodes[current].next; // If this is not the last timer, increment the next timer by this timer timeout. current = mp_nodes[previous].next; if (current != TIMER_NULL) { mp_nodes[current].ticks_to_expire += timeout; } }
/**@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) } }
uint32_t app_timer_init(uint32_t prescaler, uint8_t op_queue_size, void * p_buffer, app_timer_evt_schedule_func_t evt_schedule_func) { // Check that buffer is correctly aligned if (!is_word_aligned(p_buffer)) { return NRF_ERROR_INVALID_PARAM; } // Check for NULL buffer if (p_buffer == NULL) { return NRF_ERROR_INVALID_PARAM; } // Stop RTC to prevent any running timers from expiring (in case of reinitialization) rtc1_stop(); m_evt_schedule_func = evt_schedule_func; // Initialize operation queue m_op_queue.first = 0; m_op_queue.last = 0; m_op_queue.size = op_queue_size; m_op_queue.p_user_op_queue = p_buffer; mp_timer_id_head = NULL; m_ticks_elapsed_q_read_ind = 0; m_ticks_elapsed_q_write_ind = 0; #if APP_TIMER_WITH_PROFILER m_max_user_op_queue_utilization = 0; #endif NVIC_ClearPendingIRQ(SWI_IRQn); NVIC_SetPriority(SWI_IRQn, SWI_IRQ_PRI); NVIC_EnableIRQ(SWI_IRQn); rtc1_init(prescaler); m_ticks_latest = rtc1_counter_get(); return NRF_SUCCESS; }
/**@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(); } }
uint32_t app_timer_init(uint32_t prescaler, uint8_t max_timers, uint8_t op_queues_size, void * p_buffer, app_timer_evt_schedule_func_t evt_schedule_func) { int i; // Check that buffer is correctly aligned if (!is_word_aligned(p_buffer)) { return NRF_ERROR_INVALID_PARAM; } // Check for NULL buffer if (p_buffer == NULL) { return NRF_ERROR_INVALID_PARAM; } // Stop RTC to prevent any running timers from expiring (in case of reinitialization) rtc1_stop(); m_evt_schedule_func = evt_schedule_func; // Initialize timer node array m_node_array_size = max_timers; mp_nodes = p_buffer; for (i = 0; i < max_timers; i++) { mp_nodes[i].state = STATE_FREE; mp_nodes[i].is_running = false; } // Skip timer node array p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)]; // Initialize users array m_user_array_size = APP_TIMER_INT_LEVELS; mp_users = p_buffer; // Skip user array p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)]; // Initialize operation queues for (i = 0; i < APP_TIMER_INT_LEVELS; i++) { timer_user_t * p_user = &mp_users[i]; p_user->first = 0; p_user->last = 0; p_user->user_op_queue_size = op_queues_size; p_user->p_user_op_queue = p_buffer; // Skip operation queue p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)]; } m_timer_id_head = TIMER_NULL; m_ticks_elapsed_q_read_ind = 0; m_ticks_elapsed_q_write_ind = 0; /* NVIC_ClearPendingIRQ(SWI0_IRQn); NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI); NVIC_EnableIRQ(SWI0_IRQn); */ /*--khai-- : temporarily use SWI1 for app_timer so that conflict with event_handler won't occur*/ NVIC_ClearPendingIRQ(SWI1_IRQn); NVIC_SetPriority(SWI1_IRQn, SWI0_IRQ_PRI); NVIC_EnableIRQ(SWI1_IRQn); rtc1_init(prescaler); m_ticks_latest = rtc1_counter_get(); return NRF_SUCCESS; }