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:
parent
0be36a6ac1
commit
9653255cff
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
|
153
arch/arm/src/stm32/stm32_exti_wakeup.c
Normal file
153
arch/arm/src/stm32/stm32_exti_wakeup.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
173
arch/arm/src/stm32/stm32l15xxx_alarm.h
Normal file
173
arch/arm/src/stm32/stm32l15xxx_alarm.h
Normal 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 */
|
1906
arch/arm/src/stm32/stm32l15xxx_rtcc.c
Normal file
1906
arch/arm/src/stm32/stm32l15xxx_rtcc.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
153
arch/arm/src/stm32l4/stm32l4_exti_wakeup.c
Normal file
153
arch/arm/src/stm32l4/stm32l4_exti_wakeup.c
Normal 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;
|
||||
}
|
@ -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 */
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user