#include "board.h" #include "uart.h" #include "app_util_platform.h" #include "nrf_drv_common.h" #include "nrf_systick.h" #include "nrf_rtc.h" #include "nrf_drv_clock.h" #include "softdevice_handler.h" #include "nrf_drv_uart.h" #include "nrf_gpio.h" #include static rt_bool_t osready = RT_FALSE; #if 0 /******************************************************************************* * Function Name : SysTick_Configuration * Description : Configures the SysTick for OS tick. * Input : None * Output : None * Return : None *******************************************************************************/ void SysTick_Configuration(void) { nrf_drv_common_irq_enable(SysTick_IRQn, APP_TIMER_CONFIG_IRQ_PRIORITY); nrf_systick_load_set(SystemCoreClock / RT_TICK_PER_SECOND); nrf_systick_val_clear(); nrf_systick_csr_set(NRF_SYSTICK_CSR_CLKSOURCE_CPU | NRF_SYSTICK_CSR_TICKINT_ENABLE | NRF_SYSTICK_CSR_ENABLE); } /** * This is the timer interrupt service routine. * */ void SysTick_Handler(void) { if (osready) { /* enter interrupt */ rt_interrupt_enter(); rt_tick_increase(); /* leave interrupt */ rt_interrupt_leave(); } } #else #define TICK_RATE_HZ RT_TICK_PER_SECOND #define SYSTICK_CLOCK_HZ ( 32768UL ) #define NRF_RTC_REG NRF_RTC1 /* IRQn used by the selected RTC */ #define NRF_RTC_IRQn RTC1_IRQn /* Constants required to manipulate the NVIC. */ #define NRF_RTC_PRESCALER ( (uint32_t) (ROUNDED_DIV(SYSTICK_CLOCK_HZ, TICK_RATE_HZ) - 1) ) /* Maximum RTC ticks */ #define NRF_RTC_MAXTICKS ((1U<<24)-1U) static volatile uint32_t m_tick_overflow_count = 0; #define NRF_RTC_BITWIDTH 24 #define OSTick_Handler RTC1_IRQHandler #define EXPECTED_IDLE_TIME_BEFORE_SLEEP 2 void SysTick_Configuration(void) { nrf_drv_clock_lfclk_request(NULL); /* Configure SysTick to interrupt at the requested rate. */ nrf_rtc_prescaler_set(NRF_RTC_REG, NRF_RTC_PRESCALER); nrf_rtc_int_enable (NRF_RTC_REG, RTC_INTENSET_TICK_Msk); nrf_rtc_task_trigger (NRF_RTC_REG, NRF_RTC_TASK_CLEAR); nrf_rtc_task_trigger (NRF_RTC_REG, NRF_RTC_TASK_START); nrf_rtc_event_enable(NRF_RTC_REG, RTC_EVTEN_OVRFLW_Msk); NVIC_SetPriority(NRF_RTC_IRQn, 0xF); NVIC_EnableIRQ(NRF_RTC_IRQn); } void OSTick_Handler( void ) { nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); uint32_t systick_counter = nrf_rtc_counter_get(NRF_RTC_REG); nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_TICK); /* check for overflow in TICK counter */ if(nrf_rtc_event_pending(NRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW)) { nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_OVERFLOW); m_tick_overflow_count++; } { uint32_t diff; diff = ((m_tick_overflow_count << NRF_RTC_BITWIDTH) + systick_counter) - rt_tick_get(); while((diff--) > 0) { if (osready) { /* enter interrupt */ rt_interrupt_enter(); rt_tick_increase(); /* leave interrupt */ rt_interrupt_leave(); } } } } static void _sleep_ongo( uint32_t sleep_tick ) { /* * Implementation note: * * To help debugging the option configUSE_TICKLESS_IDLE_SIMPLE_DEBUG was presented. * This option would make sure that even if program execution was stopped inside * this function no more than expected number of ticks would be skipped. * * Normally RTC works all the time even if firmware execution was stopped * and that may lead to skipping too much of ticks. */ uint32_t enterTime; uint32_t entry_tick; /* Make sure the SysTick reload value does not overflow the counter. */ if ( sleep_tick > NRF_RTC_MAXTICKS - EXPECTED_IDLE_TIME_BEFORE_SLEEP ) { sleep_tick = NRF_RTC_MAXTICKS - EXPECTED_IDLE_TIME_BEFORE_SLEEP; } rt_enter_critical(); enterTime = nrf_rtc_counter_get(NRF_RTC_REG); // if ( eTaskConfirmSleepModeStatus() != eAbortSleep ) { uint32_t wakeupTime = (enterTime + sleep_tick) & NRF_RTC_MAXTICKS; /* Stop tick events */ nrf_rtc_int_disable(NRF_RTC_REG, NRF_RTC_INT_TICK_MASK); /* Configure CTC interrupt */ nrf_rtc_cc_set(NRF_RTC_REG, 0, wakeupTime); nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); nrf_rtc_int_enable(NRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK); entry_tick = rt_tick_get(); __DSB(); if ( sleep_tick > 0 ) { #ifdef SOFTDEVICE_PRESENT if (softdevice_handler_is_enabled()) { uint32_t err_code = sd_app_evt_wait(); APP_ERROR_CHECK(err_code); } else #endif { /* No SD - we would just block interrupts globally. * BASEPRI cannot be used for that because it would prevent WFE from wake up. */ do{ __WFE(); } while (0 == (NVIC->ISPR[0] | NVIC->ISPR[1])); } } nrf_rtc_int_disable(NRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK); nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0); /* Correct the system ticks */ { nrf_rtc_event_clear(NRF_RTC_REG, NRF_RTC_EVENT_TICK); nrf_rtc_int_enable (NRF_RTC_REG, NRF_RTC_INT_TICK_MASK); /* It is important that we clear pending here so that our corrections are latest and in sync with tick_interrupt handler */ NVIC_ClearPendingIRQ(NRF_RTC_IRQn); } rt_kprintf("entry tick:%u, expected:%u, current tick:%u\n", entry_tick, sleep_tick, rt_tick_get()); } rt_exit_critical(); } #endif void rt_os_ready(void) { osready = 1; } void rt_hw_system_powersave(void) { uint32_t sleep_tick; sleep_tick = rt_timer_next_timeout_tick() - rt_tick_get(); if ( sleep_tick >= EXPECTED_IDLE_TIME_BEFORE_SLEEP) { // rt_kprintf("sleep entry:%u\n", rt_tick_get()); _sleep_ongo( sleep_tick ); } } void rt_hw_board_init(void) { // sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE); /* Activate deep sleep mode */ SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; nrf_drv_clock_init(); // nrf_drv_clock_hfclk_request(0); SysTick_Configuration(); rt_thread_idle_sethook(rt_hw_system_powersave); rt_hw_uart_init(); #ifdef RT_USING_CONSOLE rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #endif #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif }