245 lines
6.5 KiB
C
245 lines
6.5 KiB
C
#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 <rtthread.h>
|
|
|
|
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
|
|
}
|
|
|