/**@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(); } }
void us_ticker_init(void) { if (us_ticker_inited) { return; } rtc1_start(); us_ticker_inited = true; }
/**@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(); } }
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 = (timer_node_t *) 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 = (timer_user_t *) 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 = (timer_user_op_t *) 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); rtc1_init(prescaler); rtc1_start(); m_ticks_latest = rtc1_counter_get(); return NRF_SUCCESS; }