summaryrefslogtreecommitdiffstats
path: root/nuttx
diff options
context:
space:
mode:
authorpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2011-10-01 22:09:00 +0000
committerpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2011-10-01 22:09:00 +0000
commit4762f40a5e30c0c2a82c272557645476f7ec2aad (patch)
tree9bf8b7599be1785b828c91655da7510937c92303 /nuttx
parente468782ea0173ac6241b8d737ae36b79588fd824 (diff)
Add support for lo- and hi-res RTC hardware
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4005 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/ChangeLog5
-rw-r--r--nuttx/Documentation/NuttxPortingGuide.html69
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_i2c.c3
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_rtc.c614
-rwxr-xr-xnuttx/configs/vsn/nsh/defconfig1
-rw-r--r--nuttx/configs/vsn/src/sif.c5
-rw-r--r--nuttx/include/nuttx/clock.h2
-rw-r--r--nuttx/include/nuttx/rtc.h131
-rw-r--r--nuttx/include/time.h2
-rw-r--r--nuttx/sched/clock_gettime.c57
-rw-r--r--nuttx/sched/clock_initialize.c116
-rw-r--r--nuttx/sched/clock_settime.c30
-rw-r--r--nuttx/sched/clock_systimer.c14
13 files changed, 746 insertions, 303 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index d1557285cf..d774bb48ce 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -2121,3 +2121,8 @@
* configs/sam3u/touchscreen - This is the configuration that I plan to use
to verify the SAM3U-EK touchscreen driver. However, as of this writing,
there is no touchscreen driver for the board.
+ * CONFIG_RTC_HIRES - Add an option to support either a high-resolution RTC
+ that completely replaces the system timer tick but may overflow and lose
+ time when the MCU is off and also for a low-resolution (1 sec/tick) RTC
+ that can run until 2106 with no overflow. But in this latter case, higher
+ resolution time must come from the system timer.
diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html
index 20f6778ca8..d05eea2396 100644
--- a/nuttx/Documentation/NuttxPortingGuide.html
+++ b/nuttx/Documentation/NuttxPortingGuide.html
@@ -12,7 +12,7 @@
<h1><big><font color="#3c34ec">
<i>NuttX RTOS Porting Guide</i>
</font></big></h1>
- <p>Last Updated: September 13, 2011</p>
+ <p>Last Updated: October 1, 2011</p>
</td>
</tr>
</table>
@@ -1989,18 +1989,30 @@ CONFIG_SYSTEM_UTC=y
<h4>4.1.20.2 Hardware</h4>
<p>
- To enable hardware module use option:
-<p>
-<ul><pre>
-CONFIG_RTC=y
-</pre></ul>
+ To enable hardware module use the following configuration options:
+<p>
+<ul><dl>
+ <dt><code>CONFIG_RTC</code>
+ <dd>Enables general support for a hardware RTC.
+ Specific architectures may require other specific settings.
+ <dt><code>CONFIG_RTC_HIRES</code>
+ <dd>The typical RTC keeps time to resolution of 1 second, usually supporting a 32-bit <code>time_t</code> value.
+ In this case, the RTC is used to &quot;seed&quot; the normal NuttX timer and the NuttX timer provides for higher resoution time.
+ If <code>CONFIG_RTC_HIRES</code> is enabled in the NuttX configuration, then the RTC provides higher resolution time and completely replaces the system timer for purpose of date and time.
+ <dt><code>CONFIG_RTC_FREQUENCY</code>
+ <dd>If <code>CONFIG_RTC_HIRES</code> is defined, then the frequency of the high resolution RTC must be provided.
+ If <code>CONFIG_RTC_HIRES</code> is not defined, <code>CONFIG_RTC_FREQUENCY</code> is assumed to be one.
+ <dt><code>CONFIG_RTC_ALARM</code>
+ <dd>Enable if the RTC hardware supports setting of an alarm.
+ A callback function will be executed when the alarm goes off
+</dl></ul>
<p>
which requires the following three base functions to read time:
</p>
<ul>
<li><code>up_rtcinitialize()</code></li>
- <li><code>up_rtc_gettime()</code>. UTC time in seconds.</li>
- <li><code>up_rtc_getclock()</code>. Replacement for <code>g_system_tick</code></li>
+ <li><code>up_rtc_time()</code>. UTC time in seconds.</li>
+ <li><code>up_rtc_gettime()</code>. Replacement for <code>g_system_tick</code></li>
</ul>
<p>
This module depends on <code>CONFIG_SYSTEM_UTC=y</code>.
@@ -2024,15 +2036,17 @@ CONFIG_RTC=y
Running at rate of system base timer, used for time-slicing, and so forth.
</p>
<p>
- If hardware RTC is present (<code>CONFIG_RTC</code>) and enabled, then after successful
- initiliazation variables are overriden by calls to <code>up_rtc_getclock()</code> which is
+ If hardware RTC is present (<code>CONFIG_RTC</code>) and and high-resolution timeing
+ is enabled (<code>CONFIG_RTC_HIRES</code>), then after successful
+ initiliazation variables are overriden by calls to <code>up_rtc_gettime()</code> which is
running continously even in power-down modes.
</p>
<p>
- In the case of <code>CONFIG_RTC</code> is set the <code>g_tickcount</code> and <code>g_system_utc</code> keep
- counting at rate of a system timer, which however, is disabled in power-down
- mode. By comparing this time and RTC (actual time) one may determine the
- actual system active time. To retrieve that variable use:
+ In the case of <code>CONFIG_RTC_HIRES</code> is set the <code>g_tickcount</code> and
+ <code>g_system_utc</code> keep counting at rate of a system timer, which however, is
+ disabled in power-down mode.
+ By comparing this time and RTC (actual time) one may determine the actual system active time.
+ To retrieve that variable use:
</p>
<ul><pre>
<li><code>clock_gettime(CLOCK_ACTIVETIME, tp)</code>
@@ -4239,10 +4253,35 @@ build
</ul>
<h2>Device Drivers</h2>
+<h3>RTC</h3>
+<ul>
+ <li>
+ <code>CONFIG_RTC</code>:
+ Enables general support for a hardware RTC.
+ Specific architectures may require other specific settings.
+ </li>
+ <li>
+ <code>CONFIG_RTC_HIRES</code>:
+ The typical RTC keeps time to resolution of 1 second, usually supporting a 32-bit <code>time_t</code> value.
+ In this case, the RTC is used to &quot;seed&quot; the normal NuttX timer and the NuttX timer provides for higher resoution time.
+ If <code>CONFIG_RTC_HIRES</code> is enabled in the NuttX configuration, then the RTC provides higher resolution time and completely replaces the system timer for purpose of date and time.
+ </li>
+ <li>
+ <code>CONFIG_RTC_FREQUENCY</code>:
+ If <code>CONFIG_RTC_HIRES</code> is defined, then the frequency of the high resolution RTC must be provided.
+ If <code>CONFIG_RTC_HIRES</code> is not defined, <code>CONFIG_RTC_FREQUENCY</code> is assumed to be one.
+ </li>
+ <li>
+ <code>CONFIG_RTC_ALARM</code>:
+ Enable if the RTC hardware supports setting of an alarm.
+ A callback function will be executed when the alarm goes off
+ </li>
+</ul>
+
<h3>SPI driver</h3>
<ul>
<li>
- <code>CONFIG_SPI_OWNBUS</code> - Set if there is only one active device
+ <code>CONFIG_SPI_OWNBUS</code>: Set if there is only one active device
on the SPI bus. No locking or SPI configuration will be performed.
It is not necessary for clients to lock, re-configure, etc..
</li>
diff --git a/nuttx/arch/arm/src/stm32/stm32_i2c.c b/nuttx/arch/arm/src/stm32/stm32_i2c.c
index a46cc4af99..74d403648a 100644
--- a/nuttx/arch/arm/src/stm32/stm32_i2c.c
+++ b/nuttx/arch/arm/src/stm32/stm32_i2c.c
@@ -6,6 +6,7 @@
*
* With extensions, modifications by:
*
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregroy Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -932,7 +933,7 @@ static inline void stm32_i2c_enablefsmc(uint32_t ahbenr)
}
}
#else
-# define stm32_i2c_disablefsmc() (0)
+# define stm32_i2c_disablefsmc(priv) (0)
# define stm32_i2c_enablefsmc(ahbenr)
#endif
diff --git a/nuttx/arch/arm/src/stm32/stm32_rtc.c b/nuttx/arch/arm/src/stm32/stm32_rtc.c
index 78105228fe..84d50ccdac 100644
--- a/nuttx/arch/arm/src/stm32/stm32_rtc.c
+++ b/nuttx/arch/arm/src/stm32/stm32_rtc.c
@@ -33,14 +33,7 @@
*
************************************************************************************/
-/** \file
- * \author Uros Platise
- * \brief STM32 Real-Time Clock
- *
- * \addtogroup STM32_RTC
- * \{
- *
- * The STM32 RTC Driver offers standard precision of 1 Hz or High Resolution
+/* The STM32 RTC Driver offers standard precision of 1 Hz or High Resolution
* operating at rate up to 16384 Hz. It provides UTC time and alarm interface
* with external output pin (for wake-up).
*
@@ -53,9 +46,13 @@
* - time is a combination of clock and upper bits stored in backuped domain
* with unit of 1 [s]
*
- * \todo Error Handling in case LSE fails during start-up or during operation.
+ * TODO: Error Handling in case LSE fails during start-up or during operation.
*/
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
@@ -74,21 +71,78 @@
#include "stm32_rtc.h"
#include "stm32_waste.h"
+/************************************************************************************
+ * Pre-processor Definitions
+ ************************************************************************************/
+/* Configuration ********************************************************************/
+
+#ifdef CONFIG_RTC_HIRES
+# ifndef CONFIG_RTC_FREQUENCY
+# error "CONFIG_RTC_FREQUENCY is required for CONFIG_RTC_HIRES"
+# elif CONFIG_RTC_FREQUENCY != 16384
+# error "Only hi-res CONFIG_RTC_FREQUENCY of 16384Hz is supported"
+# endif
+# ifndef CONFIG_STM32_BKP
+# error "CONFIG_STM32_BKP is required for CONFIG_RTC_HIRES"
+# endif
+#else
+# ifndef CONFIG_RTC_FREQUENCY
+# define CONFIG_RTC_FREQUENCY 1
+# endif
+# if CONFIG_RTC_FREQUENCY != 1
+# error "Only lo-res CONFIG_RTC_FREQUENCY of 1Hz is supported"
+# endif
+#endif
+
+/* RTC/BKP Definitions *************************************************************/
+/* STM32_RTC_PRESCALAR_VALUE
+ * RTC pre-scalar value. The RTC is driven by a 32,768Hz input clock. This input
+ * value is divided by this value (plus one) to generate the RTC frequency.
+ * RTC_TIMEMSB_REG
+ * The BKP module register used to hold the RTC overflow value. Overflows are
+ * only handled in hi-res mode.
+ * RTC_CLOCKS_SHIFT
+ * The shift used to convert the hi-res timer LSB to one second. Not used with
+ * the lo-res timer.
+ */
-#if defined(CONFIG_STM32_BKP)
+#ifdef CONFIG_RTC_HIRES
+# define STM32_RTC_PRESCALAR_VALUE STM32_RTC_PRESCALER_MIN
+# define RTC_TIMEMSB_REG STM32_BKP_DR1
+# define RTC_CLOCKS_SHIFT 14
+#else
+# define STM32_RTC_PRESCALAR_VALUE STM32_RTC_PRESCALER_SECOND
+#endif
/************************************************************************************
- * Configuration of the RTC Backup Register (16-bit)
+ * Private Types
************************************************************************************/
-#define RTC_TIMEMSB_REG STM32_BKP_DR1
+struct rtc_regvals_s
+{
+ uint16_t cntl;
+ uint16_t cnth;
+#ifdef CONFIG_RTC_HIRES
+ uint16_t ovf;
+#endif
+};
/************************************************************************************
* Private Data
************************************************************************************/
-/** Variable determines the state of the LSE oscilator.
- * Possible errors:
+/* Callback to use when the alarm expires */
+
+#ifdef CONFIG_RTC_ALARM
+static alarmcb_t g_alarmcb;
+#endif
+
+/************************************************************************************
+ * Public Data
+ ************************************************************************************/
+
+/* Variable determines the state of the LSE oscilator.
+ * Possible errors:
* - on start-up
* - during operation, reported by LSE interrupt
*/
@@ -99,113 +153,265 @@ volatile bool g_rtc_enabled = false;
* Private Functions
************************************************************************************/
+/************************************************************************************
+ * Name: stm32_rtc_beginwr
+ *
+ * Description:
+ * Enter configuration mode
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ************************************************************************************/
+
static inline void stm32_rtc_beginwr(void)
{
- /* Previous write is done? */
- while( (getreg16(STM32_RTC_CRL) & RTC_CRL_RTOFF)==0 ) up_waste();
+ /* Previous write is done? */
+
+ while ((getreg16(STM32_RTC_CRL) & RTC_CRL_RTOFF) == 0)
+ {
+ up_waste();
+ }
+
+ /* Enter Config mode, Set Value and Exit */
- /* Enter Config mode, Set Value and Exit */
- modifyreg16(STM32_RTC_CRL, 0, RTC_CRL_CNF);
+ modifyreg16(STM32_RTC_CRL, 0, RTC_CRL_CNF);
}
+/************************************************************************************
+ * Name: stm32_rtc_endwr
+ *
+ * Description:
+ * Exit configuration mode
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ************************************************************************************/
+
static inline void stm32_rtc_endwr(void)
{
- modifyreg16(STM32_RTC_CRL, RTC_CRL_CNF, 0);
+ modifyreg16(STM32_RTC_CRL, RTC_CRL_CNF, 0);
}
-/** Wait for registerred to synchronise with RTC module, call after power-up only */
+/************************************************************************************
+ * Name: stm32_rtc_wait4rsf
+ *
+ * Description:
+ * Wait for registers to synchronise with RTC module, call after power-up only
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ************************************************************************************/
+
static inline void stm32_rtc_wait4rsf(void)
{
- modifyreg16(STM32_RTC_CRL, RTC_CRL_RSF, 0);
- while( !(getreg16(STM32_RTC_CRL) & RTC_CRL_RSF) ) up_waste();
+ modifyreg16(STM32_RTC_CRL, RTC_CRL_RSF, 0);
+ while (!(getreg16(STM32_RTC_CRL) & RTC_CRL_RSF))
+ {
+ up_waste();
+ }
}
/************************************************************************************
- * Interrupt Service Routines
+ * Name: up_rtc_breakout
+ *
+ * Description:
+ * Set the RTC to the provided time.
+ *
+ * Input Parameters:
+ * tp - the time to use
+ *
+ * Returned Value:
+ * None
+ *
************************************************************************************/
-static int stm32_rtc_overflow_isr(int irq, void *context)
+#ifdef CONFIG_RTC_HIRES
+static void up_rtc_breakout(FAR const struct timespec *tp,
+ FAR struct rtc_regvals_s *regvals)
{
- uint16_t source = getreg16( STM32_RTC_CRL );
-
- if (source & RTC_CRL_OWF) {
- putreg16( getreg16(RTC_TIMEMSB_REG) + 1, RTC_TIMEMSB_REG );
+ uint64_t frac;
+ uint32_t cnt;
+ uint16_t ovf;
+
+ /* Break up the time in seconds + milleconds into the correct values for our use */
+
+ frac = ((uint64_t)tp->tv_nsec * CONFIG_RTC_FREQUENCY) / 1000000000;
+ cnt = (tp->tv_sec << RTC_CLOCKS_SHIFT) | ((uint32_t)frac & (CONFIG_RTC_FREQUENCY-1));
+ ovf = (tp->tv_sec >> (32 - RTC_CLOCKS_SHIFT));
+
+ /* Then return the broken out time */
+
+ regvals->cnth = cnt >> 16;
+ regvals->cntl = cnt & 0xffff;
+ regvals->ovf = ovf;
+}
+#else
+static inline void up_rtc_breakout(FAR const struct timespec *tp,
+ FAR struct rtc_regvals_s *regvals)
+{
+ /* The low-res timer is easy... tv_sec holds exactly the value needed by the
+ * CNTH/CNTL registers.
+ */
+
+ regvals->cnth = (uint16_t)((uint32_t)tp->tv_sec >> 16);
+ regvals->cntl = (uint16_t)((uint32_t)tp->tv_sec & 0xffff);
+}
+#endif
+
+/************************************************************************************
+ * Name: stm32_rtc_interrupt
+ *
+ * Description:
+ * RTC interrupt service routine
+ *
+ * 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.
+ *
+ ************************************************************************************/
+
+#if defined(CONFIG_RTC_HIRES) || defined(CONFIG_RTC_ALARM)
+static int stm32_rtc_interrupt(int irq, void *context)
+{
+ uint16_t source = getreg16(STM32_RTC_CRL);
+
+#ifdef CONFIG_RTC_HIRES
+ if ((source & RTC_CRL_OWF) != 0)
+ {
+ putreg16(getreg16(RTC_TIMEMSB_REG) + 1, RTC_TIMEMSB_REG);
}
-
- if (source & RTC_CRL_ALRF) {
- /* Alarm */
+#endif
+
+#ifdef CONFIG_RTC_ALARM
+ if ((source & RTC_CRL_ALRF) != 0 && g_alarmcb != NULL)
+ {
+ /* Alarm callback */
+
+ g_alarmcb();
+ g_alarmcb = NULL;
}
+#endif
+
+ /* Clear pending flags, leave RSF high */
- /* Clear pending flags, leave RSF high */
-
- putreg16( RTC_CRL_RSF, STM32_RTC_CRL );
- return 0;
+ putreg16(RTC_CRL_RSF, STM32_RTC_CRL);
+ return 0;
}
+#endif
/************************************************************************************
- * Public Function - Initialization
+ * Public Functions
+ ************************************************************************************/
+
+/************************************************************************************
+ * Name: up_rtcinitialize
+ *
+ * Description:
+ * Initialize the hardware RTC per the select configuration. This function is
+ * called once during the OS initialization sequence
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
************************************************************************************/
-/** Power-up RTC
- *
- * \param prescaler A 20-bit value determines the time base, and is defined as:
- * f = 32768 / (prescaler + 1)
- *
- * \return State of the RTC unit
- *
- * \retval OK If RTC has been successfully configured.
- * \retval ERROR On error, if LSE does not start.
- **/
int up_rtcinitialize(void)
{
- /* For this initial version we use predefined value */
-
- uint32_t prescaler = STM32_RTC_PRESCALER_MIN;
-
- /* Set access to the peripheral, enable power and LSE */
-
- stm32_pwr_enablebkp();
- stm32_rcc_enablelse();
+ /* For this initial version we use predefined value */
- // \todo Get state from this function, if everything is
- // okay and whether it is already enabled (if it was disabled
- // reset upper time register)
- g_rtc_enabled = true;
-
- // \todo Possible stall? should we set the timeout period? and return with -1
- stm32_rtc_wait4rsf();
-
- /* Configure prescaler, note that these are write-only registers */
+ uint32_t prescaler = STM32_RTC_PRESCALER_MIN;
- stm32_rtc_beginwr();
- putreg16(prescaler >> 16, STM32_RTC_PRLH);
- putreg16(prescaler & 0xFFFF, STM32_RTC_PRLL);
- stm32_rtc_endwr();
-
- /* Configure Overflow Interrupt */
-
- irq_attach(STM32_IRQ_RTC, stm32_rtc_overflow_isr);
- up_enable_irq(STM32_IRQ_RTC);
+ /* Set access to the peripheral, enable power and LSE */
- /* Previous write is done? This is required prior writing into CRH */
+#ifdef CONFIG_RTC_HIRES
+ stm32_pwr_enablebkp();
+#endif
+ stm32_rcc_enablelse();
- while( (getreg16(STM32_RTC_CRL) & RTC_CRL_RTOFF)==0 ) up_waste();
+ /* TODO: Get state from this function, if everything is
+ * okay and whether it is already enabled (if it was disabled
+ * reset upper time register)
+ */
+
+ g_rtc_enabled = true;
+
+ /* TODO: Possible stall? should we set the timeout period? and return with -1 */
+
+ stm32_rtc_wait4rsf();
+
+ /* Configure prescaler, note that these are write-only registers */
+
+ stm32_rtc_beginwr();
+ putreg16(prescaler >> 16, STM32_RTC_PRLH);
+ putreg16(prescaler & 0xFFFF, STM32_RTC_PRLL);
+ stm32_rtc_endwr();
+
+ /* Configure RTC interrupt to catch overflow and alarm interrupts. */
+
+#if defined(CONFIG_RTC_HIRES) || defined(CONFIG_RTC_ALARM)
+ irq_attach(STM32_IRQ_RTC, stm32_rtc_interrupt);
+ up_enable_irq(STM32_IRQ_RTC);
+#endif
+
+ /* Previous write is done? This is required prior writing into CRH */
- modifyreg16(STM32_RTC_CRH, 0, RTC_CRH_OWIE);
+ while ((getreg16(STM32_RTC_CRL) & RTC_CRL_RTOFF) == 0)
+ {
+ up_waste();
+ }
+ modifyreg16(STM32_RTC_CRH, 0, RTC_CRH_OWIE);
- /* Alarm Int via EXTI Line */
+ /* Alarm Int via EXTI Line */
- // STM32_IRQ_RTCALR /* 41: RTC alarm through EXTI line interrupt */
+ /* STM32_IRQ_RTCALR 41: RTC alarm through EXTI line interrupt */
- return OK;
+ return OK;
}
-/** Get time (counter) value
- *
- * \return time, where the unit depends on the prescaler value
- **/
-
-clock_t up_rtc_getclock(void)
+/************************************************************************************
+ * Name: up_rtc_time
+ *
+ * Description:
+ * Get the current time in seconds.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The current time in seconds
+ *
+ ************************************************************************************/
+
+#ifdef CONFIG_RTC_HIRES
+time_t up_rtc_time(void)
+{
+ struct timespec ts;
+
+ /* In the hi-res case, this function is just a wrapper for up_rtc_gettime */
+
+ (void)up_rtc_gettime(&ts);
+ return ts.tv_sec;
+}
+#else
+time_t up_rtc_time(void)
{
irqstate_t flags;
uint16_t cnth;
@@ -243,98 +449,176 @@ clock_t up_rtc_getclock(void)
while (cntl < tmp);
irqrestore(flags);
- /* Then return the full 32-bit counter value */
+ /* Okay.. the samples should be as close together in time as possible and
+ * we can be assured that no clock rollover occurred between the samples.
+ *
+ * Return the time in seconds.
+ */
- return ((uint32_t)cnth << 16) | (uint32_t)cntl;
+ return (time_t)cnth << 16 | (time_t)cntl;
}
+#endif
-/** Set time (counter) value
- *
- * \param time The unit depends on the prescaler value
- **/
+/************************************************************************************
+ * Name: up_rtc_gettime
+ *
+ * Description:
+ * Get the current time from the high resolution RTC clock.
+ *
+ * Input Parameters:
+ * tp - The location to return the high resolution time value.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
+ ************************************************************************************/
-void up_rtc_setclock(clock_t newclock)
+#ifdef CONFIG_RTC_HIRES
+int up_rtc_gettime(FAR struct timespec *tp)
{
- stm32_rtc_beginwr();
- putreg16(newclock >> 16, STM32_RTC_CNTH);
- putreg16(newclock & 0xFFFF, STM32_RTC_CNTL);
- stm32_rtc_endwr();
-}
+ irqstate_t flags;
+ uint32_t ls;
+ uint32_t ms;
+ uint16_t ovf;
+ uint16_t cnth;
+ uint16_t cntl;
+ uint16_t tmp;
-time_t up_rtc_gettime(void)
-{
- /* Fetch time from LSB (hardware counter) and MSB (backup domain)
- * Take care on overflow of the LSB:
- * - it may overflow just after reading the up_rtc_getclock, transition
- * from 0xFF...FF -> 0x000000
- * - ISR would be generated to increment the RTC_TIMEMSB_REG
- * - Wrong result would when: DR+1 and LSB is old, resulting in ~DR+2
- * instead of just DR+1
- */
-
- irqstate_t irqs = irqsave();
-
- uint32_t time_lsb = up_rtc_getclock();
- uint32_t time_msb = getreg16(RTC_TIMEMSB_REG);
-
- irqrestore( irqs );
-
- /* Use the upper bits of the LSB and lower bits of the MSB
- * structured as:
- * time = time[31:18] from MSB[13:0] | time[17:0] from time_lsb[31:14]
- */
-
- time_lsb >>= RTC_CLOCKS_SHIFT;
-
- time_msb <<= (32-RTC_CLOCKS_SHIFT);
- time_msb &= ~((1<<(32-RTC_CLOCKS_SHIFT))-1);
-
- return time_msb | time_lsb;
-}
+ /* The RTC counter is read from two 16-bit registers to form one 32-bit
+ * value. Because these are non-atomic operations, many things can happen
+ * between the two reads: This thread could get suspended or interrrupted
+ * or the lower 16-bit counter could rollover between reads. Disabling
+ * interrupts will prevent suspensions and interruptions:
+ */
-void up_rtc_settime(time_t newtime)
-{
- /* Do reverse compared to gettime above */
-
- uint32_t time_lsb = newtime << RTC_CLOCKS_SHIFT |
- (up_rtc_getclock() & ((1<<RTC_CLOCKS_SHIFT)-1));
-
- uint32_t time_msb = newtime >> (32-RTC_CLOCKS_SHIFT);
-
- irqstate_t irqs = irqsave();
-
- up_rtc_setclock(time_lsb);
- putreg16( time_msb, RTC_TIMEMSB_REG );
-
- irqrestore( irqs );
+ flags = irqsave();
+
+ /* And the following loop will handle any clock rollover events that may
+ * happen between samples. Most of the time (like 99.9%), the following
+ * loop will execute only once. In the rare rollover case, it should
+ * execute no more than 2 times.
+ */
+
+ do
+ {
+ tmp = getreg16(STM32_RTC_CNTL);
+ cnth = getreg16(STM32_RTC_CNTH);
+ ovf = getreg16(RTC_TIMEMSB_REG);
+ cntl = getreg16(STM32_RTC_CNTL);
+ }
+
+ /* The second sample of CNTL could be less than the first sample of CNTL
+ * only if rollover occurred. In that case, CNTH may or may not be out
+ * of sync. The best thing to do is try again until we know that no
+ * rollover occurred.
+ */
+
+ while (cntl < tmp);
+ irqrestore(flags);
+
+ /* Okay.. the samples should be as close together in time as possible and
+ * we can be assured that no clock rollover occurred between the samples.
+ *
+ * Create a 32-bit value from the LS and MS 16-bit RTC counter values and
+ * from the MS and overflow 16-bit counter values.
+ */
+
+ ls = (uint32_t)cnth << 16 | (uint32_t)cntl;
+ ms = (uint32_t)ovf << 16 | (uint32_t)cnth;
+
+ /* Then we can save the time in seconds and fractional seconds. */
+
+ tp->tv_sec = (ms << (32-RTC_CLOCKS_SHIFT-16)) | (ls >> (RTC_CLOCKS_SHIFT+16));
+ tp->tv_nsec = (ls & (CONFIG_RTC_FREQUENCY-1)) * (1000000000/CONFIG_RTC_FREQUENCY);
+ return OK;
}
+#endif
-/** Set ALARM at which time ALARM callback is going to be generated
- *
- * The function sets the alarm and return present time at the time
- * of setting the alarm.
- *
- * Note that If actual time has already passed callback will not be
- * generated and it is up to the higher level code to compare the
- * returned (actual) time and desired time of alarm.
- *
- * \param attime The unit depends on the prescaler value
- * \return presenttime, where the unit depends on the prescaler value
- **/
-clock_t up_rtc_setalarm(clock_t atclock)
+/************************************************************************************
+ * Name: up_rtc_settime
+ *
+ * Description:
+ * Set the RTC to the provided time.
+ *
+ * Input Parameters:
+ * tp - the time to use
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
+ ************************************************************************************/
+
+int up_rtc_settime(FAR const struct timespec *tp)
{
- stm32_rtc_beginwr();
- putreg16(atclock >> 16, STM32_RTC_ALRH);
- putreg16(atclock & 0xFFFF, STM32_RTC_ALRL);
- stm32_rtc_endwr();
-
- return up_rtc_getclock();
+ struct rtc_regvals_s regvals;
+ irqstate_t flags;
+
+ /* Break out the time values */
+
+ up_rtc_breakout(tp, &regvals);
+
+ /* Then write the broken out values to the RTC counter and BKP overflow register
+ * (hi-res mode only)
+ */
+
+ flags = irqsave();
+ stm32_rtc_beginwr();
+ putreg16(regvals.cnth, STM32_RTC_CNTH);
+ putreg16(regvals.cntl, STM32_RTC_CNTL);
+ stm32_rtc_endwr();
+
+#ifdef CONFIG_RTC_HIRES
+ putreg16(regvals.ovf, RTC_TIMEMSB_REG);
+#endif
+ irqrestore(flags);
+ return OK;
}
-/** Set alarm output pin */
-void stm32_rtc_settalarmpin(bool activate)
+/************************************************************************************
+ * Name: up_rtc_setalarm
+ *
+ * Description:
+ * Set up a alarm.
+ *
+ * Input Parameters:
+ * tp - the time to set the alarm
+ * callback - the function to call when the alarm expires.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
+ ************************************************************************************/
+
+#ifdef CONFIG_RTC_ALARM
+int up_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback);
{
-}
+ struct rtc_regvals_s regvals;
+ irqstate_t flags;
+ int ret = -EBUSY;
+
+ /* Is there already something waiting on the ALARM? */
+
+ if (g_alarmcb == NULL)
+ {
+ /* No.. Save the callback function pointer */
-#endif // defined(CONFIG_STM32_BKP)
-/** \} */
+ g_alarmcb = callback;
+
+ /* Break out the time values */
+
+ up_rtc_breakout(tp, &regvals);
+
+ /* The set the alarm */
+
+ flags = irqsave();
+ stm32_rtc_beginwr();
+ putreg16(regvals.cnth, STM32_RTC_ALRH);
+ putreg16(regvals.cntl, STM32_RTC_ALRL);
+ stm32_rtc_endwr();
+ irqrestore(flags);
+
+ ret = OK;
+ }
+ return ret;
+}
+#endif
diff --git a/nuttx/configs/vsn/nsh/defconfig b/nuttx/configs/vsn/nsh/defconfig
index ca053ec35f..ddb8114ecd 100755
--- a/nuttx/configs/vsn/nsh/defconfig
+++ b/nuttx/configs/vsn/nsh/defconfig
@@ -268,6 +268,7 @@ CONFIG_WIRELESS=y
#
CONFIG_RTC=y
CONFIG_RTC_HIRES=y
+CONFIG_RTC_FREQUENCY=16384
CONFIG_SYSTEM_UTC=y
#
diff --git a/nuttx/configs/vsn/src/sif.c b/nuttx/configs/vsn/src/sif.c
index 535a09829a..e185d8d0df 100644
--- a/nuttx/configs/vsn/src/sif.c
+++ b/nuttx/configs/vsn/src/sif.c
@@ -714,9 +714,8 @@ int sif_main(int argc, char *argv[])
struct timespec t_active;
clock_gettime(CLOCK_ACTIVETIME, &t_active);
- fprintf(stderr, "rtc time = %u / %u, active = %u / %u, time / systick = %u / %u\n",
- up_rtc_gettime(), up_rtc_getclock(),
- t_active.tv_sec, t_active.tv_nsec,
+ fprintf(stderr, "rtc time = %u, active = %u / %u, time / systick = %u / %u\n",
+ up_rtc_time(), t_active.tv_sec, t_active.tv_nsec,
time(NULL), clock_systimer() );
return -1;
}
diff --git a/nuttx/include/nuttx/clock.h b/nuttx/include/nuttx/clock.h
index 71f0c7e8a0..4990c65b4f 100644
--- a/nuttx/include/nuttx/clock.h
+++ b/nuttx/include/nuttx/clock.h
@@ -172,7 +172,7 @@ extern "C" {
*
****************************************************************************/
-#if defined(CONFIG_RTC) || !__HAVE_KERNEL_GLOBALS
+#if defined(CONFIG_SYSTEM_UTC) || !__HAVE_KERNEL_GLOBALS
EXTERN uint32_t clock_systimer(void);
#endif
diff --git a/nuttx/include/nuttx/rtc.h b/nuttx/include/nuttx/rtc.h
index 5d9ae63419..df633108ed 100644
--- a/nuttx/include/nuttx/rtc.h
+++ b/nuttx/include/nuttx/rtc.h
@@ -4,6 +4,11 @@
* Copyright(C) 2011 Uros Platise. All rights reserved.
* Author: Uros Platise <uros.platise@isotel.eu>
*
+ * With extensions, modifications by:
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregroy Nutt <gnutt@nuttx.org>
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -44,19 +49,51 @@
#include <stdint.h>
#include <stdbool.h>
-
-#include <nuttx/clock.h>
+#include <time.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+/* Configuration ************************************************************/
+/* CONFIG_RTC - Enables general support for a hardware RTC. Specific
+ * architectures may require other specific settings.
+ *
+ * CONFIG_RTC_HIRES - The typical RTC keeps time to resolution of 1 second,
+ * usually supporting a 32-bit time_t value. In this case, the RTC is
+ * used to "seed" the normal NuttX timer and the NuttX timer provides
+ * for higher resoution time.
+ *
+ * If CONFIG_RTC_HIRES is enabled in the NuttX configuration, then the
+ * RTC provides higher resolution time and completely replaces the system
+ * timer for purpose of date and time.
+ *
+ * CONFIG_RTC_FREQUENCY - If CONFIG_RTC_HIRES is defined, then the frequency
+ * of the high resolution RTC must be provided. If CONFIG_RTC_HIRES is
+ * not defined, CONFIG_RTC_FREQUENCY is assumed to be one.
+ *
+ * CONFIG_RTC_ALARM - Enable if the RTC hardware supports setting of an
+ * alarm. A callback function will be executed when the alarm goes off
+ */
-#define RTC_CLOCKS_PER_SEC 16384
-#define RTC_CLOCKS_SHIFT 14
+#ifdef CONFIG_RTC_HIRES
+# ifndef CONFIG_RTC_FREQUENCY
+# error "CONFIG_RTC_FREQUENCY is required for CONFIG_RTC_HIRES"
+# endif
+#else
+# ifndef CONFIG_RTC_FREQUENCY
+# define CONFIG_RTC_FREQUENCY 1
+# endif
+# if CONFIG_RTC_FREQUENCY != 1
+# error "The low resolution RTC must have frequency 1Hz"
+# endif
+#endif
/****************************************************************************
* Public Types
****************************************************************************/
+/* The form of an alarm callback */
+
+typedef void (alarmcb_t)(void);
/****************************************************************************
* Public Variables
@@ -83,32 +120,92 @@ extern "C" {
#define EXTERN extern
#endif
-/****************************************************************************
+/************************************************************************************
* Name: up_rtcinitialize
*
* Description:
- * Initialize the periodic timer interface. This function is called once
- * from the clock_initialize() function.
+ * Initialize the hardware RTC per the select configuration. This function is
+ * called once during the OS initialization sequence
+ *
+ * Input Parameters:
+ * None
*
* Returned Value:
- * Returns OK if RTC has successfully started, otherwise ERROR.
+ * Zero (OK) on success; a negated errno on failure
*
- ****************************************************************************/
+ ************************************************************************************/
EXTERN int up_rtcinitialize(void);
-EXTERN int up_rtcinitialize(void);
-EXTERN clock_t up_rtc_getclock(void);
-EXTERN void up_rtc_setclock(clock_t clock);
+/************************************************************************************
+ * Name: up_rtc_time
+ *
+ * Description:
+ * Get the current time in seconds. This is similar to the standard time()
+ * function.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * The current time in seconds
+ *
+ ************************************************************************************/
+
+EXTERN time_t up_rtc_time(void);
-EXTERN time_t up_rtc_gettime(void);
-EXTERN void up_rtc_settime(time_t time);
+/************************************************************************************
+ * Name: up_rtc_gettime
+ *
+ * Description:
+ * Get the current time from the high resolution RTC clock.
+ *
+ * Input Parameters:
+ * tp - The location to return the high resolution time value.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
+ ************************************************************************************/
+
+#ifdef CONFIG_RTC_HIRES
+EXTERN int up_rtc_gettime(FAR struct timespec *tp);
+#endif
+
+/************************************************************************************
+ * Name: up_rtc_settime
+ *
+ * Description:
+ * Set the RTC to the provided time.
+ *
+ * Input Parameters:
+ * tp - the time to use
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
+ ************************************************************************************/
-EXTERN clock_t up_rtc_setalarm(clock_t atclock);
+EXTERN int up_rtc_settime(FAR const struct timespec *tp);
-/* This callback is provided by the clock module and called by the RTC ISR */
+/************************************************************************************
+ * Name: up_rtc_setalarm
+ *
+ * Description:
+ * Set up a alarm.
+ *
+ * Input Parameters:
+ * tp - the time to set the alarm
+ * callback - the function to call when the alarm expires.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno on failure
+ *
+ ************************************************************************************/
-EXTERN void clock_rtcalarmcb(clock_t clock);
+#ifdef CONFIG_RTC_ALARM
+EXTERN int up_rtc_setalarm(FAR const struct timespec *tp, alarmcb_t callback);
+#endif
#undef EXTERN
#if defined(__cplusplus)
diff --git a/nuttx/include/time.h b/nuttx/include/time.h
index c52e74bf2d..fae9484025 100644
--- a/nuttx/include/time.h
+++ b/nuttx/include/time.h
@@ -77,7 +77,7 @@
* power down modes. Unit is 1 second.
*/
-#ifdef CONFIG_RTC
+#ifdef CONFIG_SYSTEM_UTC
# define CLOCK_ACTIVETIME 1
#endif
diff --git a/nuttx/sched/clock_gettime.c b/nuttx/sched/clock_gettime.c
index 1dc48aeb7a..fc3a1593a2 100644
--- a/nuttx/sched/clock_gettime.c
+++ b/nuttx/sched/clock_gettime.c
@@ -113,7 +113,12 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp)
if (clock_id == CLOCK_REALTIME && tp)
{
+ /* If CONFIG_SYSTEM_UTC is not defined, then we have to get the time
+ * from g_system_timer.
+ */
+
#ifndef CONFIG_SYSTEM_UTC
+
/* Get the elapsed time since power up (in milliseconds) biased
* as appropriate.
*/
@@ -151,47 +156,18 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp)
tp->tv_sec = (time_t)secs;
tp->tv_nsec = (long)nsecs;
-#else /* if CONFIG_SYSTEM_UTC=y */
+#else /* CONFIG_SYSTEM_UTC */
+
+ /* CONFIG_SYSTEM_UTC is defined. But we might be able to get the time
+ * from the hardware if a high resolution RTC is available.
+ */
-#ifdef CONFIG_RTC
+#ifdef CONFIG_RTC_HIRES
if (g_rtc_enabled)
{
- /* up_rtc_gettime() returns the time in seconds and up_rtc_getclock()
- * will return the time int RTC clock ticks. Under the hood, these
- * are probably based on the same running time. However, since we
- * sample this time twice, we have to add the following strange logic
- * to assure that the fractional second value does not rollover to
- * a full second between sampling times.
- */
+ /* Get the hi-resolution time from the RTC */
- clock_t rtc_frac; /* Current fractional seconds in RTC ticks */
- clock_t rtc_last; /* Previous fractional seconds in RTC ticks */
- time_t rtc_sec; /* Current seconds */
-
- /* Interrupts are disabled here only to prevent interrupts and context
- * switches from interfering with the consecutive time samples. I
- * expect to go through this loop 1 time 99.9% of the time and then
- * only twice on the remaining cornercases.
- */
-
- flags = irqsave();
- rtc_frac = up_rtc_getclock() & (RTC_CLOCKS_PER_SEC-1);
- do
- {
- rtc_last = rtc_frac;
- rtc_sec = up_rtc_gettime();
- rtc_frac = up_rtc_getclock() & (RTC_CLOCKS_PER_SEC-1);
- }
- while (rtc_frac < rtc_last);
- irqrestore(flags);
-
- /* Okay.. the samples should be as close together in time as possible
- * and we can be assured that no fractional second rollover occurred
- * between the samples.
- */
-
- tp->tv_sec = rtc_sec;
- tp->tv_nsec = rtc_frac * (1000000000/RTC_CLOCKS_PER_SEC);
+ ret = up_rtc_gettime(tp);
}
else
#endif
@@ -209,17 +185,16 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp)
tp->tv_sec = system_utc;
tp->tv_nsec = tickcount * (1000000000/TICK_PER_SEC);
}
-#endif
+#endif /* CONFIG_SYSTEM_UTC */
- sdbg("Returning tp=(%d,%d)\n",
- (int)tp->tv_sec, (int)tp->tv_nsec);
+ sdbg("Returning tp=(%d,%d)\n", (int)tp->tv_sec, (int)tp->tv_nsec);
}
/* CLOCK_ACTIVETIME is non-standard. Returns active UTC time, which is
* disabled during power down modes. Unit is 1 second.
*/
-#ifdef CONFIG_RTC
+#ifdef CONFIG_SYSTEM_UTC
else if (clock_id == CLOCK_ACTIVETIME && g_rtc_enabled && tp)
{
/* Disable interrupts while g_system_utc and g_tickcount are sampled
diff --git a/nuttx/sched/clock_initialize.c b/nuttx/sched/clock_initialize.c
index 8919b6005d..ed3a258289 100644
--- a/nuttx/sched/clock_initialize.c
+++ b/nuttx/sched/clock_initialize.c
@@ -54,6 +54,12 @@
* Definitions
****************************************************************************/
+#ifdef CONFIG_RTC
+# ifndef CONFIG_SYSTEM_UTC
+# error "In order to support hardware RTC system must have set the CONFIG_SYSTEM_UTC=y"
+# endif
+#endif
+
/* Standard time definitions (in units of seconds) */
#define SEC_PER_MIN ((time_t)60)
@@ -85,11 +91,11 @@
****************************************************************************/
#if CONFIG_SYSTEM_UTC
-volatile time_t g_system_utc = 0;
+volatile time_t g_system_utc;
#else
-volatile clock_t g_system_timer = 0;
-struct timespec g_basetime = {0,0};
-uint32_t g_tickbias = 0;
+volatile clock_t g_system_timer;
+struct timespec g_basetime;
+uint32_t g_tickbias;
#endif
/**************************************************************************
@@ -102,11 +108,11 @@ uint32_t g_tickbias = 0;
#if CONFIG_SYSTEM_UTC
#if TICK_PER_SEC > 32767
-volatile uint32_t g_tickcount = 0;
+volatile uint32_t g_tickcount;
#elif TICK_PER_SEC > 255
-volatile uint16_t g_tickcount = 0;
+volatile uint16_t g_tickcount;
#else
-volatile uint8_t g_tickcount = 0;
+volatile uint8_t g_tickcount;
#endif
#endif /* CONFIG_SYSTEM_UTC */
@@ -114,7 +120,7 @@ volatile uint8_t g_tickcount = 0;
* Private Functions
**************************************************************************/
/****************************************************************************
- * Function: clock_timer
+ * Function: incr_utc
*
* Description:
* This function must be called once every time the real
@@ -139,49 +145,40 @@ static inline void incr_utc(void)
#endif
/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Function: clock_initialize
+ * Function: clock_inittime
*
* Description:
- * Perform one-time initialization of the timing facilities.
+ * Get the initial time value from the best source available.
*
****************************************************************************/
-void clock_initialize(void)
+#ifdef CONFIG_RTC
+#ifdef CONFIG_RTC_HIRES
+
+static inline void clock_inittime(FAR struct timespec *tp)
{
-#ifndef CONFIG_SYSTEM_UTC
- time_t jdn = 0;
-#endif
- /* Initialize the real time close (this should be un-nesssary except on a
- * restart).
- */
+ /* Get the complete time from the hi-res RTC. */
+
+ (void)up_rtc_gettime(tp);
+}
-#ifdef CONFIG_SYSTEM_UTC
- g_system_utc = 0;
#else
- g_system_timer = 0;
-#endif
- /* Do we have hardware RTC support? */
+static inline void clock_inittime(FAR struct timespec *tp)
+{
+ /* Get the seconds (only) from the lo-res RTC */
-#ifdef CONFIG_RTC
+ tp->tv_sec = up_rtc_time();
+ tp->tv_nsec = 0;
+}
-#ifndef CONFIG_SYSTEM_UTC
-# error In order to support hardware RTC system must have set the CONFIG_SYSTEM_UTC=y
-#endif
+#endif /* CONFIG_RTC_HIRES */
+#else /* CONFIG_RTC */
- up_rtcinitialize();
-#endif
-
-#ifndef CONFIG_SYSTEM_UTC
+static inline void clock_inittime(FAR struct timespec *tp)
+{
+ time_t jdn = 0;
/* Get the EPOCH-relative julian date from the calendar year,
* month, and date
@@ -192,12 +189,47 @@ void clock_initialize(void)
/* Set the base time as seconds into this julian day. */
- g_basetime.tv_sec = jdn * SEC_PER_DAY;
- g_basetime.tv_nsec = 0;
+ tp->tv_sec = jdn * SEC_PER_DAY;
+ tp->tv_nsec = 0;
+}
+
+#endif /* CONFIG_RTC */
+
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: clock_initialize
+ *
+ * Description:
+ * Perform one-time initialization of the timing facilities.
+ *
+ ****************************************************************************/
+
+void clock_initialize(void)
+{
+#ifdef CONFIG_SYSTEM_UTC
+ struct timespec ts;
+#endif
+
+ /* Initialize the RTC hardware */
+
+#ifdef CONFIG_RTC
+ up_rtcinitialize();
+#endif
- /* These is no time bias from this time. */
+ /* Initialize the time value */
- g_tickbias = 0;
+#ifdef CONFIG_SYSTEM_UTC
+ clock_inittime(&ts);
+ g_system_utc = ts.tv_sec;
+ g_tickcount = ((ts.tv_nsec > 10) * CLOCKS_PER_SEC) / (1000000000 >> 10);
+#else
+ clock_inittime(&g_basetime);
+ g_system_timer = 0;
+ g_tickbias = 0;
#endif
}
diff --git a/nuttx/sched/clock_settime.c b/nuttx/sched/clock_settime.c
index 77b6ebecc9..299e8c65bd 100644
--- a/nuttx/sched/clock_settime.c
+++ b/nuttx/sched/clock_settime.c
@@ -43,6 +43,8 @@
#include <time.h>
#include <errno.h>
#include <debug.h>
+
+#include <arch/irq.h>
#include "clock_internal.h"
/************************************************************************
@@ -85,7 +87,7 @@
*
************************************************************************/
-int clock_settime(clockid_t clock_id, const struct timespec *tp)
+int clock_settime(clockid_t clock_id, FAR const struct timespec *tp)
{
int ret = OK;
@@ -116,12 +118,13 @@ int clock_settime(clockid_t clock_id, const struct timespec *tp)
#ifdef CONFIG_RTC
if (g_rtc_enabled)
{
- up_rtc_settime(tp->tv_sec);
+ up_rtc_settime(tp);
}
else
#endif
- g_system_utc = tp->tv_sec;
-
+ {
+ g_system_utc = tp->tv_sec;
+ }
#endif
sdbg("basetime=(%d,%d) tickbias=%d\n",
@@ -133,10 +136,25 @@ int clock_settime(clockid_t clock_id, const struct timespec *tp)
* disabled during power down modes. Unit is 1 second.
*/
-#ifdef CONFIG_RTC
- else if (clock_id == CLOCK_ACTIVETIME && g_rtc_enabled && tp)
+#ifdef CONFIG_SYSTEM_UTC
+ else if (clock_id == CLOCK_ACTIVETIME && tp)
{
+ irqstate_t flags;
+ uint32_t tickcount;
+
+ /* Calculate the number of ticks correspond to the nanosecond count...
+ * exercising care to avoid overflows. This could still overflow
+ * if CLOCKS_PER_SEC is very large (something like 4096).
+ */
+
+ tickcount = ((tp->tv_nsec >> 10) * CLOCKS_PER_SEC) / (1000000000 >> 10);
+
+ /* Then set the UTC time (seconds) plus the tickcount (fractional seconds */
+
+ flags = irqsave();
g_system_utc = tp->tv_sec;
+ g_tickcount = tickcount;
+ irqrestore(flags);
}
#endif
diff --git a/nuttx/sched/clock_systimer.c b/nuttx/sched/clock_systimer.c
index cfa019fc75..2061b1de6b 100644
--- a/nuttx/sched/clock_systimer.c
+++ b/nuttx/sched/clock_systimer.c
@@ -85,20 +85,12 @@ uint32_t clock_systimer(void)
uint32_t tickcount;
#endif
- /* Fetch the g_system_timer value from timer hardware, if available */
-
-#ifdef CONFIG_RTC
-
- /* Check if the periodic timer is initialized
+#ifdef CONFIG_RTC_HIRES
+ /* Fetch the g_system_timer value from timer hardware, if available.
*
- * Note that the unit of the g_system_timer and and up_rtc_getclock() do
+ * Note that the unit of the g_system_timer and and up_rtc_gettime() do
* not have the same unit.
*/
-
- if (g_rtc_enabled)
- {
- /* return up_rtc_getclock(); */
- }
#endif
#ifndef CONFIG_SYSTEM_UTC