nrf52: extend systimer support; support WFI/WFE again
This commit exends systimer options for nRF52 arch. It is possible to use ARM SysTick either for tickless or non-tickless mode. Also, it is possible to use the RTC peripheral for tickless mode. This also re-enables support for WFI/WFE sleep if RTC is used, since this counter continues to run in this mode (in contrast to SysTick).
This commit is contained in:
parent
dcd49c3882
commit
459ad29799
@ -208,6 +208,7 @@ config ARCH_CHIP_MOXART
|
|||||||
config ARCH_CHIP_NRF52
|
config ARCH_CHIP_NRF52
|
||||||
bool "Nordic NRF52"
|
bool "Nordic NRF52"
|
||||||
select ARCH_CORTEXM4
|
select ARCH_CORTEXM4
|
||||||
|
select ARCH_HAVE_TICKLESS
|
||||||
#select ARCH_HAVE_MPU
|
#select ARCH_HAVE_MPU
|
||||||
#select ARM_HAVE_MPU_UNIFIED
|
#select ARM_HAVE_MPU_UNIFIED
|
||||||
select ARCH_HAVE_FPU
|
select ARCH_HAVE_FPU
|
||||||
|
@ -291,6 +291,57 @@ endif # NRF52_USE_LFCLK
|
|||||||
|
|
||||||
endmenu # Clock Configuration
|
endmenu # Clock Configuration
|
||||||
|
|
||||||
|
menu "System Timer"
|
||||||
|
|
||||||
|
config NRF52_SYSTIMER
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "System Timer Source"
|
||||||
|
default NRF52_SYSTIMER_SYSTICK
|
||||||
|
---help---
|
||||||
|
Choose which hardware resource will drive NuttX
|
||||||
|
system time
|
||||||
|
|
||||||
|
config NRF52_SYSTIMER_SYSTICK
|
||||||
|
bool "SysTick"
|
||||||
|
select TIMER_ARCH
|
||||||
|
select TIMER
|
||||||
|
select ARMV7M_SYSTICK
|
||||||
|
---help---
|
||||||
|
Use ARM SysTick. It can be used for tickless and
|
||||||
|
non-tickless mode.
|
||||||
|
|
||||||
|
NOTE: nRF52 implementation of WFE/WFI involves is
|
||||||
|
incompatible with SysTick. This means that if
|
||||||
|
you choose this option, WFE/WFI will not be used
|
||||||
|
in idle loop.
|
||||||
|
|
||||||
|
config NRF52_SYSTIMER_RTC
|
||||||
|
bool "RTC"
|
||||||
|
select NRF52_RTC
|
||||||
|
select SCHED_TICKLESS
|
||||||
|
select SCHED_TICKLESS_ALARM
|
||||||
|
select NRF52_USE_LFCLK
|
||||||
|
---help---
|
||||||
|
Use RTC timer in tickless mode.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
if NRF52_SYSTIMER_RTC
|
||||||
|
|
||||||
|
config NRF52_SYSTIMER_RTC_INSTANCE
|
||||||
|
int "RTC timer instance"
|
||||||
|
default 0
|
||||||
|
range 0 2
|
||||||
|
---help---
|
||||||
|
Which RTC instance to use to drive the system timer
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
endmenu # System Timer
|
||||||
|
|
||||||
config NRF52_FLASH_PREFETCH
|
config NRF52_FLASH_PREFETCH
|
||||||
bool "Enable FLASH Pre-fetch"
|
bool "Enable FLASH Pre-fetch"
|
||||||
default y
|
default y
|
||||||
|
@ -45,12 +45,20 @@ endif
|
|||||||
CMN_CSRCS = arm_assert.c arm_blocktask.c arm_copyfullstate.c
|
CMN_CSRCS = arm_assert.c arm_blocktask.c arm_copyfullstate.c
|
||||||
CMN_CSRCS += arm_createstack.c arm_doirq.c arm_exit.c arm_hardfault.c
|
CMN_CSRCS += arm_createstack.c arm_doirq.c arm_exit.c arm_hardfault.c
|
||||||
CMN_CSRCS += arm_initialize.c arm_initialstate.c arm_interruptcontext.c
|
CMN_CSRCS += arm_initialize.c arm_initialstate.c arm_interruptcontext.c
|
||||||
CMN_CSRCS += arm_memfault.c arm_mdelay.c arm_modifyreg8.c arm_modifyreg16.c
|
CMN_CSRCS += arm_memfault.c arm_modifyreg8.c arm_modifyreg16.c
|
||||||
CMN_CSRCS += arm_modifyreg32.c arm_releasepending.c arm_releasestack.c
|
CMN_CSRCS += arm_modifyreg32.c arm_releasepending.c arm_releasestack.c
|
||||||
CMN_CSRCS += arm_reprioritizertr.c arm_schedulesigaction.c arm_sigdeliver.c
|
CMN_CSRCS += arm_reprioritizertr.c arm_schedulesigaction.c arm_sigdeliver.c
|
||||||
CMN_CSRCS += arm_stackframe.c arm_svcall.c arm_trigger_irq.c arm_udelay.c
|
CMN_CSRCS += arm_stackframe.c arm_svcall.c arm_trigger_irq.c arm_udelay.c
|
||||||
CMN_CSRCS += arm_unblocktask.c arm_usestack.c arm_vfork.c arm_systemreset.c
|
CMN_CSRCS += arm_unblocktask.c arm_usestack.c arm_vfork.c arm_systemreset.c
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_NRF52_SYSTIMER_SYSTICK),y)
|
||||||
|
CMN_CSRCS += arm_systick.c nrf52_systick.c
|
||||||
|
else
|
||||||
|
ifeq ($(CONFIG_NRF52_SYSTIMER_RTC),y)
|
||||||
|
CMN_CSRCS += nrf52_tickless_rtc.c arm_mdelay.c
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_ARMV7M_LAZYFPU),y)
|
ifeq ($(CONFIG_ARMV7M_LAZYFPU),y)
|
||||||
CMN_ASRCS += arm_lazyexception.S
|
CMN_ASRCS += arm_lazyexception.S
|
||||||
else
|
else
|
||||||
@ -85,12 +93,6 @@ ifeq ($(CONFIG_ARCH_CHIP_NRF52832),y)
|
|||||||
CHIP_CSRCS += nrf52832_errdata.c
|
CHIP_CSRCS += nrf52832_errdata.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(CONFIG_SCHED_TICKLESS),y)
|
|
||||||
CHIP_CSRCS += nrf52_timerisr.c
|
|
||||||
else
|
|
||||||
CHIP_CSRCS += nrf52_tickless.c
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(CONFIG_BUILD_PROTECTED),y)
|
ifeq ($(CONFIG_BUILD_PROTECTED),y)
|
||||||
CHIP_CSRCS += nrf52_userspace.c nrf52_mpuinit.c
|
CHIP_CSRCS += nrf52_userspace.c nrf52_mpuinit.c
|
||||||
endif
|
endif
|
||||||
|
@ -178,11 +178,11 @@ void up_idle(void)
|
|||||||
|
|
||||||
/* Sleep until an interrupt occurs to save power
|
/* Sleep until an interrupt occurs to save power
|
||||||
*
|
*
|
||||||
* REVISIT: The SysTick's clock will only tick when the CPU is
|
* The SysTick's clock will only tick when the CPU is
|
||||||
* running (not in WFE/WFI) or when the system is in debug interface mode.
|
* running (not in WFE/WFI) or when the system is in debug interface mode.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if 0
|
#ifdef CONFIG_NRF52_SYSTIMER_RTC
|
||||||
BEGIN_IDLE();
|
BEGIN_IDLE();
|
||||||
asm("WFI");
|
asm("WFI");
|
||||||
END_IDLE();
|
END_IDLE();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* arch/arm/src/nrf52/nrf52_timerisr.c
|
* arch/arm/src/nrf52/nrf52_systick.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2018 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
@ -46,68 +46,17 @@
|
|||||||
#include <nuttx/arch.h>
|
#include <nuttx/arch.h>
|
||||||
#include <arch/board/board.h>
|
#include <arch/board/board.h>
|
||||||
|
|
||||||
#include "nvic.h"
|
#include <nuttx/timers/arch_timer.h>
|
||||||
#include "clock/clock.h"
|
#include "systick.h"
|
||||||
#include "arm_internal.h"
|
|
||||||
#include "arm_arch.h"
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* The SysTick clock may be clocked internally either by the by the system
|
|
||||||
* clock (CLKSOURCE==1) or by the SysTick function clock (CLKSOURCE==0).
|
|
||||||
* The SysTick Function clock is equal to:
|
|
||||||
*
|
|
||||||
* Fsystick = Fmainclk / SYSTICKCLKDIV
|
|
||||||
*
|
|
||||||
* Both the divider value (BOARD_SYSTICKCLKDIV) and the resulting SysTick
|
|
||||||
* function clock frequency (Fsystick, BOARD_SYSTICK_CLOCK)
|
|
||||||
*
|
|
||||||
* The desired timer interrupt frequency is provided by the definition
|
|
||||||
* CLK_TCK (see include/time.h). CLK_TCK defines the desired number of
|
|
||||||
* system clock ticks per second. That value is a user configurable setting
|
|
||||||
* that defaults to 100 (100 ticks per second = 10 MS interval).
|
|
||||||
*
|
|
||||||
* reload = (Fsystick / CLK_TICK) - 1
|
|
||||||
*
|
|
||||||
* Tips for selecting BOARD_SYSTICKCLKDIV: The resulting reload value
|
|
||||||
* should be as large as possible, but must be less than 2^24:
|
|
||||||
*
|
|
||||||
* SYSTICKDIV > Fmainclk / CLK_TCK / 2^24
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SYSTICK_RELOAD ((BOARD_SYSTICK_CLOCK / CLK_TCK) - 1)
|
|
||||||
|
|
||||||
/* The size of the reload field is 24 bits. Verify that the reload value
|
|
||||||
* will fit in the reload register.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if SYSTICK_RELOAD > 0x00ffffff
|
|
||||||
# error SYSTICK_RELOAD exceeds the range of the RELOAD register
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Function: nrf52_timerisr
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* The timer ISR will perform a variety of services for various portions
|
|
||||||
* of the systems.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int nrf52_timerisr(int irq, uint32_t *regs, void *arg)
|
|
||||||
{
|
|
||||||
/* Process timer interrupt */
|
|
||||||
|
|
||||||
nxsched_process_timer();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@ -123,26 +72,7 @@ static int nrf52_timerisr(int irq, uint32_t *regs, void *arg)
|
|||||||
|
|
||||||
void up_timer_initialize(void)
|
void up_timer_initialize(void)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
/* Use SysTick to drive system timer */
|
||||||
|
|
||||||
regval = getreg32(NVIC_SYSTICK_CTRL);
|
up_timer_set_lowerhalf(systick_initialize(true, BOARD_SYSTICK_CLOCK, -1));
|
||||||
regval &= ~NVIC_SYSTICK_CTRL_CLKSOURCE;
|
|
||||||
putreg32(regval, NVIC_SYSTICK_CTRL);
|
|
||||||
|
|
||||||
/* Configure SysTick to interrupt at the requested rate */
|
|
||||||
|
|
||||||
putreg32(SYSTICK_RELOAD, NVIC_SYSTICK_RELOAD);
|
|
||||||
|
|
||||||
/* Attach the timer interrupt vector */
|
|
||||||
|
|
||||||
irq_attach(NRF52_IRQ_SYSTICK, (xcpt_t)nrf52_timerisr, NULL);
|
|
||||||
|
|
||||||
/* Enable SysTick interrupts */
|
|
||||||
|
|
||||||
putreg32((NVIC_SYSTICK_CTRL_CLKSOURCE | NVIC_SYSTICK_CTRL_TICKINT |
|
|
||||||
NVIC_SYSTICK_CTRL_ENABLE), NVIC_SYSTICK_CTRL);
|
|
||||||
|
|
||||||
/* And enable the timer interrupt */
|
|
||||||
|
|
||||||
up_enable_irq(NRF52_IRQ_SYSTICK);
|
|
||||||
}
|
}
|
330
arch/arm/src/nrf52/nrf52_tickless_rtc.c
Normal file
330
arch/arm/src/nrf52/nrf52_tickless_rtc.c
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* arch/arm/src/nrf52/nrf52_tickless_rtc.c
|
||||||
|
*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership. The
|
||||||
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Included Files
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <nuttx/config.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
#include <nuttx/arch.h>
|
||||||
|
|
||||||
|
#include "arm_arch.h"
|
||||||
|
|
||||||
|
#include "hardware/nrf52_rtc.h"
|
||||||
|
#include "nrf52_rtc.h"
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Pre-processor Definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/* Check corresponding RTC support */
|
||||||
|
|
||||||
|
#if (CONFIG_NRF52_SYSTIMER_RTC_INSTANCE == 0) && !defined(CONFIG_NRF52_RTC0)
|
||||||
|
# error "Support for RTC0 is not enabled"
|
||||||
|
#elif (CONFIG_NRF52_SYSTIMER_RTC_INSTANCE == 1) && !defined(CONFIG_NRF52_RTC1)
|
||||||
|
# error "Support for RTC1 is not enabled"
|
||||||
|
#elif (CONFIG_NRF52_SYSTIMER_RTC_INSTANCE == 2) && !defined(CONFIG_NRF52_RTC2)
|
||||||
|
# error "Support for RTC2 is not enabled"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TIMER configuration */
|
||||||
|
|
||||||
|
#if (CONFIG_NRF52_SYSTIMER_RTC_INSTANCE == 0)
|
||||||
|
# define NRF52_RTC_BASE NRF52_RTC0_BASE
|
||||||
|
#elif (CONFIG_NRF52_SYSTIMER_RTC_INSTANCE == 1)
|
||||||
|
# define NRF52_RTC_BASE NRF52_RTC1_BASE
|
||||||
|
#elif (CONFIG_NRF52_SYSTIMER_RTC_INSTANCE == 2)
|
||||||
|
# define NRF52_RTC_BASE NRF52_RTC2_BASE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NRF52_RTC_PERIOD (512)
|
||||||
|
#define NRF52_RTC_MAX (0x00ffffff)
|
||||||
|
#define NRF52_RTC_MAX_TIME (NRF52_RTC_MAX * 31)
|
||||||
|
|
||||||
|
/* Convert uS to timer count for f = 32768Hz, using more precision
|
||||||
|
* when possible:
|
||||||
|
* (1 / 32768) s ~ 30.51 uS ~ 31 uS
|
||||||
|
* 512 * (1 / 32768) s = 0.015625 s = 15625 uS
|
||||||
|
* So, instead of always dividing by 31, if t * 512 < (2**32 - 1), we can do:
|
||||||
|
* (t * 512) / 15625 ~ t / 30.51
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USEC_TO_COUNTER(t) (t > 0x7fffff ? (t / 31) : ((t * 512) / 15625))
|
||||||
|
|
||||||
|
/* To convert from counter to uS we split the counter into one second worth
|
||||||
|
* of counts (32768) and a fractional part we can safely multiply first
|
||||||
|
* by (USEC_PER_SEC/8) and still be within 32 bit value
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define COUNTER_TO_USEC(c) ((c / 32768) * USEC_PER_SEC) + \
|
||||||
|
(((c % 32768) * (USEC_PER_SEC / 8)) / (32768 / 8))
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Types
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
struct nrf52_tickless_dev_s
|
||||||
|
{
|
||||||
|
FAR struct nrf52_rtc_dev_s *rtc; /* nrf52 RTC driver */
|
||||||
|
uint32_t periods; /* how many times the timer overflowed */
|
||||||
|
bool alarm_set; /* is the alarm set? */
|
||||||
|
struct timespec alarm; /* absolute time of alarm */
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Function Prototypes
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int rtc_handler(int irq, void *context, void *arg);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
struct nrf52_tickless_dev_s g_tickless_dev;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void rtc_counter_to_ts(uint32_t counter, struct timespec *now)
|
||||||
|
{
|
||||||
|
uint32_t usec;
|
||||||
|
|
||||||
|
usec = COUNTER_TO_USEC(counter);
|
||||||
|
now->tv_sec = usec / USEC_PER_SEC;
|
||||||
|
now->tv_nsec = (usec % USEC_PER_SEC) * NSEC_PER_USEC;
|
||||||
|
|
||||||
|
now->tv_sec += g_tickless_dev.periods * NRF52_RTC_PERIOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_prepare_alarm(void)
|
||||||
|
{
|
||||||
|
struct timespec now;
|
||||||
|
struct timespec delta;
|
||||||
|
uint32_t usec;
|
||||||
|
uint32_t counter;
|
||||||
|
uint32_t target_counter;
|
||||||
|
|
||||||
|
/* get current counter and absolute time */
|
||||||
|
|
||||||
|
NRF52_RTC_GETCOUNTER(g_tickless_dev.rtc, &counter);
|
||||||
|
rtc_counter_to_ts(counter, &now);
|
||||||
|
|
||||||
|
/* obtain relative time to alarm */
|
||||||
|
|
||||||
|
clock_timespec_subtract(&g_tickless_dev.alarm, &now, &delta);
|
||||||
|
usec = delta.tv_sec * USEC_PER_SEC + delta.tv_nsec / NSEC_PER_USEC;
|
||||||
|
|
||||||
|
/* if the alarm is to expire within one RTC period, we can set the CC */
|
||||||
|
|
||||||
|
if (usec < NRF52_RTC_PERIOD * USEC_PER_SEC)
|
||||||
|
{
|
||||||
|
/* usec is the time w.r.t. now, so we compute the counter compare value
|
||||||
|
* from current counter. as this may be "behind" the counter, we wrap
|
||||||
|
* around one full timer period
|
||||||
|
*/
|
||||||
|
|
||||||
|
target_counter = USEC_TO_COUNTER(usec);
|
||||||
|
|
||||||
|
if (target_counter < 2)
|
||||||
|
{
|
||||||
|
/* ensure counter fires, from nRF52832_PS_v1.4 (p. 245):
|
||||||
|
* "If the COUNTER is N, writing N+2 to a CC register is
|
||||||
|
* guaranteed to trigger a COMPARE event at N+2."
|
||||||
|
*/
|
||||||
|
|
||||||
|
target_counter = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_counter = (counter + target_counter) % (NRF52_RTC_MAX + 1);
|
||||||
|
|
||||||
|
NRF52_RTC_SETCC(g_tickless_dev.rtc, NRF52_RTC_CC0, target_counter);
|
||||||
|
NRF52_RTC_ENABLEINT(g_tickless_dev.rtc, NRF52_RTC_EVT_COMPARE0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: rtc_handler
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int rtc_handler(int irq, void *context, void *arg)
|
||||||
|
{
|
||||||
|
irqstate_t flags;
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
/* if the timer wrapped-around */
|
||||||
|
|
||||||
|
if (getreg32(NRF52_RTC_BASE + NRF52_RTC_EVENTS_OVRFLW_OFFSET))
|
||||||
|
{
|
||||||
|
/* ack interrupt */
|
||||||
|
|
||||||
|
NRF52_RTC_ACKINT(g_tickless_dev.rtc, NRF52_RTC_EVT_OVRFLW);
|
||||||
|
|
||||||
|
/* count one more period */
|
||||||
|
|
||||||
|
g_tickless_dev.periods++;
|
||||||
|
|
||||||
|
/* check if the currently set alarm is to fire in this new period */
|
||||||
|
|
||||||
|
if (g_tickless_dev.alarm_set)
|
||||||
|
{
|
||||||
|
rtc_prepare_alarm();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the compare event fired */
|
||||||
|
|
||||||
|
if (getreg32(NRF52_RTC_BASE + NRF52_RTC_EVENTS_COMPARE_OFFSET(0)))
|
||||||
|
{
|
||||||
|
struct timespec now;
|
||||||
|
|
||||||
|
/* cancel alarm and get current time */
|
||||||
|
|
||||||
|
up_alarm_cancel(&now);
|
||||||
|
|
||||||
|
/* let scheduler now of alarm firing */
|
||||||
|
|
||||||
|
nxsched_alarm_expiration(&now);
|
||||||
|
}
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Public Functions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_alarm_cancel
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_alarm_cancel(FAR struct timespec *ts)
|
||||||
|
{
|
||||||
|
if (g_tickless_dev.alarm_set)
|
||||||
|
{
|
||||||
|
uint32_t counter;
|
||||||
|
irqstate_t flags;
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
NRF52_RTC_DISABLEINT(g_tickless_dev.rtc, NRF52_RTC_EVT_COMPARE0);
|
||||||
|
NRF52_RTC_GETCOUNTER(g_tickless_dev.rtc, &counter);
|
||||||
|
rtc_counter_to_ts(counter, ts);
|
||||||
|
|
||||||
|
NRF52_RTC_ACKINT(g_tickless_dev.rtc, NRF52_RTC_EVT_COMPARE0);
|
||||||
|
g_tickless_dev.alarm_set = false;
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_alarm_start
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_alarm_start(FAR const struct timespec *ts)
|
||||||
|
{
|
||||||
|
irqstate_t flags;
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
/* remember the alarm time */
|
||||||
|
|
||||||
|
g_tickless_dev.alarm_set = true;
|
||||||
|
g_tickless_dev.alarm = *ts;
|
||||||
|
|
||||||
|
rtc_prepare_alarm();
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_timer_gettime
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
int up_timer_gettime(FAR struct timespec *ts)
|
||||||
|
{
|
||||||
|
uint32_t counter;
|
||||||
|
irqstate_t flags;
|
||||||
|
|
||||||
|
flags = enter_critical_section();
|
||||||
|
|
||||||
|
NRF52_RTC_GETCOUNTER(g_tickless_dev.rtc, &counter);
|
||||||
|
rtc_counter_to_ts(counter, ts);
|
||||||
|
|
||||||
|
leave_critical_section(flags);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: up_timer_initialize
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
void up_timer_initialize(void)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
g_tickless_dev.rtc = nrf52_rtc_init(CONFIG_NRF52_SYSTIMER_RTC_INSTANCE);
|
||||||
|
g_tickless_dev.periods = 0;
|
||||||
|
g_tickless_dev.alarm_set = false;
|
||||||
|
|
||||||
|
/* Ensure we have support for the selected RTC instance */
|
||||||
|
|
||||||
|
ASSERT(g_tickless_dev.rtc);
|
||||||
|
|
||||||
|
/* Configure prescaler */
|
||||||
|
|
||||||
|
NRF52_RTC_SETPRE(g_tickless_dev.rtc, 0);
|
||||||
|
|
||||||
|
/* Configure ISR */
|
||||||
|
|
||||||
|
NRF52_RTC_SETISR(g_tickless_dev.rtc, rtc_handler, NULL);
|
||||||
|
|
||||||
|
/* Enable overflow interrupt */
|
||||||
|
|
||||||
|
NRF52_RTC_ENABLEINT(g_tickless_dev.rtc, NRF52_RTC_EVT_OVRFLW);
|
||||||
|
|
||||||
|
/* Start counting */
|
||||||
|
|
||||||
|
NRF52_RTC_CLEAR(g_tickless_dev.rtc);
|
||||||
|
NRF52_RTC_ACKINT(g_tickless_dev.rtc, NRF52_RTC_EVT_OVRFLW);
|
||||||
|
NRF52_RTC_ACKINT(g_tickless_dev.rtc, NRF52_RTC_EVT_COMPARE0);
|
||||||
|
NRF52_RTC_START(g_tickless_dev.rtc);
|
||||||
|
|
||||||
|
/* kick off alarm scheduling */
|
||||||
|
|
||||||
|
ts.tv_sec = ts.tv_nsec = 0;
|
||||||
|
nxsched_alarm_expiration(&ts);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user