From 45530a77d42bc7a0411ddd37dc7f6b267fe2590b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 17 Nov 2015 14:07:55 -0600 Subject: [PATCH] Add support for DS3231 I2C RTC. Untested on initial commit. --- ChangeLog | 2 + Documentation | 2 +- configs | 2 +- drivers/timers/Kconfig | 18 ++ drivers/timers/Make.defs | 6 + drivers/timers/ds3231.c | 474 ++++++++++++++++++++++++++++++++++ drivers/timers/ds3231.h | 274 ++++++++++++++++++++ include/nuttx/timers/ds3231.h | 83 ++++++ 8 files changed, 859 insertions(+), 2 deletions(-) create mode 100644 drivers/timers/ds3231.c create mode 100644 drivers/timers/ds3231.h create mode 100644 include/nuttx/timers/ds3231.h diff --git a/ChangeLog b/ChangeLog index 3713274c66..f8cab43b1e 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11098,4 +11098,6 @@ (2015-11-16). * drivers/mtd/at24xx.c: Add support for multiple AT24xx EEPROM parts, each with unique I2C addresses, but otherwise idential (2015-11-17). + * drivers/timers/ds3231.c: Add support for the DS3231 I2C RTC. Untested + on the initial commit (2015-11-17). diff --git a/Documentation b/Documentation index 81e94b2e1d..9a0efe5bb5 160000 --- a/Documentation +++ b/Documentation @@ -1 +1 @@ -Subproject commit 81e94b2e1d2831d590f07ef729e74a7b66922ac5 +Subproject commit 9a0efe5bb5e0a817f74b4521f4bb0d91b6f0c2cf diff --git a/configs b/configs index 174b30da6b..8a8b3d3ea6 160000 --- a/configs +++ b/configs @@ -1 +1 @@ -Subproject commit 174b30da6b334c1e040d4212e31237b5b6aabd06 +Subproject commit 8a8b3d3ea61739a5462058889e8ba5352100ab5f diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig index c8579a8fea..1c4f5685de 100644 --- a/drivers/timers/Kconfig +++ b/drivers/timers/Kconfig @@ -117,6 +117,24 @@ config RTC_IOCTL architecture-specific RTC operations to the RTC interface endif # RTC_DRIVER + +config RTC_DS3231 + bool "DS3231 RTC Driver" + default n + select I2C + select I2C_TRANSFER + select RTC_DATETIME + ---help--- + Enables support for the Maxim Integrated DS3231 I2C RTC timer. + +if RTC_DS3231 + +config DS3231_I2C_FREQUENCY + int "DS3231 I2C frequency" + default 400000 + range 1 4000000 + +endif # RTC_DS3231 endif # RTC menuconfig WATCHDOG diff --git a/drivers/timers/Make.defs b/drivers/timers/Make.defs index f70052a21f..e856991826 100644 --- a/drivers/timers/Make.defs +++ b/drivers/timers/Make.defs @@ -51,6 +51,12 @@ ifeq ($(CONFIG_TIMER),y) TMRVPATH = :timers endif +ifeq ($(CONFIG_RTC_DS3231),y) + CSRCS += ds3231.c + TMRDEPPATH = --dep-path timers + TMRVPATH = :timers +endif + ifeq ($(CONFIG_RTC_DRIVER),y) CSRCS += rtc.c TMRDEPPATH = --dep-path timers diff --git a/drivers/timers/ds3231.c b/drivers/timers/ds3231.c new file mode 100644 index 0000000000..c47485d60f --- /dev/null +++ b/drivers/timers/ds3231.c @@ -0,0 +1,474 @@ +/************************************************************************************ + * drivers/timers/ds3231.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include +#include +#include +#include + +#include +#include +#include + +#include "ds3231.h" + +#ifdef CONFIG_RTC_DS3231 + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ +/* Configuration ********************************************************************/ +/* This RTC implementation supports only date/time RTC hardware */ + +#ifndef CONFIG_RTC_DATETIME +# error CONFIG_RTC_DATETIME must be set to use this driver +#endif + +#ifdef CONFIG_RTC_HIRES +# error CONFIG_RTC_HIRES must NOT be set with this driver +#endif + +#ifndef CONFIG_I2C_TRANSFER +# error CONFIG_I2C_TRANSFER is required by this driver +#endif + +#ifndef CONFIG_DS3231_I2C_FREQUENCY +# error CONFIG_DS3231_I2C_FREQUENCY is not configured +# define CONFIG_DS3231_I2C_FREQUENCY 400000 +#endif + +#if CONFIG_DS3231_I2C_FREQUENCY > 400000 +# error CONFIG_DS3231_I2C_FREQUENCY is out of range +#endif + +#define DS3231_I2C_ADDRESS 0x68 + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_RTC +#endif + +/* Debug ****************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC +# define rtcdbg dbg +# define rtcvdbg vdbg +# define rtclldbg lldbg +# define rtcllvdbg llvdbg +#else +# define rtcdbg(x...) +# define rtcvdbg(x...) +# define rtclldbg(x...) +# define rtcllvdbg(x...) +#endif + +/************************************************************************************ + * Priviate Types + ************************************************************************************/ +/* This structure describes the state of the DS3231 chip. Only a single RTC is + * supported. + */ + +struct ds3231_dev_s +{ + FAR struct i2c_dev_s *i2c; /* Contained reference to the I2C bus driver */ +}; + +/************************************************************************************ + * Public Data + ************************************************************************************/ + +/* g_rtc_enabled is set true after the RTC has successfully initialized */ + +volatile bool g_rtc_enabled = false; + +/************************************************************************************ + * Private Data + ************************************************************************************/ +/* The state of the DS3231 chip. Only a single RTC is supported */ + +static struct ds3231_dev_s g_ds3231; + +/************************************************************************************ + * Private Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: rtc_dumptime + * + * Description: + * Show the broken out time. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ************************************************************************************/ + +#ifdef CONFIG_DEBUG_RTC +static void rtc_dumptime(FAR struct tm *tp, FAR const char *msg) +{ + rtclldbg("%s:\n", msg); + rtclldbg(" tm_sec: %08x\n", tp->tm_sec); + rtclldbg(" tm_min: %08x\n", tp->tm_min); + rtclldbg(" tm_hour: %08x\n", tp->tm_hour); + rtclldbg(" tm_mday: %08x\n", tp->tm_mday); + rtclldbg(" tm_mon: %08x\n", tp->tm_mon); + rtclldbg(" tm_year: %08x\n", tp->tm_year); +#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED) + rtclldbg(" tm_wday: %08x\n", tp->tm_wday); + rtclldbg(" tm_yday: %08x\n", tp->tm_yday); + rtclldbg(" tm_isdst: %08x\n", tp->tm_isdst); +#endif +} +#else +# define rtc_dumptime(tp, msg) +#endif + +/************************************************************************************ + * Name: rtc_bin2bcd + * + * Description: + * Converts a 2 digit binary to BCD format + * + * Input Parameters: + * value - The byte to be converted. + * + * Returned Value: + * The value in BCD representation + * + ************************************************************************************/ + +static uint8_t rtc_bin2bcd(int value) +{ + uint8_t msbcd = 0; + + while (value >= 10) + { + msbcd++; + value -= 10; + } + + return (msbcd << 4) | value; +} + +/************************************************************************************ + * Name: rtc_bin2bcd + * + * Description: + * Convert from 2 digit BCD to binary. + * + * Input Parameters: + * value - The BCD value to be converted. + * + * Returned Value: + * The value in binary representation + * + ************************************************************************************/ + +static int rtc_bcd2bin(uint8_t value) +{ + int tens = ((int)value >> 4) * 10; + return tens + (value & 0x0f); +} + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: ds3231_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected 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 + * + ************************************************************************************/ + +int ds3231_rtc_initialize(FAR struct i2c_dev_s *i2c) +{ + /* Remember the i2c device and claim that the RTC is enabled */ + + g_ds3231.i2c = i2c; + g_rtc_enabled = true; + return OK; +} + +/************************************************************************************ + * Name: up_rtc_getdatetime + * + * Description: + * Get the current date and time from the date/time RTC. This interface + * is only supported by the date/time RTC hardware implementation. + * It is used to replace the system timer. It is only used by the RTOS during + * initialization to set up the system time when CONFIG_RTC and CONFIG_RTC_DATETIME + * are selected (and CONFIG_RTC_HIRES is not). + * + * NOTE: Some date/time RTC hardware is capability of sub-second accuracy. That + * sub-second accuracy is lost in this interface. However, since the system time + * is reinitialized on each power-up/reset, there will be no timing inaccuracy in + * the long run. + * + * Input Parameters: + * tp - The location to return the high resolution time value. + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ************************************************************************************/ + +int up_rtc_getdatetime(FAR struct tm *tp) +{ + struct i2c_msg_s msg[2]; + uint8_t buffer[8]; + int tmp; + int ret; + + /* Select to begin reading at the seconds register */ + + buffer[0] = DS3231_TIME_SECR; + + msg[0].addr = DS3231_I2C_ADDRESS; + msg[0].flags = 0; + msg[0].buffer = buffer; + msg[0].length = 1; + + /* Set up to read 7 registers: secs, min, hr, dow, date, mth, yr */ + + msg[1].addr = DS3231_I2C_ADDRESS; + msg[1].flags = I2C_M_READ; + msg[1].buffer = &buffer[1]; + msg[1].length = 7; + + /* Configure I2C before using it */ + + I2C_SETFREQUENCY(g_ds3231.i2c, CONFIG_DS3231_I2C_FREQUENCY); + + /* Perform the transfer (This could be done with I2C_WRITEREAD()) */ + + ret = I2C_TRANSFER(g_ds3231.i2c, msg, 1); + if (ret < 0) + { + rtcdbg("ERROR: I2C_TRANSFER failed: %d\n", ret) + return ret; + } + + /* Format the return time */ + /* Return seconds (0-61) */ + + tp->tm_sec = rtc_bcd2bin(buffer[1] & DS3231_TIME_SEC_BCDMASK); + + /* Return minutes (0-59) */ + + tp->tm_min = rtc_bcd2bin(buffer[2] & DS3231_TIME_MIN_BCDMASK); + + /* Return hour (0-23). This assumes 24-hour time was set. */ + + tp->tm_hour = rtc_bcd2bin(buffer[3] & DS3231_TIME_HOUR24_BCDMASK); + + #if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED) + /* Return the day of the week (0-6) */ + + tp->tm_wday = (rtc_bcd2bin(buffer[4]) & DS3231_TIME_DAY_MASK)- 1; +#endif + + /* Return the day of the month (1-31) */ + + tp->tm_mday = rtc_bcd2bin(buffer[5] & DS3231_TIME_DATE_BCDMASK); + + /* Return the month (0-11) */ + + tp->tm_mon = rtc_bcd2bin(buffer[6] & DS3231_TIME_MONTH_BCDMASK) - 1; + + /* Return the years since 1990 */ + + tmp = rtc_bcd2bin(buffer[7] & DS3231_TIME_YEAR_BCDMASK); + + if ((buffer[6] & DS3231_TIME_CENTURY_MASK) == DS3231_TIME_1900) + { + tp->tm_year = tmp; + } + else + { + tp->tm_year = tmp + 100; + } + + rtc_dumptime(tp, "Returning"); + return OK; +} + +/************************************************************************************ + * Name: up_rtc_settime + * + * Description: + * Set the RTC to the provided time. All RTC implementations must be able to + * set their time based on a standard timespec. + * + * 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) +{ + struct i2c_msg_s msg; + struct tm newtm; + time_t newtime; + uint8_t buffer[8]; + uint8_t century; + uint8_t year; + int ret; + + rtc_dumptime(tp, "Setting time"); + + /* Get the broken out time */ + + newtime = (time_t)tp->tv_sec; + if (tp->tv_nsec >= 500000000) + { + /* Round up */ + + newtime++; + } + + #ifdef CONFIG_LIBC_LOCALTIME + if (localtime_r(&newtime, &newtm) == NULL) + { + rtcdbg("ERROR: localtime_r failed\n") + return -EINVAL; + } +#else + if (gmtime_r(&newtime, &newtm) == NULL) + { + rtcdbg("ERROR: gmtime_r failed\n") + return -EINVAL; + } +#endif + + rtc_dumptime(&tm, "New time"); + + /* Construct the message */ + /* Write starting with the seconds regiser */ + + buffer[0] = DS3231_TIME_SECR; + + /* Save seconds (0-59) converted to BCD */ + + buffer[1] = rtc_bin2bcd(newtm.tm_sec); + + /* Save minutes (0-59) converted to BCD */ + + buffer[2] = rtc_bin2bcd(newtm.tm_min); + + /* Save hour (0-23) with 24-hour time indicatin */ + + buffer[3] = rtc_bin2bcd(newtm.tm_hour) | DS3231_TIME_24; + + /* Save the day of the week (1-7) */ + +#if defined(CONFIG_LIBC_LOCALTIME) || defined(CONFIG_TIME_EXTENDED) + buffer[4] = rtc_bin2bcd(newtm.tm_wday + 1); +#else + buffer[4] = 1; +#endif + + /* Save the day of the week (1-31) */ + + buffer[5] = rtc_bin2bcd(newtm.tm_mday); + + /* Handle years in the 20th vs the 21st century */ + + if (newtm.tm_year < 100) + { + /* Convert years in the range 1900-1999 */ + + century = DS3231_TIME_1900; + year = newtm.tm_year; + } + else + { + /* Convert years in the range 2000-2099 */ + + century = DS3231_TIME_2000; + year = newtm.tm_year - 100; + } + + /* Save the month (1-12) with century */ + + buffer[6] = rtc_bin2bcd(newtm.tm_mon + 1) | century; + + /* Save the year */ + + buffer[7] = year; + + /* Setup the I2C message */ + + msg.addr = DS3231_I2C_ADDRESS; + msg.flags = 0; + msg.buffer = buffer; + msg.length = 8; + + /* Configure I2C before using it */ + + I2C_SETFREQUENCY(g_ds3231.i2c, CONFIG_DS3231_I2C_FREQUENCY); + + /* Perform the transfer (This could be done with I2C_READ) */ + + ret = I2C_TRANSFER(g_ds3231.i2c, &msg, 1); + if (ret < 0) + { + rtcdbg("ERROR: I2C_TRANSFER failed: %d\n", ret) + } + + return ret; +} + +#endif /* CONFIG_RTC_DS3231 */ diff --git a/drivers/timers/ds3231.h b/drivers/timers/ds3231.h new file mode 100644 index 0000000000..4c2a4cbc14 --- /dev/null +++ b/drivers/timers/ds3231.h @@ -0,0 +1,274 @@ +/**************************************************************************** + * drivers/timers/ds3231.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 __DRIVERS_TIMERS_DS3231_H +#define __DRIVERS_TIMERS_DS3231_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DS3231_TIME_SECR 0x00 /* Seconds register */ +# define DS3231_TIME_SEC_SHIFT 0 /* Bits 0-3: Seconds, range 0-9 */ +# define DS3231_TIME_SEC_MASK (15 << DS3231_TIME_SEC_SHIFT) +# define DS3231_TIME_SEC(n) ((uint8_t)(n) << DS3231_TIME_SEC_SHIFT) +# define DS3231_TIME_10SEC_SHIFT 4 /* Bits 4-6: 10 seconds, range 0-5 */ +# define DS3231_TIME_10SEC_MASK (7 << DS3231_TIME_10SEC_SHIFT) +# define DS3231_TIME_10SEC(n) ((uint8_t)(n) << DS3231_TIME_10SEC_SHIFT) +# define DS3231_TIME_SEC_BCDMASK (DS3231_TIME_SEC_MASK | DS3231_TIME_10SEC_MASK) + +#define DS3231_TIME_MINR 0x01 /* Minutes register */ +# define DS3231_TIME_MIN_SHIFT 0 /* Bits 0-3: Minutes, range 0-9 */ +# define DS3231_TIME_MIN_MASK (15 << DS3231_TIME_MIN_SHIFT) +# define DS3231_TIME_MIN(n) ((uint8_t)(n) << DS3231_TIME_MIN_SHIFT) +# define DS3231_TIME_10MIN_SHIFT 4 /* Bits 4-6: 10 minutes, range 0-5 */ +# define DS3231_TIME_10MIN_MASK (7 << DS3231_TIME_10MIN_SHIFT) +# define DS3231_TIME_10MIN(n) ((uint8_t)(n) << DS3231_TIME_10MIN_SHIFT) +# define DS3231_TIME_MIN_BCDMASK (DS3231_TIME_MIN_MASK | DS3231_TIME_10MIN_MASK) + +#define DS3231_TIME_HOURR 0x02 /* Hours register */ +# define DS3231_TIME_HOUR_SHIFT 0 /* Bits 0-3: Hours, range 0-9 */ +# define DS3231_TIME_HOUR_MASK (15 << DS3231_TIME_HOUR_SHIFT) +# define DS3231_TIME_HOUR(n) ((uint8_t)(n) << DS3231_TIME_HOUR_SHIFT) +# define DS3231_TIME_10HOUR12_SHIFT 4 /* Bit 4: 10 hours, range 0-1 */ +# define DS3231_TIME_10HOUR12_MASK (1 << DS3231_TIME_10HOUR12_SHIFT) +# define DS3231_TIME_10HOUR12(n) ((uint8_t)(n) << DS3231_TIME_10HOUR12_SHIFT) +# define DS3231_TIME_10HOUR24_SHIFT 4 /* Bits 4-5: 10 hours, range 0-2 */ +# define DS3231_TIME_10HOUR24_MASK (3 << DS3231_TIME_10HOUR24_SHIFT) +# define DS3231_TIME_10HOUR24(n) ((uint8_t)(n) << DS3231_TIME_10HOUR24_SHIFT) +# define DS3231_TIME_HOUR12_BCDMASK (DS3231_TIME_HOUR_MASK | DS3231_TIME_10HOUR12_MASK) +# define DS3231_TIME_HOUR24_BCDMASK (DS3231_TIME_HOUR_MASK | DS3231_TIME_10HOUR24_MASK) +# define DS3231_TIME_AMPM_SHIFT 5 /* Bit 5: AM/PM Indication */ +# define DS3231_TIME_AMPM_MASK (1 << DS3231_TIME_AMPM_SHIFT) +# define DS3231_TIME_AM ((uint8_t)(0) << DS3231_TIME_AMPM_SHIFT) +# define DS3231_TIME_PM ((uint8_t)(1) << DS3231_TIME_AMPM_SHIFT) +# define DS3231_TIME_1224_SHIFT 6 /* Bit 6: 12/24 Indication */ +# define DS3231_TIME_1224_MASK (1 << DS3231_TIME_1224_SHIFT) +# define DS3231_TIME_24 ((uint8_t)(0) << DS3231_TIME_1224_SHIFT) +# define DS3231_TIME_12 ((uint8_t)(1) << DS3231_TIME_1224_SHIFT) + +#define DS3231_TIME_DAYR 0x03 /* Day of the week register */ +# define DS3231_TIME_DAY_SHIFT 0 /* Bits 0-3: Day of the week, range 1-7 */ +# define DS3231_TIME_DAY_MASK (7 << DS3231_TIME_DAY_SHIFT) +# define DS3231_TIME_DAY(n) ((uint8_t)(n) << DS3231_TIME_DAY_SHIFT) + +#define DS3231_TIME_DATER 0x04 /* Date register */ +# define DS3231_TIME_DATE_SHIFT 0 /* Bits 0-3: Days, range 0-9 */ +# define DS3231_TIME_DATE_MASK (15 << DS3231_TIME_DATE_SHIFT) +# define DS3231_TIME_DATE(n) ((uint8_t)(n) << DS3231_TIME_DATE_SHIFT) +# define DS3231_TIME_10DATE_SHIFT 4 /* Bits 4-5: 10 days, range 0-5 */ +# define DS3231_TIME_10DATE_MASK (3 << DS3231_TIME_10DATE_SHIFT) +# define DS3231_TIME_10DATE(n) ((uint8_t)(n) << DS3231_TIME_10DATE_SHIFT) +# define DS3231_TIME_DATE_BCDMASK (DS3231_TIME_DATE_MASK | DS3231_TIME_10DATE_MASK) + +#define DS3231_TIME_MONTHR 0x05 /* Month register */ +# define DS3231_TIME_MONTH_SHIFT 0 /* Bits 0-3: Month, range 0-9 */ +# define DS3231_TIME_MONTH_MASK (15 << DS3231_TIME_MONTH_SHIFT) +# define DS3231_TIME_MONTH(n) ((uint8_t)(n) << DS3231_TIME_MONTH_SHIFT) +# define DS3231_TIME_10MONTH_SHIFT 4 /* Bit 4: 10 month, range 0-1 */ +# define DS3231_TIME_10MONTH_MASK (1 << DS3231_TIME_10MONTH_SHIFT) +# define DS3231_TIME_10MONTH(n) ((uint8_t)(n) << DS3231_TIME_10MONTH_SHIFT) +# define DS3231_TIME_MONTH_BCDMASK (DS3231_TIME_MONTH_MASK | DS3231_TIME_10MONTH_MASK) +# define DS3231_TIME_CENTURY_SHIFT 7 /* Bit 7: AM/PM Indication */ +# define DS3231_TIME_CENTURY_MASK (1 << DS3231_TIME_CENTURY_SHIFT) +# define DS3231_TIME_1900 ((uint8_t)(0) << DS3231_TIME_CENTURY_SHIFT) +# define DS3231_TIME_2000 ((uint8_t)(1) << DS3231_TIME_CENTURY_SHIFT) + +#define DS3231_TIME_YEARR 0x06 /* Date register */ +# define DS3231_TIME_YEAR_SHIFT 0 /* Bits 0-3: Year, range 0-9 */ +# define DS3231_TIME_YEAR_MASK (15 << DS3231_TIME_YEAR_SHIFT) +# define DS3231_TIME_YEAR(n) ((uint8_t)(n) << DS3231_TIME_YEAR_SHIFT) +# define DS3231_TIME_10YEAR_SHIFT 4 /* Bits 4-7: 10 year, range 0-9 */ +# define DS3231_TIME_10YEAR_MASK (15 << DS3231_TIME_10YEAR_SHIFT) +# define DS3231_TIME_10YEAR(n) ((uint8_t)(n) << DS3231_TIME_10YEAR_SHIFT) +# define DS3231_TIME_YEAR_BCDMASK (DS3231_TIME_YEAR_MASK | DS3231_TIME_10YEAR_MASK) + +#define DS3231_ALARM1_SECR 0x07 /* Alarm1 seconds register */ +# define DS3231_ALARM1_SEC_SHIFT 0 /* Bits 0-3: Seconds, range 0-9 */ +# define DS3231_ALARM1_SEC_MASK (15 << DS3231_ALARM1_SEC_SHIFT) +# define DS3231_ALARM1_SEC(n) ((uint8_t)(n) << DS3231_ALARM1_SEC_SHIFT) +# define DS3231_ALARM1_10SEC_SHIFT 4 /* Bits 4-6: 10 seconds, range 0-5 */ +# define DS3231_ALARM1_10SEC_MASK (7 << DS3231_ALARM1_10SEC_SHIFT) +# define DS3231_ALARM1_10SEC(n) ((uint8_t)(n) << DS3231_ALARM1_10SEC_SHIFT) +# define DS3231_ALARM1_SEC_BCDMASK (DS3231_ALARM1_SEC_MASK | DS3231_ALARM1_10SEC_MASK) +# define DS3231_ALARM1_A1M1_SHIFT 7 /* Bits 7: A1M1 mask */ +# define DS3231_ALARM1_A1M1_MASK (1 << DS3231_ALARM1_A1M1_SHIFT) +# define DS3231_ALARM1_A1M1(n) ((uint8_t)(n) << DS3231_ALARM1_A1M1_SHIFT) + +#define DS3231_ALARM1_MINR 0x08 /* Alarm1 minutes register */ +# define DS3231_ALARM1_MIN_SHIFT 0 /* Bits 0-3: Minutes, range 0-9 */ +# define DS3231_ALARM1_MIN_MASK (15 << DS3231_ALARM1_MIN_SHIFT) +# define DS3231_ALARM1_MIN(n) ((uint8_t)(n) << DS3231_ALARM1_MIN_SHIFT) +# define DS3231_ALARM1_10MIN_SHIFT 4 /* Bits 4-6: 10 minutes, range 0-5 */ +# define DS3231_ALARM1_10MIN_MASK (7 << DS3231_ALARM1_10MIN_SHIFT) +# define DS3231_ALARM1_10MIN(n) ((uint8_t)(n) << DS3231_ALARM1_10MIN_SHIFT) +# define DS3231_ALARM1_MIN_BCDMASK (DS3231_ALARM1_MIN_MASK | DS3231_ALARM1_10MIN_MASK) +# define DS3231_ALARM1_A1M2_SHIFT 7 /* Bits 7: A1M2 mask */ +# define DS3231_ALARM1_A1M2_MASK (1 << DS3231_ALARM1_A1M2_SHIFT) +# define DS3231_ALARM1_A1M2(n) ((uint8_t)(n) << DS3231_ALARM1_A1M2_SHIFT) + +#define DS3231_ALARM1_HOURR 0x09 /* Alarm1 hours register */ +# define DS3231_ALARM1_HOUR_SHIFT 0 /* Bits 0-3: Hours, range 0-9 */ +# define DS3231_ALARM1_HOUR_MASK (15 << DS3231_ALARM1_HOUR_SHIFT) +# define DS3231_ALARM1_HOUR(n) ((uint8_t)(n) << DS3231_ALARM1_HOUR_SHIFT) +# define DS3231_ALARM1_10HOUR12_SHIFT 4 /* Bit 4: 10 hours, range 0-1 */ +# define DS3231_ALARM1_10HOUR12_MASK (1 << DS3231_ALARM1_10HOUR12_SHIFT) +# define DS3231_ALARM1_10HOUR12(n) ((uint8_t)(n) << DS3231_ALARM1_10HOUR12_SHIFT) +# define DS3231_ALARM1_10HOUR24_SHIFT 4 /* Bits 4-5: 10 hours, range 0-2 */ +# define DS3231_ALARM1_10HOUR24_MASK (3 << DS3231_ALARM1_10HOUR24_SHIFT) +# define DS3231_ALARM1_10HOUR24(n) ((uint8_t)(n) << DS3231_ALARM1_10HOUR24_SHIFT) +# define DS3231_ALARM1_HOUR12_BCDMASK (DS3231_ALARM1_HOUR_MASK | DS3231_ALARM1_10HOUR12_MASK) +# define DS3231_ALARM1_HOUR24_BCDMASK (DS3231_ALARM1_HOUR_MASK | DS3231_ALARM1_10HOUR24_MASK) +# define DS3231_ALARM1_AMPM_SHIFT 5 /* Bit 5: AM/PM Indication */ +# define DS3231_ALARM1_AMPM_MASK (1 << DS3231_ALARM1_AMPM_SHIFT) +# define DS3231_ALARM1_AM ((uint8_t)(0) << DS3231_ALARM1_AMPM_SHIFT) +# define DS3231_ALARM1_PM ((uint8_t)(1) << DS3231_ALARM1_AMPM_SHIFT) +# define DS3231_ALARM1_1224_SHIFT 6 /* Bit 6: 12/24 Indication */ +# define DS3231_ALARM1_1224_MASK (1 << DS3231_ALARM1_1224_SHIFT) +# define DS3231_ALARM1_12 ((uint8_t)(0) << DS3231_ALARM1_1224_SHIFT) +# define DS3231_ALARM1_24 ((uint8_t)(1) << DS3231_ALARM1_1224_SHIFT) +# define DS3231_ALARM1_A1M3_SHIFT 7 /* Bits 7: A1M3 mask */ +# define DS3231_ALARM1_A1M3_MASK (1 << DS3231_ALARM1_A1M3_SHIFT) +# define DS3231_ALARM1_A1M3(n) ((uint8_t)(n) << DS3231_ALARM1_A1M3_SHIFT) + +#define DS3231_ALARM1_DAYDATER 0x0a /* Alarm1 date / day of the week register */ +# define DS3231_ALARM1_DAY_SHIFT 0 /* Bits 0-3: Day of the week, range 1-7 */ +# define DS3231_ALARM1_DAY_MASK (7 << DS3231_ALARM1_DAY_SHIFT) +# define DS3231_ALARM1_DAY(n) ((uint8_t)(n) << DS3231_ALARM1_DAY_SHIFT) +# define DS3231_ALARM1_DATE_SHIFT 0 /* Bits 0-3: Days, range 0-9 */ +# define DS3231_ALARM1_DATE_MASK (15 << DS3231_ALARM1_DATE_SHIFT) +# define DS3231_ALARM1_DATE(n) ((uint8_t)(n) << DS3231_ALARM1_DATE_SHIFT) +# define DS3231_ALARM1_10DATE_SHIFT 4 /* Bits 4-5: 10 days, range 0-5 */ +# define DS3231_ALARM1_10DATE_MASK (3 << DS3231_ALARM1_10DATE_SHIFT) +# define DS3231_ALARM1_10DATE(n) ((uint8_t)(n) << DS3231_ALARM1_10DATE_SHIFT) +# define DS3231_ALARM1_DATE_BCDMASK (DS3231_ALARM1_DATE_MASK | DS3231_ALARM1_10DATE_MASK) +# define DS3231_ALARM1_DYDT_SHIFT 6 /* Bits 6: DY/DT */ +# define DS3231_ALARM1_DYDT_MASK (1 << DS3231_ALARM1_DYDT_SHIFT) +# define DS3231_ALARM1_DYDT_DATE ((uint8_t)(0) << DS3231_ALARM1_DYDT_SHIFT) +# define DS3231_ALARM1_DYDT_DAY ((uint8_t)(1) << DS3231_ALARM1_DYDT_SHIFT) +# define DS3231_ALARM1_A1M4_SHIFT 7 /* Bits 7: A1M4 mask */ +# define DS3231_ALARM1_A1M4_MASK (1 << DS3231_ALARM1_A1M4_SHIFT) +# define DS3231_ALARM1_A1M4(n) ((uint8_t)(n) << DS3231_ALARM1_A1M4_SHIFT) + +#define DS3231_ALARM2_MINR 0x0b /* Alarm2 minutes register */ +# define DS3231_ALARM2_MIN_SHIFT 0 /* Bits 0-3: Minutes, range 0-9 */ +# define DS3231_ALARM2_MIN_MASK (15 << DS3231_ALARM2_MIN_SHIFT) +# define DS3231_ALARM2_MIN(n) ((uint8_t)(n) << DS3231_ALARM2_MIN_SHIFT) +# define DS3231_ALARM2_10MIN_SHIFT 4 /* Bits 4-6: 10 minutes, range 0-5 */ +# define DS3231_ALARM2_10MIN_MASK (7 << DS3231_ALARM2_10MIN_SHIFT) +# define DS3231_ALARM2_10MIN(n) ((uint8_t)(n) << DS3231_ALARM2_10MIN_SHIFT) +# define DS3231_ALARM2_MIN_BCDMASK (DS3231_ALARM2_MIN_MASK | DS3231_ALARM2_10MIN_MASK) +# define DS3231_ALARM2_A2M2_SHIFT 7 /* Bits 7: A2M2 mask */ +# define DS3231_ALARM2_A2M2_MASK (1 << DS3231_ALARM2_A2M2_SHIFT) +# define DS3231_ALARM2_A2M2(n) ((uint8_t)(n) << DS3231_ALARM2_A2M2_SHIFT) + +#define DS3231_ALARM2_HOURR 0x0c /* Alarm2 hours register */ +# define DS3231_ALARM2_HOUR_SHIFT 0 /* Bits 0-3: Hours, range 0-9 */ +# define DS3231_ALARM2_HOUR_MASK (15 << DS3231_ALARM2_HOUR_SHIFT) +# define DS3231_ALARM2_HOUR(n) ((uint8_t)(n) << DS3231_ALARM2_HOUR_SHIFT) +# define DS3231_ALARM2_10HOUR12_SHIFT 4 /* Bit 4: 10 hours, range 0-1 */ +# define DS3231_ALARM2_10HOUR12_MASK (1 << DS3231_ALARM2_10HOUR12_SHIFT) +# define DS3231_ALARM2_10HOUR12(n) ((uint8_t)(n) << DS3231_ALARM2_10HOUR12_SHIFT) +# define DS3231_ALARM2_10HOUR24_SHIFT 4 /* Bits 4-5: 10 hours, range 0-2 */ +# define DS3231_ALARM2_10HOUR24_MASK (3 << DS3231_ALARM2_10HOUR24_SHIFT) +# define DS3231_ALARM2_10HOUR24(n) ((uint8_t)(n) << DS3231_ALARM2_10HOUR24_SHIFT) +# define DS3231_ALARM2_HOUR12_BCDMASK (DS3231_ALARM2_HOUR_MASK | DS3231_ALARM2_10HOUR12_MASK) +# define DS3231_ALARM2_HOUR24_BCDMASK (DS3231_ALARM2_HOUR_MASK | DS3231_ALARM2_10HOUR24_MASK) +# define DS3231_ALARM2_AMPM_SHIFT 5 /* Bit 5: AM/PM Indication */ +# define DS3231_ALARM2_AMPM_MASK (1 << DS3231_ALARM2_AMPM_SHIFT) +# define DS3231_ALARM2_AM ((uint8_t)(0) << DS3231_ALARM2_AMPM_SHIFT) +# define DS3231_ALARM2_PM ((uint8_t)(1) << DS3231_ALARM2_AMPM_SHIFT) +# define DS3231_ALARM2_1224_SHIFT 6 /* Bit 6: 12/24 Indication */ +# define DS3231_ALARM2_1224_MASK (1 << DS3231_ALARM2_1224_SHIFT) +# define DS3231_ALARM2_12 ((uint8_t)(0) << DS3231_ALARM2_1224_SHIFT) +# define DS3231_ALARM2_24 ((uint8_t)(1) << DS3231_ALARM2_1224_SHIFT) +# define DS3231_ALARM2_A2M3_SHIFT 7 /* Bits 7: A2M3 mask */ +# define DS3231_ALARM2_A2M3_MASK (1 << DS3231_ALARM2_A2M3_SHIFT) +# define DS3231_ALARM2_A2M3(n) ((uint8_t)(n) << DS3231_ALARM2_A2M3_SHIFT) + +#define DS3231_ALARM2_DAYDATER 0x0d /* Alarm2 date / day of the week register */ +# define DS3231_ALARM2_DAY_SHIFT 0 /* Bits 0-3: Day of the week, range 1-7 */ +# define DS3231_ALARM2_DAY_MASK (7 << DS3231_ALARM2_DAY_SHIFT) +# define DS3231_ALARM2_DAY(n) ((uint8_t)(n) << DS3231_ALARM2_DAY_SHIFT) +# define DS3231_ALARM2_DATE_SHIFT 0 /* Bits 0-3: Days, range 0-9 */ +# define DS3231_ALARM2_DATE_MASK (15 << DS3231_ALARM2_DATE_SHIFT) +# define DS3231_ALARM2_DATE(n) ((uint8_t)(n) << DS3231_ALARM2_DATE_SHIFT) +# define DS3231_ALARM2_10DATE_SHIFT 4 /* Bits 4-5: 10 days, range 0-5 */ +# define DS3231_ALARM2_10DATE_MASK (3 << DS3231_ALARM2_10DATE_SHIFT) +# define DS3231_ALARM2_10DATE(n) ((uint8_t)(n) << DS3231_ALARM2_10DATE_SHIFT) +# define DS3231_ALARM2_DATE_BCDMASK (DS3231_ALARM2_DATE_MASK | DS3231_ALARM2_10DATE_MASK) +# define DS3231_ALARM2_DYDT_SHIFT 6 /* Bits 6: DY/DT */ +# define DS3231_ALARM2_DYDT_MASK (1 << DS3231_ALARM2_DYDT_SHIFT) +# define DS3231_ALARM2_DYDT_DATE ((uint8_t)(0) << DS3231_ALARM2_DYDT_SHIFT) +# define DS3231_ALARM2_DYDT_DAY ((uint8_t)(1) << DS3231_ALARM2_DYDT_SHIFT) +# define DS3231_ALARM2_A2M4_SHIFT 7 /* Bits 7: A2M4 mask */ +# define DS3231_ALARM2_A2M4_MASK (1 << DS3231_ALARM2_A2M4_SHIFT) +# define DS3231_ALARM2_A2M4(n) ((uint8_t)(n) << DS3231_ALARM2_A2M4_SHIFT) + +#define DS3231_CR 0x0e /* Control register */ +# define DS3231_CR_A1IE (1 << 0) /* Bit 0: Alarm 1 interrupt enable */ +# define DS3231_CR_A2IE (1 << 1) /* Bit 1: Alarm 2 interrupt enable */ +# define DS3231_CR_INTCN (1 << 2) /* Bit 2: Interrupt control */ +# define DS3231_CR_RS_SHIFT (3) /* Bit 3-4: Rate selection */ +# define DS3231_CR_RS_MASK (3 << DS3231_CR_RS_SHIFT) +# define DS3231_CR_RS_1HZ (0 << DS3231_CR_RS_SHIFT) /* 1Hz */ +# define DS3231_CR_RS_1KHZ (1 << DS3231_CR_RS_SHIFT) /* 1.024kHz */ +# define DS3231_CR_RS_4KHZ (2 << DS3231_CR_RS_SHIFT) /* 4.096kHz */ +# define DS3231_CR_RS_8KHZ (3 << DS3231_CR_RS_SHIFT) /* 8.192kHz */ +# define DS3231_CR_CONV (1 << 5) /* Bit 5: Convert temperature */ +# define DS3231_CR_BBSQW (1 << 6) /* Bit 6: Battery backed square wave enable */ +# define DS3231_CR_EOSC (1 << 7) /* Bit 7: Enable oscillator */ + +#define DS3231_CSR 0x0f /* Control/status register */ +# define DS3231_CSR_A1F (1 << 0) /* Bit 0: Alarm 1 flag */ +# define DS3231_CSR_A2F (1 << 1) /* Bit 1: Alarm 2 flag */ +# define DS3231_CSR_BSY (1 << 2) /* Bit 2: Busy */ +# define DS3231_CSR_EN32kHz (1 << 3) /* Bit 3: Enable 32kHz output */ +# define DS3231_CSR_OSF (1 << 7) /* Bit 7: Oscillator stop flag */ + +#define DS3231_AGINGR 0x10 /* Aging offset register (8-bit, 2's complement) */ + +#define DS3231_TMPMR 0x11 /* MSB of temp register (8-bit, 2's complement) */ + +#define DS3231_TMPLR 0x12 /* LSB of temp register (2-bits) */ +# define DS3231_TMPLR_MASK 0xc0 /* Bits 6-7: LSB of temp register (2-bits) */ + +#endif /* __DRIVERS_TIMERS_DS3231_H */ diff --git a/include/nuttx/timers/ds3231.h b/include/nuttx/timers/ds3231.h new file mode 100644 index 0000000000..c67edb30cb --- /dev/null +++ b/include/nuttx/timers/ds3231.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * include/nuttx/timers/ds3231.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 __INCLUDE_NUTTX_TIMERS_DS3231_H +#define __INCLUDE_NUTTX_TIMERS_DS3231_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#ifdef CONFIG_RTC_DS3231 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/************************************************************************************ + * Name: ds3231_rtc_initialize + * + * Description: + * Initialize the hardware RTC per the selected 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 + * + ************************************************************************************/ + +struct i2c_dev_s; /* Forward reference */ +int ds3231_rtc_initialize(FAR struct i2c_dev_s *i2c); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_RTC_DS3231 */ +#endif /* __INCLUDE_NUTTX_TIMERS_DS3231_H */