Merged in juniskane/nuttx_stm32l4/stm32l1_stm32l4_rtc_update_pr (pull request #514)

STM32L1, STM32L4 RTC: add periodic interrupts, update L1 RTC implementation

* STM32L4 RTC: add support experimental CONFIG_RTC_PERIODIC

* STM32 RTC: separate STM32L1 RTC into a separate file

    STM32L1 RTC is very close to F4 or L4 versions, with two alarms
    and periodic wakeup support so backported L4 peripheral to L1.

* RTC: add periodic alarms to upper and lower halves

Approved-by: Gregory Nutt <gnutt@nuttx.org>
This commit is contained in:
Juha Niskanen 2017-10-20 17:15:17 +00:00 committed by Gregory Nutt
parent 0be36a6ac1
commit 9653255cff
18 changed files with 3328 additions and 111 deletions

View File

@ -200,6 +200,9 @@ CHIP_CSRCS += stm32_rtc.c
ifeq ($(CONFIG_RTC_ALARM),y)
CHIP_CSRCS += stm32_exti_alarm.c
endif
ifeq ($(CONFIG_RTC_PERIODIC),y)
CHIP_CSRCS += stm32_exti_wakeup.c
endif
ifeq ($(CONFIG_RTC_DRIVER),y)
CHIP_CSRCS += stm32_rtc_lowerhalf.c
endif

View File

@ -111,6 +111,29 @@ int stm32_exti_alarm(bool risingedge, bool fallingedge, bool event, xcpt_t func,
void *arg);
#endif
/****************************************************************************
* Name: stm32_exti_wakeup
*
* Description:
* Sets/clears EXTI wakeup interrupt.
*
* Parameters:
* - rising/falling edge: enables interrupt on rising/falling edges
* - event: generate event when set
* - func: when non-NULL, generate interrupt
* - arg: Argument passed to the interrupt callback
*
* Returns:
* Zero (OK) on success; a negated errno value on failure indicating the
* nature of the failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
int stm32_exti_wakeup(bool risingedge, bool fallingedge, bool event,
xcpt_t func, void *arg);
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -0,0 +1,153 @@
/****************************************************************************
* arch/arm/src/stm32/stm32_exti_wakeup.c
*
* Copyright (C) 2009, 2012, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Juha Niskanen <juha.niskanen@haltian.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <arch/irq.h>
#include "up_arch.h"
#include "chip.h"
#include "stm32_gpio.h"
#include "stm32_exti.h"
/****************************************************************************
* Private Data
****************************************************************************/
/* Interrupt handlers attached to the RTC WAKEUP EXTI */
static xcpt_t g_wakeup_callback;
static void *g_callback_arg;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_exti_wakeup_isr
*
* Description:
* EXTI periodic WAKEUP interrupt service routine/dispatcher
*
****************************************************************************/
static int stm32_exti_wakeup_isr(int irq, void *context, FAR void *arg)
{
int ret = OK;
/* Dispatch the interrupt to the handler */
if (g_wakeup_callback != NULL)
{
ret = g_wakeup_callback(irq, context, g_callback_arg);
}
/* Clear the pending EXTI interrupt */
putreg32(EXTI_RTC_WAKEUP, STM32_EXTI_PR);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_exti_wakeup
*
* Description:
* Sets/clears EXTI wakeup interrupt.
*
* Parameters:
* - rising/falling edge: enables interrupt on rising/falling edges
* - event: generate event when set
* - func: when non-NULL, generate interrupt
*
* Returns:
* Zero (OK) on success; a negated errno value on failure indicating the
* nature of the failure.
*
****************************************************************************/
int stm32_exti_wakeup(bool risingedge, bool fallingedge, bool event,
xcpt_t func, void *arg)
{
g_wakeup_callback = func;
g_callback_arg = arg;
/* Install external interrupt handlers (if not already attached) */
if (func)
{
irq_attach(STM32_IRQ_RTC_WKUP, stm32_exti_wakeup_isr, NULL);
up_enable_irq(STM32_IRQ_RTC_WKUP);
}
else
{
up_disable_irq(STM32_IRQ_RTC_WKUP);
}
/* Configure rising/falling edges */
modifyreg32(STM32_EXTI_RTSR,
risingedge ? 0 : EXTI_RTC_WAKEUP,
risingedge ? EXTI_RTC_WAKEUP : 0);
modifyreg32(STM32_EXTI_FTSR,
fallingedge ? 0 : EXTI_RTC_WAKEUP,
fallingedge ? EXTI_RTC_WAKEUP : 0);
/* Enable Events and Interrupts */
modifyreg32(STM32_EXTI_EMR,
event ? 0 : EXTI_RTC_WAKEUP,
event ? EXTI_RTC_WAKEUP : 0);
modifyreg32(STM32_EXTI_IMR,
func ? 0 : EXTI_RTC_WAKEUP,
func ? EXTI_RTC_WAKEUP : 0);
return OK;
}

View File

@ -63,9 +63,11 @@
* the RTCC in these families.
*/
#elif defined(CONFIG_STM32_STM32L15XX) || defined(CONFIG_STM32_STM32F20XX) || \
#elif defined(CONFIG_STM32_STM32F20XX) || \
defined(CONFIG_STM32_STM32F30XX)
# include "stm32_rtcc.c"
#elif defined(CONFIG_STM32_STM32L15XX)
# include "stm32l15xxx_rtcc.c"
#elif defined(CONFIG_STM32_STM32F4XXX)
# include "stm32f40xxx_rtcc.c"
#endif

View File

@ -66,8 +66,10 @@
/* Alarm function differs from part to part */
#ifdef CONFIG_STM32_STM32F4XXX
#if defined(CONFIG_STM32_STM32F4XXX)
# include "stm32f40xxx_alarm.h"
#elif defined(CONFIG_STM32_STM32L15XX)
# include "stm32l15xxx_alarm.h"
#else
# include "stm32_alarm.h"
#endif

View File

@ -33,8 +33,6 @@
*
****************************************************************************/
/* REVISIT: This driver is *not* thread-safe! */
/****************************************************************************
* Included Files
****************************************************************************/
@ -60,7 +58,7 @@
* Pre-processor Definitions
****************************************************************************/
#ifdef CONFIG_STM32_STM32F4XXX
#if defined(CONFIG_STM32_STM32F4XXX) || defined(CONFIG_STM32_STM32L15XX)
# define STM32_NALARMS 2
#else
# define STM32_NALARMS 1
@ -74,8 +72,8 @@
struct stm32_cbinfo_s
{
volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */
volatile FAR void *priv; /* Private argurment to accompany callback */
#ifdef CONFIG_STM32_STM32F4XXX
volatile FAR void *priv; /* Private argument to accompany callback */
#if defined(CONFIG_STM32_STM32F4XXX) || defined(CONFIG_STM32_STM32L15XX)
uint8_t id; /* Identifies the alarm */
#endif
};
@ -97,11 +95,19 @@ struct stm32_lowerhalf_s
* this file.
*/
sem_t devsem; /* Threads can only exclusively access the RTC */
#ifdef CONFIG_RTC_ALARM
/* Alarm callback information */
struct stm32_cbinfo_s cbinfo[STM32_NALARMS];
#endif
#ifdef CONFIG_RTC_PERIODIC
/* Periodic wakeup information */
struct lower_setperiodic_s periodic;
#endif
};
/****************************************************************************
@ -126,6 +132,12 @@ static int stm32_rdalarm(FAR struct rtc_lowerhalf_s *lower,
FAR struct lower_rdalarm_s *alarminfo);
#endif
#ifdef CONFIG_RTC_PERIODIC
static int stm32_setperiodic(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setperiodic_s *alarminfo);
static int stm32_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id);
#endif
/****************************************************************************
* Private Data
****************************************************************************/
@ -142,6 +154,10 @@ static const struct rtc_ops_s g_rtc_ops =
.cancelalarm = stm32_cancelalarm,
.rdalarm = stm32_rdalarm,
#endif
#ifdef CONFIG_RTC_PERIODIC
.setperiodic = stm32_setperiodic,
.cancelperiodic = stm32_cancelperiodic,
#endif
#ifdef CONFIG_RTC_IOCTL
.ioctl = NULL,
#endif
@ -177,7 +193,7 @@ static struct stm32_lowerhalf_s g_rtc_lowerhalf =
****************************************************************************/
#ifdef CONFIG_RTC_ALARM
#ifdef CONFIG_STM32_STM32F4XXX
#if defined(CONFIG_STM32_STM32F4XXX) || defined(CONFIG_STM32_STM32L15XX)
static void stm32_alarm_callback(FAR void *arg, unsigned int alarmid)
{
FAR struct stm32_lowerhalf_s *lower;
@ -232,7 +248,7 @@ static void stm32_alarm_callback(void)
}
}
#endif /* CONFIG_STM32_STM32F4XXX */
#endif /* CONFIG_STM32_STM32F4XXX || CONFIG_STM32_STM32L15XX */
#endif /* CONFIG_RTC_ALARM */
/****************************************************************************
@ -396,11 +412,11 @@ static bool stm32_havesettime(FAR struct rtc_lowerhalf_s *lower)
static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setalarm_s *alarminfo)
{
#ifdef CONFIG_STM32_STM32F4XXX
#if defined(CONFIG_STM32_STM32F4XXX) || defined(CONFIG_STM32_STM32L15XX)
FAR struct stm32_lowerhalf_s *priv;
FAR struct stm32_cbinfo_s *cbinfo;
struct alm_setalarm_s lowerinfo;
int ret = -EINVAL;
int ret;
/* ID0-> Alarm A; ID1 -> Alarm B */
@ -408,6 +424,13 @@ static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower,
DEBUGASSERT(alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB);
priv = (FAR struct stm32_lowerhalf_s *)lower;
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
ret = -EINVAL;
if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB)
{
/* Remember the callback information */
@ -434,16 +457,25 @@ static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower,
}
}
nxsem_post(&priv->devsem);
return ret;
#else
FAR struct stm32_lowerhalf_s *priv;
FAR struct stm32_cbinfo_s *cbinfo;
int ret = -EINVAL;
int ret;
DEBUGASSERT(lower != NULL && alarminfo != NULL && alarminfo->id == 0);
priv = (FAR struct stm32_lowerhalf_s *)lower;
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
ret = -EINVAL;
if (alarminfo->id == 0)
{
struct timespec ts;
@ -469,6 +501,8 @@ static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower,
}
}
nxsem_post(&priv->devsem);
return ret;
#endif
}
@ -495,7 +529,7 @@ static int stm32_setalarm(FAR struct rtc_lowerhalf_s *lower,
static int stm32_setrelative(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setrelative_s *alarminfo)
{
#ifdef CONFIG_STM32_STM32F4XXX
#if defined(CONFIG_STM32_STM32F4XXX) || defined(CONFIG_STM32_STM32L15XX)
struct lower_setalarm_s setalarm;
struct tm time;
time_t seconds;
@ -646,17 +680,24 @@ static int stm32_setrelative(FAR struct rtc_lowerhalf_s *lower,
#ifdef CONFIG_RTC_ALARM
static int stm32_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid)
{
#ifdef CONFIG_STM32_STM32F4XXX
#if defined(CONFIG_STM32_STM32F4XXX) || defined(CONFIG_STM32_STM32L15XX)
FAR struct stm32_lowerhalf_s *priv;
FAR struct stm32_cbinfo_s *cbinfo;
int ret = -EINVAL;
int ret;
DEBUGASSERT(lower != NULL);
DEBUGASSERT(alarmid == RTC_ALARMA || alarmid == RTC_ALARMB);
priv = (FAR struct stm32_lowerhalf_s *)lower;
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
/* ID0-> Alarm A; ID1 -> Alarm B */
ret = -EINVAL;
if (alarmid == RTC_ALARMA || alarmid == RTC_ALARMB)
{
/* Nullify callback information to reduce window for race conditions */
@ -670,6 +711,8 @@ static int stm32_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid)
ret = stm32_rtc_cancelalarm((enum alm_id_e)alarmid);
}
nxsem_post(&priv->devsem);
return ret;
#else
@ -739,6 +782,130 @@ static int stm32_rdalarm(FAR struct rtc_lowerhalf_s *lower,
}
#endif
/****************************************************************************
* Name: stm32_periodic_callback
*
* Description:
* This is the function that is called from the RTC driver when the periodic
* wakeup goes off. It just invokes the upper half drivers callback.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32_periodic_callback(void)
{
FAR struct stm32_lowerhalf_s *lower;
struct lower_setperiodic_s *cbinfo;
rtc_wakeup_callback_t cb;
FAR void *priv;
lower = (FAR struct stm32_lowerhalf_s *)&g_rtc_lowerhalf;
cbinfo = &lower->periodic;
cb = (rtc_wakeup_callback_t)cbinfo->cb;
priv = (FAR void *)cbinfo->priv;
/* Perform the callback */
if (cb != NULL)
{
cb(priv, 0);
}
return OK;
}
#endif /* CONFIG_RTC_PERIODIC */
/****************************************************************************
* Name: stm32_setperiodic
*
* Description:
* Set a new periodic wakeup relative to the current time, with a given
* period. This function implements the setperiodic() method of the RTC
* driver interface
*
* Input Parameters:
* lower - A reference to RTC lower half driver state structure
* alarminfo - Provided information needed to set the wakeup activity
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on any failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32_setperiodic(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setperiodic_s *alarminfo)
{
FAR struct stm32_lowerhalf_s *priv;
int ret;
ASSERT(lower != NULL && alarminfo != NULL);
priv = (FAR struct stm32_lowerhalf_s *)lower;
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
memcpy(&priv->periodic, alarminfo, sizeof(struct lower_setperiodic_s));
ret = stm32_rtc_setperiodic(&alarminfo->period, stm32_periodic_callback);
nxsem_post(&priv->devsem);
return ret;
}
#endif
/****************************************************************************
* Name: stm32_cancelperiodic
*
* Description:
* Cancel the current periodic wakeup activity. This function implements
* the cancelperiodic() method of the RTC driver interface
*
* Input Parameters:
* lower - A reference to RTC lower half driver state structure
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on any failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id)
{
FAR struct stm32_lowerhalf_s *priv;
int ret;
DEBUGASSERT(lower != NULL);
priv = (FAR struct stm32_lowerhalf_s *)lower;
DEBUGASSERT(id == 0);
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
ret = stm32_rtc_cancelperiodic();
nxsem_post(&priv->devsem);
return ret;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -767,6 +934,8 @@ static int stm32_rdalarm(FAR struct rtc_lowerhalf_s *lower,
FAR struct rtc_lowerhalf_s *stm32_rtc_lowerhalf(void)
{
nxsem_init(&g_rtc_lowerhalf.devsem, 0, 1);
return (FAR struct rtc_lowerhalf_s *)&g_rtc_lowerhalf;
}

View File

@ -76,39 +76,11 @@
# error "CONFIG_STM32_PWR must selected to use this driver"
#endif
#ifdef CONFIG_STM32_STM32L15XX
# if defined(CONFIG_RTC_HSECLOCK)
# error "RTC with HSE clock not yet implemented for STM32L15XXX"
# elif defined(CONFIG_RTC_LSICLOCK)
# error "RTC with LSI clock not yet implemented for STM32L15XXX"
# endif
#endif
/* Constants ************************************************************************/
#define SYNCHRO_TIMEOUT (0x00020000)
#define INITMODE_TIMEOUT (0x00010000)
/* Proxy definitions to make the same code work for all the STM32 series ************/
#if defined(CONFIG_STM32_STM32L15XX)
# define STM32_RCC_XXX STM32_RCC_CSR
# define RCC_XXX_YYYRST RCC_CSR_RTCRST
# define RCC_XXX_RTCEN RCC_CSR_RTCEN
# define RCC_XXX_RTCSEL_MASK RCC_CSR_RTCSEL_MASK
# define RCC_XXX_RTCSEL_LSE RCC_CSR_RTCSEL_LSE
# define RCC_XXX_RTCSEL_LSI RCC_CSR_RTCSEL_LSI
# define RCC_XXX_RTCSEL_HSE RCC_CSR_RTCSEL_HSE
#else
# define STM32_RCC_XXX STM32_RCC_BDCR
# define RCC_XXX_YYYRST RCC_BDCR_BDRST
# define RCC_XXX_RTCEN RCC_BDCR_RTCEN
# define RCC_XXX_RTCSEL_MASK RCC_BDCR_RTCSEL_MASK
# define RCC_XXX_RTCSEL_LSE RCC_BDCR_RTCSEL_LSE
# define RCC_XXX_RTCSEL_LSI RCC_BDCR_RTCSEL_LSI
# define RCC_XXX_RTCSEL_HSE RCC_BDCR_RTCSEL_HSE
#endif
/************************************************************************************
* Private Data
************************************************************************************/
@ -534,29 +506,6 @@ static void rtc_resume(void)
#endif
}
/************************************************************************************
* Name: rtc_wkup_interrupt
*
* Description:
* RTC WKUP interrupt service routine through the EXTI line
*
* Input Parameters:
* irq - The IRQ number that generated the interrupt
* context - Architecture specific register save information.
*
* Returned Value:
* Zero (OK) on success; A negated errno value on failure.
*
************************************************************************************/
#ifdef CONFIG_RTC_ALARM
static int rtc_wkup_interrupt(int irq, void *context)
{
#warning "Missing logic"
return OK;
}
#endif
/************************************************************************************
* Public Functions
************************************************************************************/
@ -610,54 +559,54 @@ int up_rtc_initialize(void)
#ifdef CONFIG_RTC_HSECLOCK
/* Use the HSE clock as the input to the RTC block */
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_HSE);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_HSE);
#elif defined(CONFIG_RTC_LSICLOCK)
/* Use the LSI clock as the input to the RTC block */
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSI);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSI);
#elif defined(CONFIG_RTC_LSECLOCK)
/* Use the LSE clock as the input to the RTC block */
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSE);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE);
#endif
/* Enable the RTC Clock by setting the RTCEN bit in the RCC register */
modifyreg32(STM32_RCC_XXX, 0, RCC_XXX_RTCEN);
modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN);
}
else /* The RTC is already in use: check if the clock source is changed */
{
#if defined(CONFIG_RTC_HSECLOCK) || defined(CONFIG_RTC_LSICLOCK) || \
defined(CONFIG_RTC_LSECLOCK)
uint32_t clksrc = getreg32(STM32_RCC_XXX);
uint32_t clksrc = getreg32(STM32_RCC_BDCR);
#if defined(CONFIG_RTC_HSECLOCK)
if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_HSE)
if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL_HSE)
#elif defined(CONFIG_RTC_LSICLOCK)
if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_LSI)
if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL_LSI)
#elif defined(CONFIG_RTC_LSECLOCK)
if ((clksrc & RCC_XXX_RTCSEL_MASK) != RCC_XXX_RTCSEL_LSE)
if ((clksrc & RCC_BDCR_RTCSEL_MASK) != RCC_BDCR_RTCSEL_LSE)
#endif
#endif
{
tr_bkp = getreg32(STM32_RTC_TR);
dr_bkp = getreg32(STM32_RTC_DR);
modifyreg32(STM32_RCC_XXX, 0, RCC_XXX_YYYRST);
modifyreg32(STM32_RCC_XXX, RCC_XXX_YYYRST, 0);
modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_BDRST);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_BDRST, 0);
#if defined(CONFIG_RTC_HSECLOCK)
/* Change to the new clock as the input to the RTC block */
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_HSE);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_HSE);
#elif defined(CONFIG_RTC_LSICLOCK)
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSI);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSI);
#elif defined(CONFIG_RTC_LSECLOCK)
modifyreg32(STM32_RCC_XXX, RCC_XXX_RTCSEL_MASK, RCC_XXX_RTCSEL_LSE);
modifyreg32(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE);
#endif
putreg32(tr_bkp, STM32_RTC_TR);
@ -669,7 +618,7 @@ int up_rtc_initialize(void)
/* Enable the RTC Clock by setting the RTCEN bit in the RCC register */
modifyreg32(STM32_RCC_XXX, 0, RCC_XXX_RTCEN);
modifyreg32(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN);
}
}
@ -786,12 +735,7 @@ int up_rtc_initialize(void)
int stm32_rtc_irqinitialize(void)
{
#ifdef CONFIG_RTC_ALARM
# warning "Missing EXTI setup logic"
/* Attach the ALARM interrupt handler */
irq_attach(STM32_IRQ_RTC_WKUP, rtc_interrupt, NULL);
up_enable_irq(STM32_IRQ_RTC_WKUP);
# warning "Missing logic"
#endif
return OK;

View File

@ -0,0 +1,173 @@
/****************************************************************************
* arch/arm/src/stm32/stm32l15xxx_alarm.h
*
* Copyright (C) 2016-2017 Gregory Nutt. All rights reserved.
* Author: Juha Niskanen <juha.niskanen@haltian.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_STM32_STM32L15XXX_ALARM_H
#define __ARCH_ARM_SRC_STM32_STM32L15XXX_ALARM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <time.h>
/****************************************************************************
* Public Types
****************************************************************************/
#ifdef CONFIG_RTC_ALARM
typedef CODE void (*alm_callback_t)(FAR void *arg, unsigned int alarmid);
/* These features are the same than in STM32F4 and STM32L4 */
enum alm_id_e
{
RTC_ALARMA = 0, /* RTC ALARM A */
RTC_ALARMB, /* RTC ALARM B */
RTC_ALARM_LAST
};
/* Structure used to pass parameters to set an alarm */
struct alm_setalarm_s
{
int as_id; /* enum alm_id_e */
struct tm as_time; /* Alarm expiration time */
alm_callback_t as_cb; /* Callback (if non-NULL) */
FAR void *as_arg; /* Argument for callback */
};
/* Structure used to pass parameters to query an alarm */
struct alm_rdalarm_s
{
int ar_id; /* enum alm_id_e */
FAR struct rtc_time *ar_time; /* Argument for storing ALARM RTC time */
};
#endif
#ifdef CONFIG_RTC_PERIODIC
typedef CODE int (*wakeupcb_t)(void);
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef CONFIG_RTC_ALARM
/****************************************************************************
* Name: stm32_rtc_setalarm
*
* Description:
* Set an alarm to an absolute time using associated hardware.
*
* Input Parameters:
* alminfo - Information about the alarm configuration.
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
int stm32_rtc_setalarm(FAR struct alm_setalarm_s *alminfo);
/************************************************************************************
* Name: stm32_rtc_rdalarm
*
* Description:
* Query an alarm configured in hardware.
*
* Input Parameters:
* alminfo - Information about the alarm configuration.
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
************************************************************************************/
int stm32_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo);
/****************************************************************************
* Name: stm32_rtc_cancelalarm
*
* Description:
* Cancel an alarm.
*
* Input Parameters:
* alarmid - Identifies the alarm to be cancelled
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
int stm32_rtc_cancelalarm(enum alm_id_e alarmid);
#endif /* CONFIG_RTC_ALARM */
#ifdef CONFIG_RTC_PERIODIC
/****************************************************************************
* Name: stm32_rtc_setperiodic
*
* Description:
* Set a periodic RTC wakeup
*
* Input Parameters:
* period - Time to sleep between wakeups
* callback - Function to call when the period expires.
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
int stm32_rtc_setperiodic(FAR const struct timespec *period, wakeupcb_t callback);
/****************************************************************************
* Name: stm32_rtc_cancelperiodic
*
* Description:
* Cancel a periodic wakeup
*
* Input Parameters:
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
int stm32_rtc_cancelperiodic(void);
#endif /* CONFIG_RTC_PERIODIC */
#endif /* __ARCH_ARM_SRC_STM32_STM32L15XXX_ALARM_H */

File diff suppressed because it is too large Load Diff

View File

@ -182,6 +182,9 @@ ifeq ($(CONFIG_RTC),y)
ifeq ($(CONFIG_RTC_ALARM),y)
CHIP_CSRCS += stm32l4_exti_alarm.c
endif
ifeq ($(CONFIG_RTC_PERIODIC),y)
CHIP_CSRCS += stm32l4_exti_wakeup.c
endif
ifeq ($(CONFIG_RTC_DRIVER),y)
CHIP_CSRCS += stm32l4_rtc_lowerhalf.c
CHIP_CSRCS += stm32l4_rtc.c

View File

@ -1016,7 +1016,7 @@ static int adc_timinit(FAR struct stm32_dev_s *priv)
* states. Check if ADC is in progress and if so prevent from entering STOP.
*
****************************************************************************/
#if CONFIG_PM
#ifdef CONFIG_PM
static int adc_pm_prepare(struct pm_callback_s *cb, int domain,
enum pm_state_e state)
{

View File

@ -112,6 +112,29 @@ int stm32l4_exti_alarm(bool risingedge, bool fallingedge, bool event,
xcpt_t func, void *arg);
#endif
/****************************************************************************
* Name: stm32l4_exti_wakeup
*
* Description:
* Sets/clears EXTI wakeup interrupt.
*
* Parameters:
* - rising/falling edge: enables interrupt on rising/falling edges
* - event: generate event when set
* - func: when non-NULL, generate interrupt
* - arg: Argument passed to the interrupt callback
*
* Returns:
* Zero (OK) on success; a negated errno value on failure indicating the
* nature of the failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
int stm32l4_exti_wakeup(bool risingedge, bool fallingedge, bool event,
xcpt_t func, void *arg);
#endif
/****************************************************************************
* Name: stm32l4_exti_comp
*
@ -120,7 +143,7 @@ int stm32l4_exti_alarm(bool risingedge, bool fallingedge, bool event,
*
* Parameters:
* - cmp: comparator
* - rising/falling edge: enables interrupt on rising/falling edget
* - rising/falling edge: enables interrupt on rising/falling edges
* - event: generate event when set
* - func: when non-NULL, generate interrupt
* - arg: Argument passed to the interrupt callback

View File

@ -0,0 +1,153 @@
/****************************************************************************
* arch/arm/src/stm32l4/stm32l4_exti_wakeup.c
*
* Copyright (C) 2009, 2012, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* Juha Niskanen <juha.niskanen@haltian.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <stdint.h>
#include <stdbool.h>
#include <errno.h>
#include <arch/irq.h>
#include "up_arch.h"
#include "chip.h"
#include "stm32l4_gpio.h"
#include "stm32l4_exti.h"
/****************************************************************************
* Private Data
****************************************************************************/
/* Interrupt handlers attached to the RTC WAKEUP EXTI */
static xcpt_t g_wakeup_callback;
static void *g_callback_arg;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: stm32l4_exti_wakeup_isr
*
* Description:
* EXTI periodic WAKEUP interrupt service routine/dispatcher
*
****************************************************************************/
static int stm32l4_exti_wakeup_isr(int irq, void *context, FAR void *arg)
{
int ret = OK;
/* Dispatch the interrupt to the handler */
if (g_wakeup_callback != NULL)
{
ret = g_wakeup_callback(irq, context, g_callback_arg);
}
/* Clear the pending EXTI interrupt */
putreg32(EXTI1_RTC_WAKEUP, STM32L4_EXTI1_PR);
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32l4_exti_wakeup
*
* Description:
* Sets/clears EXTI wakeup interrupt.
*
* Parameters:
* - rising/falling edge: enables interrupt on rising/falling edges
* - event: generate event when set
* - func: when non-NULL, generate interrupt
*
* Returns:
* Zero (OK) on success; a negated errno value on failure indicating the
* nature of the failure.
*
****************************************************************************/
int stm32l4_exti_wakeup(bool risingedge, bool fallingedge, bool event,
xcpt_t func, void *arg)
{
g_wakeup_callback = func;
g_callback_arg = arg;
/* Install external interrupt handlers (if not already attached) */
if (func)
{
irq_attach(STM32L4_IRQ_RTC_WKUP, stm32l4_exti_wakeup_isr, NULL);
up_enable_irq(STM32L4_IRQ_RTC_WKUP);
}
else
{
up_disable_irq(STM32L4_IRQ_RTC_WKUP);
}
/* Configure rising/falling edges */
modifyreg32(STM32L4_EXTI1_RTSR,
risingedge ? 0 : EXTI1_RTC_WAKEUP,
risingedge ? EXTI1_RTC_WAKEUP : 0);
modifyreg32(STM32L4_EXTI1_FTSR,
fallingedge ? 0 : EXTI1_RTC_WAKEUP,
fallingedge ? EXTI1_RTC_WAKEUP : 0);
/* Enable Events and Interrupts */
modifyreg32(STM32L4_EXTI1_EMR,
event ? 0 : EXTI1_RTC_WAKEUP,
event ? EXTI1_RTC_WAKEUP : 0);
modifyreg32(STM32L4_EXTI1_IMR,
func ? 0 : EXTI1_RTC_WAKEUP,
func ? EXTI1_RTC_WAKEUP : 0);
return OK;
}

View File

@ -4,6 +4,7 @@
* Copyright (C) 2012-2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
* dev@ziggurat29.com (adaptations to stm32l4)
* Juha Niskanen <juha.niskanen@haltian.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -131,6 +132,11 @@ static struct alm_cbinfo_s g_alarmcb[RTC_ALARM_LAST];
static bool g_alarm_enabled; /* True: Alarm interrupts are enabled */
#endif
#ifdef CONFIG_RTC_PERIODIC
static wakeupcb_t g_wakeupcb;
static bool g_wakeup_enabled; /* True: Wakeup interrupts are enabled */
#endif
/****************************************************************************
* Public Data
****************************************************************************/
@ -1601,4 +1607,273 @@ int stm32l4_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo)
}
#endif
/****************************************************************************
* Name: stm32l4_rtc_wakeup_handler
*
* Description:
* RTC WAKEUP interrupt service routine through the EXTI line
*
* Input Parameters:
* irq - The IRQ number that generated the interrupt
*
* Returned Value:
* Zero (OK) on success; A negated errno value on failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32l4_rtc_wakeup_handler(int irq, FAR void *context, FAR void *arg)
{
uint32_t regval = 0;
(void)stm32l4_pwr_enablebkp(true);
regval = getreg32(STM32L4_RTC_ISR);
regval &= ~RTC_ISR_WUTF;
putreg32(regval, STM32L4_RTC_ISR);
(void)stm32l4_pwr_enablebkp(false);
if (g_wakeupcb != NULL)
{
g_wakeupcb();
}
return OK;
}
#endif
/****************************************************************************
* Name: rtc_enable_wakeup
*
* Description:
* Enable periodic wakeup interrupts
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static inline void rtc_enable_wakeup(void)
{
if (!g_wakeup_enabled)
{
(void)stm32l4_exti_wakeup(true, false, true, stm32l4_rtc_wakeup_handler, NULL);
g_wakeup_enabled = true;
}
}
#endif
/************************************************************************************
* Name: rtc_set_wcksel
*
* Description:
* Sets RTC wakeup clock selection value
*
************************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static inline void rtc_set_wcksel(unsigned int wucksel)
{
uint32_t regval = 0;
regval = getreg32(STM32L4_RTC_CR);
regval &= ~RTC_CR_WUCKSEL_MASK;
regval |= wucksel;
putreg32(regval, STM32L4_RTC_CR);
}
#endif
/****************************************************************************
* Name: stm32l4_rtc_setperiodic
*
* Description:
* Set a periodic RTC wakeup
*
* Input Parameters:
* period - Time to sleep between wakeups
* callback - Function to call when the period expires.
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
int stm32l4_rtc_setperiodic(FAR const struct timespec *period, wakeupcb_t callback)
{
unsigned int wutr_val;
int ret;
int timeout;
uint32_t regval;
uint32_t secs;
uint32_t millisecs;
#if defined(CONFIG_STM32L4_RTC_HSECLOCK)
# error "Periodic wakeup not available for HSE"
#elif defined(CONFIG_STM32L4_RTC_LSICLOCK)
# error "Periodic wakeup not available for LSI (and it is too inaccurate!)"
#elif defined(CONFIG_STM32L4_RTC_LSECLOCK)
const uint32_t rtc_div16_max_msecs = 16 * 1000 * 0xffffU / STM32L4_LSE_FREQUENCY;
#else
# error "No clock for RTC!"
#endif
/* Lets use RTC wake-up with 0.001 sec to ~18 hour range.
*
* TODO: scale to higher periods, with necessary losing some precision.
* We currently go for subseconds accuracy instead of maximum period.
*/
if (period->tv_sec > 0xffffU ||
(period->tv_sec == 0xffffU && period->tv_nsec > 0))
{
/* More than max. */
secs = 0xffffU;
millisecs = secs * 1000;
}
else
{
secs = period->tv_sec;
millisecs = secs * 1000 + period->tv_nsec / NSEC_PER_MSEC;
}
if (millisecs == 0)
{
return -EINVAL;
}
/* Make sure the alarm interrupt is enabled at the NVIC */
rtc_enable_wakeup();
rtc_wprunlock();
/* Clear WUTE in RTC_CR to disable the wakeup timer */
regval = getreg32(STM32L4_RTC_CR);
regval &= ~RTC_CR_WUTE;
putreg32(regval, STM32L4_RTC_CR);
/* Poll WUTWF until it is set in RTC_ISR (takes around 2 RTCCLK clock cycles) */
ret = -ETIMEDOUT;
for (timeout = 0; timeout < SYNCHRO_TIMEOUT; timeout++)
{
regval = getreg32(STM32L4_RTC_ISR);
if ((regval & RTC_ISR_WUTWF) != 0)
{
/* Synchronized */
ret = OK;
break;
}
}
/* Set callback function pointer. */
g_wakeupcb = callback;
if (millisecs <= rtc_div16_max_msecs)
{
unsigned int ticks;
/* Select wake-up with 32768/16 hz counter. */
rtc_set_wcksel(RTC_CR_WUCKSEL_RTCDIV16);
/* Get number of ticks. */
ticks = millisecs * STM32L4_LSE_FREQUENCY / (16 * 1000);
/* Wake-up is after WUT+1 ticks. */
wutr_val = ticks - 1;
}
else
{
/* Select wake-up with 1hz counter. */
rtc_set_wcksel(RTC_CR_WUCKSEL_CKSPRE);
/* Wake-up is after WUT+1 ticks. */
wutr_val = secs - 1;
}
/* Program the wakeup auto-reload value WUT[15:0], and the wakeup clock
* selection.
*/
putreg32(wutr_val, STM32L4_RTC_WUTR);
regval = getreg32(STM32L4_RTC_CR);
regval |= RTC_CR_WUTIE | RTC_CR_WUTE;
putreg32(regval, STM32L4_RTC_CR);
/* Just in case resets the WUTF flag in RTC_ISR */
regval = getreg32(STM32L4_RTC_ISR);
regval &= ~RTC_ISR_WUTF;
putreg32(regval, STM32L4_RTC_ISR);
rtc_wprlock();
return ret;
}
#endif
/****************************************************************************
* Name: stm32l4_rtc_cancelperiodic
*
* Description:
* Cancel a periodic wakeup
*
* Input Parameters:
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
int stm32l4_rtc_cancelperiodic(void)
{
int ret = OK;
int timeout = 0;
uint32_t regval = 0;
rtc_wprunlock();
/* Clear WUTE and WUTIE in RTC_CR to disable the wakeup timer */
regval = getreg32(STM32L4_RTC_CR);
regval &= ~(RTC_CR_WUTE | RTC_CR_WUTIE);
putreg32(regval, STM32L4_RTC_CR);
/* Poll WUTWF until it is set in RTC_ISR (takes around 2 RTCCLK clock cycles) */
ret = -ETIMEDOUT;
for (timeout = 0; timeout < SYNCHRO_TIMEOUT; timeout++)
{
regval = getreg32(STM32L4_RTC_ISR);
if ((regval & RTC_ISR_WUTWF) != 0)
{
/* Synchronized */
ret = OK;
break;
}
}
/* Clears RTC_WUTR register */
regval = getreg32(STM32L4_RTC_WUTR);
regval &= ~RTC_WUTR_MASK;
putreg32(regval, STM32L4_RTC_WUTR);
rtc_wprlock();
return ret;
}
#endif
#endif /* CONFIG_RTC */

View File

@ -96,6 +96,10 @@ struct alm_rdalarm_s
#endif /* CONFIG_RTC_ALARM */
#ifdef CONFIG_RTC_PERIODIC
typedef CODE int (*wakeupcb_t)(void);
#endif
/****************************************************************************
* Public Data
****************************************************************************/
@ -195,7 +199,7 @@ bool stm32l4_rtc_havesettime(void);
* Name: stm32l4_rtc_setalarm
*
* Description:
* Set an alarm to an asbolute time using associated hardware.
* Set an alarm to an absolute time using associated hardware.
*
* Input Parameters:
* alminfo - Information about the alarm configuration.
@ -227,7 +231,7 @@ int stm32l4_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo);
* Name: stm32l4_rtc_cancelalarm
*
* Description:
* Cancel an alaram.
* Cancel an alarm.
*
* Input Parameters:
* alarmid - Identifies the alarm to be cancelled
@ -240,6 +244,41 @@ int stm32l4_rtc_rdalarm(FAR struct alm_rdalarm_s *alminfo);
int stm32l4_rtc_cancelalarm(enum alm_id_e alarmid);
#endif /* CONFIG_RTC_ALARM */
#ifdef CONFIG_RTC_PERIODIC
/****************************************************************************
* Name: stm32l4_rtc_setperiodic
*
* Description:
* Set a periodic RTC wakeup
*
* Input Parameters:
* period - Time to sleep between wakeups
* callback - Function to call when the period expires.
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
int stm32l4_rtc_setperiodic(FAR const struct timespec *period, wakeupcb_t callback);
/****************************************************************************
* Name: stm32l4_rtc_cancelperiodic
*
* Description:
* Cancel a periodic wakeup
*
* Input Parameters:
*
* Returned Value:
* Zero (OK) on success; a negated errno on failure
*
****************************************************************************/
int stm32l4_rtc_cancelperiodic(void);
#endif /* CONFIG_RTC_PERIODIC */
/****************************************************************************
* Name: stm32l4_rtc_lowerhalf
*

View File

@ -67,7 +67,7 @@
struct stm32l4_cbinfo_s
{
volatile rtc_alarm_callback_t cb; /* Callback when the alarm expires */
volatile FAR void *priv; /* Private argurment to accompany callback */
volatile FAR void *priv; /* Private argument to accompany callback */
uint8_t id; /* Identifies the alarm */
};
#endif
@ -95,6 +95,12 @@ struct stm32l4_lowerhalf_s
struct stm32l4_cbinfo_s cbinfo[STM32L4_NALARMS];
#endif
#ifdef CONFIG_RTC_PERIODIC
/* Periodic wakeup information */
struct lower_setperiodic_s periodic;
#endif
};
/****************************************************************************
@ -111,13 +117,19 @@ static bool stm32l4_havesettime(FAR struct rtc_lowerhalf_s *lower);
#ifdef CONFIG_RTC_ALARM
static int stm32l4_setalarm(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setalarm_s *alarminfo);
FAR const struct lower_setalarm_s *alarminfo);
static int stm32l4_setrelative(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setrelative_s *alarminfo);
FAR const struct lower_setrelative_s *alarminfo);
static int stm32l4_cancelalarm(FAR struct rtc_lowerhalf_s *lower,
int alarmid);
int alarmid);
static int stm32l4_rdalarm(FAR struct rtc_lowerhalf_s *lower,
FAR struct lower_rdalarm_s *alarminfo);
FAR struct lower_rdalarm_s *alarminfo);
#endif
#ifdef CONFIG_RTC_PERIODIC
static int stm32l4_setperiodic(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setperiodic_s *alarminfo);
static int stm32l4_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id);
#endif
/****************************************************************************
@ -137,6 +149,10 @@ static const struct rtc_ops_s g_rtc_ops =
.cancelalarm = stm32l4_cancelalarm,
.rdalarm = stm32l4_rdalarm,
#endif
#ifdef CONFIG_RTC_PERIODIC
.setperiodic = stm32l4_setperiodic,
.cancelperiodic = stm32l4_cancelperiodic,
#endif
#ifdef CONFIG_RTC_IOCTL
.ioctl = NULL,
#endif
@ -271,11 +287,11 @@ static int stm32l4_settime(FAR struct rtc_lowerhalf_s *lower,
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
{
return ret;
}
/* This operation depends on the fact that struct rtc_time is cast
/* This operation depends on the fact that struct rtc_time is cast
* compatible with struct tm.
*/
@ -339,9 +355,9 @@ static int stm32l4_setalarm(FAR struct rtc_lowerhalf_s *lower,
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
{
return ret;
}
ret = -EINVAL;
if (alarminfo->id == RTC_ALARMA || alarminfo->id == RTC_ALARMB)
@ -479,9 +495,9 @@ static int stm32l4_cancelalarm(FAR struct rtc_lowerhalf_s *lower, int alarmid)
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
{
return ret;
}
/* ID0-> Alarm A; ID1 -> Alarm B */
@ -551,6 +567,131 @@ static int stm32l4_rdalarm(FAR struct rtc_lowerhalf_s *lower,
}
#endif
/****************************************************************************
* Name: stm32l4_periodic_callback
*
* Description:
* This is the function that is called from the RTC driver when the periodic
* wakeup goes off. It just invokes the upper half drivers callback.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32l4_periodic_callback(void)
{
FAR struct stm32l4_lowerhalf_s *lower;
struct lower_setperiodic_s *cbinfo;
rtc_wakeup_callback_t cb;
FAR void *priv;
lower = (FAR struct stm32l4_lowerhalf_s *)&g_rtc_lowerhalf;
cbinfo = &lower->periodic;
cb = (rtc_wakeup_callback_t)cbinfo->cb;
priv = (FAR void *)cbinfo->priv;
/* Perform the callback */
if (cb != NULL)
{
cb(priv, 0);
}
return OK;
}
#endif /* CONFIG_RTC_PERIODIC */
/****************************************************************************
* Name: stm32l4_setperiodic
*
* Description:
* Set a new periodic wakeup relative to the current time, with a given
* period. This function implements the setperiodic() method of the RTC
* driver interface
*
* Input Parameters:
* lower - A reference to RTC lower half driver state structure
* alarminfo - Provided information needed to set the wakeup activity
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on any failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32l4_setperiodic(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setperiodic_s *alarminfo)
{
FAR struct stm32l4_lowerhalf_s *priv;
int ret;
ASSERT(lower != NULL && alarminfo != NULL);
priv = (FAR struct stm32l4_lowerhalf_s *)lower;
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
memcpy(&priv->periodic, alarminfo, sizeof(struct lower_setperiodic_s));
ret = stm32l4_rtc_setperiodic(&alarminfo->period, stm32l4_periodic_callback);
nxsem_post(&priv->devsem);
return ret;
}
#endif
/****************************************************************************
* Name: stm32l4_cancelperiodic
*
* Description:
* Cancel the current periodic wakeup activity. This function implements
* the cancelperiodic() method of the RTC driver interface
*
* Input Parameters:
* lower - A reference to RTC lower half driver state structure
*
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned
* on any failure.
*
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static int stm32l4_cancelperiodic(FAR struct rtc_lowerhalf_s *lower, int id)
{
FAR struct stm32l4_lowerhalf_s *priv;
int ret;
DEBUGASSERT(lower != NULL);
priv = (FAR struct stm32l4_lowerhalf_s *)lower;
DEBUGASSERT(id == 0);
ret = nxsem_wait(&priv->devsem);
if (ret < 0)
{
return ret;
}
ret = stm32l4_rtc_cancelperiodic();
nxsem_post(&priv->devsem);
return ret;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/

View File

@ -54,7 +54,7 @@
* Private Types
****************************************************************************/
#ifdef CONFIG_RTC_ALARM
#if defined(CONFIG_RTC_ALARM) || defined(CONFIG_RTC_PERIODIC)
struct rtc_alarminfo_s
{
bool active; /* True: alarm is active */
@ -80,6 +80,12 @@ struct rtc_upperhalf_s
struct rtc_alarminfo_s alarminfo[CONFIG_RTC_NALARMS];
#endif
#ifdef CONFIG_RTC_PERIODIC
/* Currently only one periodic wakeup is supported. */
struct rtc_alarminfo_s periodicinfo;
#endif
};
/****************************************************************************
@ -96,6 +102,10 @@ static void rtc_destroy(FAR struct rtc_upperhalf_s *upper);
static void rtc_alarm_callback(FAR void *priv, int id);
#endif
#ifdef CONFIG_RTC_PERIODIC
static void rtc_periodic_callback(FAR void *priv, int id);
#endif
/* Character driver methods */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
@ -203,6 +213,43 @@ static void rtc_alarm_callback(FAR void *priv, int alarmid)
}
#endif
/****************************************************************************
* Name: rtc_periodic_callback
****************************************************************************/
#ifdef CONFIG_RTC_PERIODIC
static void rtc_periodic_callback(FAR void *priv, int alarmid)
{
FAR struct rtc_upperhalf_s *upper = (FAR struct rtc_upperhalf_s *)priv;
FAR struct rtc_alarminfo_s *alarminfo;
DEBUGASSERT(upper != NULL && alarmid >= 0);
alarminfo = &upper->periodicinfo;
/* Do we think that the alarm is active? It might be due to some
* race condition between a cancellation event and the alarm
* expiration.
*/
if (alarminfo->active)
{
/* Yes.. signal the alarm expiration */
#ifdef CONFIG_CAN_PASS_STRUCTS
(void)nxsig_queue(alarminfo->pid, alarminfo->signo,
alarminfo->sigvalue);
#else
(void)nxsig_queue(alarminfo->pid, alarminfo->signo,
alarminfo->sigvalue->sival_ptr);
#endif
}
/* The alarm is no longer active */
alarminfo->active = false;
}
#endif
/****************************************************************************
* Name: rtc_open
****************************************************************************/
@ -573,6 +620,105 @@ static int rtc_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
break;
#endif /* CONFIG_RTC_ALARM */
#ifdef CONFIG_RTC_PERIODIC
/* RTC_SET_PERIODIC set a periodic wakeup.
*
* Argument: A read-only reference to a struct rtc_setperiodic_s containing the
* new wakeup period to be set.
*/
case RTC_SET_PERIODIC:
{
FAR const struct rtc_setperiodic_s *alarminfo =
(FAR const struct rtc_setperiodic_s *)((uintptr_t)arg);
FAR struct rtc_alarminfo_s *upperinfo;
struct lower_setperiodic_s lowerinfo;
int id;
DEBUGASSERT(alarminfo != NULL);
id = alarminfo->id;
DEBUGASSERT(id >= 0);
/* Is the alarm active? */
upperinfo = &upper->periodicinfo;
if (upperinfo->active)
{
/* Yes, cancel it */
if (ops->cancelperiodic)
{
(void)ops->cancelperiodic(upper->lower, id);
}
upperinfo->active = false;
}
if (ops->setperiodic)
{
pid_t pid;
/* A PID of zero means to signal the calling task */
pid = alarminfo->pid;
if (pid == 0)
{
pid = getpid();
}
/* Save the signal info to be used to notify the caller when the
* alarm expires.
*/
upperinfo->active = true;
upperinfo->signo = alarminfo->signo;
upperinfo->pid = pid;
upperinfo->sigvalue = alarminfo->sigvalue;
/* Format the alarm info needed by the lower half driver. */
lowerinfo.id = id;
lowerinfo.cb = rtc_periodic_callback;
lowerinfo.priv = (FAR void *)upper;
lowerinfo.period = alarminfo->period;
/* Then set the periodic wakeup. */
ret = ops->setperiodic(upper->lower, &lowerinfo);
if (ret < 0)
{
upperinfo->active = false;
}
}
}
break;
/* RTC_CANCEL_PERIODIC cancel the periodic wakeup.
*
* Argument: An ID value that indicates which wakeup should be canceled.
*/
case RTC_CANCEL_PERIODIC:
{
FAR struct rtc_alarminfo_s *upperinfo;
int id = (int)arg;
DEBUGASSERT(id >= 0);
upperinfo = &upper->periodicinfo;
if (ops->cancelperiodic)
{
ret = ops->cancelperiodic(upper->lower, id);
if (ret == OK)
{
upperinfo->active = false;
}
}
}
break;
#endif /* CONFIG_RTC_PERIODIC */
/* Forward any unrecognized IOCTLs to the lower half driver... they
* may represent some architecture-specific command.
*/

View File

@ -51,6 +51,7 @@
#include <stdbool.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <nuttx/fs/ioctl.h>
@ -90,6 +91,10 @@
* CONFIG_RTC_ALARM - Enable if the RTC hardware supports setting of an
* alarm. A callback function will be executed when the alarm goes off
*
* CONFIG_RTC_PERIODIC - Enable if the RTC hardware supports setting a
* periodic wakeup. A callback function will be executed when the wakeup happens.
* This is an experimental feature.
*
* CONFIG_RTC_DRIVER - Enable building the upper-half RTC driver
*/
@ -170,7 +175,7 @@
#define RTC_SET_RELATIVE _RTCIOC(0x0005)
/* RTC_SET_RELATIVE cancel the alarm.
/* RTC_CANCEL_ALARM cancel the alarm.
*
* Argument: An ALARM ID value that indicates which alarm should be canceled.
*/
@ -184,6 +189,21 @@
#define RTC_RD_ALARM _RTCIOC(0x0007)
/* RTC_SET_PERIODIC set a periodic wakeup.
*
* Argument: A read-only reference to a struct rtc_setperiodic_s containing the
* new wakeup period to be set.
*/
#define RTC_SET_PERIODIC _RTCIOC(0x0008)
/* RTC_CANCEL_PERIODIC cancel the periodic wakeup.
*
* Argument: An ID value that indicates which wakeup should be canceled.
*/
#define RTC_CANCEL_PERIODIC _RTCIOC(0x0009)
/* Architecture-specific RTC IOCTLS should begin at RTC_USER_IOCBASE. For
* example:
*
@ -192,7 +212,7 @@
* etc.
*/
#define RTC_USER_IOCBASE 0x0008
#define RTC_USER_IOCBASE 0x000a
/****************************************************************************
@ -268,7 +288,7 @@ struct lower_setalarm_s
{
uint8_t id; /* Indicates the alarm to be set */
rtc_alarm_callback_t cb; /* Callback when the alarm expires */
FAR void *priv; /* Private argurment to accompany callback */
FAR void *priv; /* Private argument to accompany callback */
struct rtc_time time; /* Alarm time */
};
@ -278,7 +298,7 @@ struct lower_setrelative_s
{
uint8_t id; /* Indicates the alarm to be set */
rtc_alarm_callback_t cb; /* Callback when the alarm expires */
FAR void *priv; /* Private argurment to accompany callback */
FAR void *priv; /* Private argument to accompany callback */
time_t reltime; /* Relative time in seconds */
};
@ -287,11 +307,42 @@ struct lower_setrelative_s
struct lower_rdalarm_s
{
uint8_t id; /* Indicates the alarm to be set */
FAR void *priv; /* Private argurment to accompany callback */
FAR void *priv; /* Private argument to accompany callback */
FAR struct rtc_time *time;/* Queried RTC time pointer */
};
#endif
#ifdef CONFIG_RTC_PERIODIC
/* Structure used with the RTC_SET_PERIODIC IOCTL command. */
struct rtc_setperiodic_s
{
uint8_t id; /* Indicates the alarm to be set */
uint8_t signo; /* Signal number for alarm notification */
pid_t pid; /* Identifies task to be notified (0=caller) */
union sigval sigvalue; /* Data passed with notification */
struct timespec period; /* Period between wakeups */
};
/* Callback type used by the RTC harware to notify the RTC driver when the
* wakeup period expires.
*/
typedef CODE void (*rtc_wakeup_callback_t)(FAR void *priv, int alarmid);
/* Structure used with the setperiodic method */
struct lower_setperiodic_s
{
uint8_t id; /* Indicates the wakeup to be set */
rtc_wakeup_callback_t cb; /* Callback when the wakeup expires */
FAR void *priv; /* Private argument to accompany callback */
struct timespec period; /* Period between wakeups */
};
#endif
/* The RTC driver is implemented as a common, upper-half character driver
* that provides the RTC driver structure and a lower-level, hardware
* specific implementation that performs the actual RTC operations.
@ -342,6 +393,17 @@ struct rtc_ops_s
FAR struct lower_rdalarm_s *alarminfo);
#endif
#ifdef CONFIG_RTC_PERIODIC
/* setperiodic sets up a new periodic wakeup. */
CODE int (*setperiodic)(FAR struct rtc_lowerhalf_s *lower,
FAR const struct lower_setperiodic_s *alarminfo);
/* cancelperiodic cancels the current periodic wakeup. */
CODE int (*cancelperiodic)(FAR struct rtc_lowerhalf_s *lower, int alarmid);
#endif
#ifdef CONFIG_RTC_IOCTL
/* Support for architecture-specific RTC operations */