From 36fbba5cb3bbc016f4cfd2eb8dcabeca684c081a Mon Sep 17 00:00:00 2001 From: Giampaolo Mancini Date: Thu, 13 Jan 2022 16:09:32 +0100 Subject: [PATCH 1/2] Add support for PCF8563T RTC --- examples/Basic/RealTimeClock/Helpers.h | 132 ++++++ .../Basic/RealTimeClock/RealTimeClock.ino | 67 +++ examples/Basic/RealTimeClock_Alarm/Helpers.h | 93 ++++ .../RealTimeClock_Alarm.ino | 133 ++++++ src/Arduino_EdgeControl.h | 3 +- src/EdgeControl_RealTimeClock.cpp | 413 ++++++++++++++++++ src/EdgeControl_RealTimeClock.h | 60 +++ 7 files changed, 900 insertions(+), 1 deletion(-) create mode 100644 examples/Basic/RealTimeClock/Helpers.h create mode 100644 examples/Basic/RealTimeClock/RealTimeClock.ino create mode 100644 examples/Basic/RealTimeClock_Alarm/Helpers.h create mode 100644 examples/Basic/RealTimeClock_Alarm/RealTimeClock_Alarm.ino create mode 100644 src/EdgeControl_RealTimeClock.cpp create mode 100644 src/EdgeControl_RealTimeClock.h diff --git a/examples/Basic/RealTimeClock/Helpers.h b/examples/Basic/RealTimeClock/Helpers.h new file mode 100644 index 0000000..ff26c31 --- /dev/null +++ b/examples/Basic/RealTimeClock/Helpers.h @@ -0,0 +1,132 @@ +#pragma once + +#include +#include +#include + +// Convert build time to UNIX time +time_t getBuildDateTime(bool local_time = true, int tz = 0) +{ + char s_month[5]; + int year; + + tm t; + time_t seconds; + + static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + sscanf(__DATE__, "%s %d %d", s_month, &t.tm_mday, &year); + sscanf(__TIME__, "%2d %*c %2d %*c %2d", &t.tm_hour, &t.tm_min, &t.tm_sec); + + // Find where is s_month in month_names. Deduce month value. + t.tm_mon = (strstr(month_names, s_month) - month_names) / 3 + 1; + t.tm_year = year - 1900; + _rtc_maketime(&t, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT); + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + seconds += (3600UL) * tz; + } else { + seconds -= (3600UL) * tz; + } + } + + return seconds; +} + +String getRTCDate() +{ + // APIs to get date fields. + auto years = RealTimeClock.getYears(); + auto months = RealTimeClock.getMonths(); + auto days = RealTimeClock.getDays(); + + char buf[12] {}; + + snprintf(buf, 11, "20%02d-%02d-%02d", years, months, days); + + return String(buf); +} + +String getRTCTime() +{ + // APIs to get time fields. + auto hours = RealTimeClock.getHours(); + auto minutes = RealTimeClock.getMinutes(); + auto seconds = RealTimeClock.getSeconds(); + + char buf[11] {}; + + snprintf(buf, 10, "%02d:%02d:%02d", hours, minutes, seconds); + + return String(buf); +} + +String getRTCDateTime() +{ + auto date = getRTCDate(); + auto time = getRTCTime(); + + auto dateTime = date + ' ' + time; + + return dateTime; +} + +String getLocaltime() +{ + char buffer[32]; + tm t; + _rtc_localtime(time(NULL), &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t); + return String(buffer); +} + +String getLocaltime(const time_t& build_time) +{ + char buffer[32]; + tm t; + _rtc_localtime(build_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t); + return String(buffer); +} + +String getLocaltime(const char* fmt, bool local_time = true, int tz = 0) +{ + char buffer[64]; + time_t tmp_time = time(NULL); + tm t; + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + tmp_time -= (3600UL) * tz; + } else { + tmp_time += (3600UL) * tz; + } + } + + _rtc_localtime(tmp_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 64, fmt, &t); + return String(buffer); +} + +String getLocaltime(const time_t build_time, const char* fmt, bool local_time = true, int tz = 0) +{ + char buffer[64]; + time_t tmp_time = build_time; + tm t; + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + tmp_time -= (3600UL) * tz; + } else { + tmp_time += (3600UL) * tz; + } + } + + _rtc_localtime(tmp_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 64, fmt, &t); + return String(buffer); +} diff --git a/examples/Basic/RealTimeClock/RealTimeClock.ino b/examples/Basic/RealTimeClock/RealTimeClock.ino new file mode 100644 index 0000000..c8d9a03 --- /dev/null +++ b/examples/Basic/RealTimeClock/RealTimeClock.ino @@ -0,0 +1,67 @@ +/* + Arduino Edge Control - RTC Example + + This sketch shows how to use the RTC (PCF8563T) on the Arduino + Edge Control and how to configure the RTC's time registers. + + Circuit: + - Arduino Edge Control + - CR2032 Battery + - Optional: Arduino Edge Control LCD + Button brekout + +*/ + +#include "Helpers.h" +#include + +void setup() +{ + pinMode(POWER_ON, INPUT); + + Serial.begin(9600); + + for (auto timeout = millis() + 2500l; !Serial && millis() < timeout; delay(250)) + ; + + Serial.println("Hello, Arduino Edge Control!"); + + EdgeControl.begin(); + + Power.on(PWR_3V3); + Power.on(PWR_VBAT); + + Wire.begin(); + delay(500); + + Serial.print("Initializating the Real Time Clock..."); + while (!RealTimeClock.begin()) { + Serial.println(" failed! Retrying..."); + delay(250); + } + Serial.println(" done!"); + + // APIs to set date's fields: years, months, days, hours, minutes and seconds + // The RTC time can be set as epoch, using one of the following two options: + // - Calendar time: RealTimeClock.setEpoch(years, months, days, hours, minutes, seconds); + // - UTC time: RealTimeClock.setEpoch(date_in_seconds); + + // Set the RTC only when LCD's PowerOn button is pressed. + // YMMV. + if (digitalRead(POWER_ON) == LOW) { + Serial.println("Resetting the RTC to Sketch Build Datetime!"); + auto buildDateTime = getBuildDateTime(); + RealTimeClock.setEpoch(buildDateTime); + Serial.print("Build "); + } +} + +void loop() +{ + Serial.print("Date: "); + Serial.println(getRTCDateTime()); + + Serial.print("Unix time: "); + Serial.println(time(NULL)); + + delay(1000); +} diff --git a/examples/Basic/RealTimeClock_Alarm/Helpers.h b/examples/Basic/RealTimeClock_Alarm/Helpers.h new file mode 100644 index 0000000..5ad9f7a --- /dev/null +++ b/examples/Basic/RealTimeClock_Alarm/Helpers.h @@ -0,0 +1,93 @@ +#pragma once + +#include +#include + +// Convert build time to UNIX time +time_t getBuildDateTime(bool local_time = true, int tz = 0) +{ + char s_month[5]; + int year; + + tm t; + time_t seconds; + + static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + sscanf(__DATE__, "%s %d %d", s_month, &t.tm_mday, &year); + sscanf(__TIME__, "%2d %*c %2d %*c %2d", &t.tm_hour, &t.tm_min, &t.tm_sec); + + // Find where is s_month in month_names. Deduce month value. + t.tm_mon = (strstr(month_names, s_month) - month_names) / 3 + 1; + t.tm_year = year - 1900; + _rtc_maketime(&t, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT); + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + seconds += (3600UL) * tz; + } else { + seconds -= (3600UL) * tz; + } + } + + return seconds; +} + +String getLocaltime() +{ + char buffer[32]; + tm t; + _rtc_localtime(time(NULL), &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t); + return String(buffer); +} + +String getLocaltime(const time_t& build_time) +{ + char buffer[32]; + tm t; + _rtc_localtime(build_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t); + return String(buffer); +} + +String getLocaltime(const char* fmt, bool local_time = true, int tz = 0) +{ + char buffer[64]; + time_t tmp_time = time(NULL); + tm t; + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + tmp_time -= (3600UL) * tz; + } else { + tmp_time += (3600UL) * tz; + } + } + + _rtc_localtime(tmp_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 64, fmt, &t); + return String(buffer); +} + +String getLocaltime(const time_t build_time, const char* fmt, bool local_time = true, int tz = 0) +{ + char buffer[64]; + time_t tmp_time = build_time; + tm t; + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + tmp_time -= (3600UL) * tz; + } else { + tmp_time += (3600UL) * tz; + } + } + + _rtc_localtime(tmp_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 64, fmt, &t); + return String(buffer); +} diff --git a/examples/Basic/RealTimeClock_Alarm/RealTimeClock_Alarm.ino b/examples/Basic/RealTimeClock_Alarm/RealTimeClock_Alarm.ino new file mode 100644 index 0000000..c0128b0 --- /dev/null +++ b/examples/Basic/RealTimeClock_Alarm/RealTimeClock_Alarm.ino @@ -0,0 +1,133 @@ +/* + Arduino Edge Control - RTC Alarm Example + + This sketch shows how to use the RTC (PCF8563T) on the Arduino + Edge Control and how to configure and use the RTC's alarm. + + Circuit: + - Arduino Edge Control + - CR2032 Battery + - Optional: Arduino Edge Control LCD + Button brekout + +*/ + +#include "Helpers.h" +#include + +volatile bool alarmFlag { false }; +byte alarmInterval { 1 }; + +void setup() +{ + Serial.begin(9600); + + for (auto timeout = millis() + 2500l; !Serial && millis() < timeout; delay(250)) + ; + + Serial.println("Hello, Arduino Edge Control!"); + + EdgeControl.begin(); + + Power.on(PWR_3V3); + Power.on(PWR_VBAT); + + Wire.begin(); + delay(500); + + Serial.print("Initializating the Real Time Clock..."); + while (!RealTimeClock.begin()) { + Serial.println(" failed! Retrying..."); + delay(250); + } + Serial.println(" done!"); + + // Set the RTC only when LCD's PowerOn button is pressed. + // YMMV. + if (digitalRead(POWER_ON) == LOW) { + auto buildDateTime = getBuildDateTime(); + RealTimeClock.setEpoch(buildDateTime); + Serial.print("Build "); + } + + Serial.print("Date: "); + Serial.println(getRTCDateTime()); + + // Enables Alarm on the RTC + RealTimeClock.enableAlarm(); + + // Set the minutes at which the alarm should rise + // Trigger in a minute + auto minutes = RealTimeClock.getMinutes(); + RealTimeClock.setMinuteAlarm(minutes + alarmInterval); + + // Attach an interrupt to the RTC interrupt pin + attachInterrupt( + digitalPinToInterrupt(IRQ_RTC), [] { alarmFlag = true; }, FALLING); + + Serial.println(); +} + +void loop() +{ + if (alarmFlag) { + Serial.println("Alarm!"); + + auto totalMinutes = RealTimeClock.getMinutes() + alarmInterval; + + // Take care of the 60-minute wrapping and... + auto minutesAlarm = totalMinutes % 60; + RealTimeClock.setMinuteAlarm(minutesAlarm); + + // don't forget to manage the hour increment. + if (totalMinutes >= 60) + RealTimeClock.setHourAlarm(RealTimeClock.getHours() + 1); + + RealTimeClock.clearAlarm(); + + // To disable the alarm uncomment the following line: + // RealTimeClock.disableAlarm(); + + alarmFlag = false; + } + + Serial.println(getRTCTime()); + delay(10000); +} + +String getRTCDate() +{ + // APIs to get date fields. + auto years = RealTimeClock.getYears(); + auto months = RealTimeClock.getMonths(); + auto days = RealTimeClock.getDays(); + + char buf[12] {}; + + snprintf(buf, 11, "20%02d-%02d-%02d", years, months, days); + + return String(buf); +} + +String getRTCTime() +{ + // APIs to get time fields. + auto hours = RealTimeClock.getHours(); + auto minutes = RealTimeClock.getMinutes(); + auto seconds = RealTimeClock.getSeconds(); + + char buf[11] {}; + + snprintf(buf, 10, "%02d:%02d:%02d", hours, minutes, seconds); + + return String(buf); +} + +String getRTCDateTime() +{ + auto date = getRTCDate(); + auto time = getRTCTime(); + + auto dateTime = date + ' ' + time; + + return dateTime; +} diff --git a/src/Arduino_EdgeControl.h b/src/Arduino_EdgeControl.h index 6366502..21bf14e 100644 --- a/src/Arduino_EdgeControl.h +++ b/src/Arduino_EdgeControl.h @@ -17,4 +17,5 @@ #include "EdgeControl_Input.h" #include "EdgeControl_Watermark.h" #include "EdgeControl_Latching.h" -#include "EdgeControl_SolidStateRelay.h" \ No newline at end of file +#include "EdgeControl_SolidStateRelay.h" +#include "EdgeControl_RealTimeClock.h" diff --git a/src/EdgeControl_RealTimeClock.cpp b/src/EdgeControl_RealTimeClock.cpp new file mode 100644 index 0000000..d458c3d --- /dev/null +++ b/src/EdgeControl_RealTimeClock.cpp @@ -0,0 +1,413 @@ +/* + This file is part of the Arduino Edge Control library. + Copyright (C) 2022 Arduino AG (http://www.arduino.cc/) + SPDX-License-Identifier: MPL-2.0 + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#include "EdgeControl_RealTimeClock.h" + +#define PCF8563T_ADDRESS 0x51 +#define PCF8563T_STATUS_2_REG 0X01 +#define PCF8563T_VL_SECONDS_REG 0X02 +#define PCF8563T_MINUTES_REG 0x03 +#define PCF8563T_HOURS_REG 0X04 +#define PCF8563T_DAYS_REG 0x05 +#define PCF8563T_MONTHS_REG 0x07 +#define PCF8563T_YEARS_REG 0x08 + +// alarm management +#define PCF8563T_MINUTE_ALARM_REG 0x09 +#define PCF8563T_MINUTE_ALARM_AE_M_MASK 0x80 +#define PCF8563T_MINUTE_ALARM_ON 0x7F + +#define PCF8563T_HOUR_ALARM_REG 0x0A +#define PCF8563T_HOUR_ALARM_AE_H_MASK 0x80 +#define PCF8563T_HOUR_ALARM_ON 0x7F + +#define PCF8563T_DAY_ALARM_REG 0x0B +#define PCF8563T_DAY_ALARM_AE_D_MASK 0x80 +#define PCF8563T_DAY_ALARM_ON 0x7F + +#define PCF8563T_TIMER_CONTROL_REG 0X0E +#define PCF8563T_TIMER_CONTROL_ON 0x80 +#define PCF8563T_TIMER_CONTROL_OFF 0x7F + +#define PCF8563T_STATUS_2_AIE_MASK 0x02 +#define PCF8563T_STATUS_2_CLEAR_INT 0xF7 +#define PCF8563T_STATUS_2_INT_OFF 0x7d + +/** + * Object constructor + * + */ +EdgeControl_RealTimeClockClass::EdgeControl_RealTimeClockClass() +{ +} + +/** + * Start the communication with the RTC + * Initialize I2C (Wire) bus and check if the chip is connected by sending an ACK on the I2C bus. + * @return true if the RTC Controller is on the I2C bus, false if it is not. + * + */ +bool EdgeControl_RealTimeClockClass::begin() +{ + Wire.beginTransmission(PCF8563T_ADDRESS); + if (!Wire.endTransmission()) { + return true; + } + return false; +} + +/** + * Set Year number's value + * Save an unsigned byte with the Year's value + * @param years Year's unsigned byte + */ +void EdgeControl_RealTimeClockClass::setYears(uint8_t years) +{ + uint8_t dec = years / 10; + uint8_t unit = years - (dec * 10); + writeByte(PCF8563T_YEARS_REG, ((dec << 4) + unit)); +} + +/** + * Set Month number's value + * Save an unsigned byte with the Month's value + * @param months Month's unsigned byte (0 to 12) + */ +void EdgeControl_RealTimeClockClass::setMonths(uint8_t months) +{ + uint8_t offset = 0; + if (months > 9) { + offset = 6; + } + writeByte(PCF8563T_MONTHS_REG, months + offset); +} + +/** + * Set Day number's value + * Save an unsigned byte with the Day's value + * @param days day's unsigned byte + */ +void EdgeControl_RealTimeClockClass::setDays(uint8_t days) +{ + uint8_t dec = days / 10; + uint8_t unit = days - (dec * 10); + writeByte(PCF8563T_DAYS_REG, ((dec << 4) + unit)); +} + +/** + * Set Hour(s) number's value + * Save an unsigned byte with the Hour(s) value + * @param hours hour unsigned byte (0 - 23) + */ +void EdgeControl_RealTimeClockClass::setHours(uint8_t hours) +{ + uint8_t dec = hours / 10; + uint8_t unit = hours - (dec * 10); + writeByte(PCF8563T_HOURS_REG, ((dec << 4) + unit)); // check formula on datasheet val + 6 * (val / 10) +} + +/** + * Set Minute(s) number's value + * Save an unsigned byte with the Minute(s) value + * @param minutes minute unsigned byte (0-60) + */ +void EdgeControl_RealTimeClockClass::setMinutes(uint8_t minutes) +{ + uint8_t dec = minutes / 10; + uint8_t unit = minutes - (dec * 10); + writeByte(PCF8563T_MINUTES_REG, ((dec << 4) + unit)); +} + +/** + * Set Second(s) number's value + * Save an unsigned byte with the Second(s) value + * @param seconds Second(s) unsigned byte (0-60) + */ +void EdgeControl_RealTimeClockClass::setSeconds(uint8_t seconds) +{ + uint8_t dec = seconds / 10; + uint8_t unit = seconds - (dec * 10); + writeByte(PCF8563T_VL_SECONDS_REG, ((dec << 4) + unit)); +} + +/** + * Get Year(s) number's value + * Get unsigned byte with the Year(s) value + * @return byte with Year(s) value + */ +uint8_t EdgeControl_RealTimeClockClass::getYears() +{ + uint8_t years = readByte(PCF8563T_YEARS_REG); + return (years & 0x0F) + ((years >> 4) * 10); +} + +/** + * Get Month(s) month's value + * Get unsigned byte with the month(s) value + * @return byte with Month(s) value + */ +uint8_t EdgeControl_RealTimeClockClass::getMonths() +{ + uint8_t months = readByte(PCF8563T_MONTHS_REG) & 0x1F; + if (months > 9) { + return months - 6; + } else { + return months; + } +} + +/** + * Get Day(s) number's value + * Get unsigned byte with the Day(s) value + * @return byte with Day(s) value + */ +uint8_t EdgeControl_RealTimeClockClass::getDays() +{ + uint8_t days = readByte(PCF8563T_DAYS_REG); + return ((days & 0x0F) + (((days >> 4) & 0x03) * 10)); +} + +/** + * Get Hour(s) number's value + * Get unsigned byte with the Hour(s) value + * @return byte with Hour(s) value + */ +uint8_t EdgeControl_RealTimeClockClass::getHours() +{ + uint8_t hours = readByte(PCF8563T_HOURS_REG) & 0x3F; + return (hours & 0x0F) + ((hours >> 4) * 10); +} + +/** + * Get Minute(s) number's value + * Get unsigned byte with the Minute(s) value + * @return byte with Minute(s) value + */ +uint8_t EdgeControl_RealTimeClockClass::getMinutes() +{ + uint8_t minutes = (readByte(PCF8563T_MINUTES_REG)) & 0x7F; + return (minutes & 0x0F) + ((minutes >> 4) * 10); +} + +/** + * Get Second(s) number's value + * Get unsigned byte with the Second(s) value + * @return byte with Second(s) value + */ +uint8_t EdgeControl_RealTimeClockClass::getSeconds() +{ + uint8_t seconds = readByte(PCF8563T_VL_SECONDS_REG) & 0x7F; + return (seconds & 0x0F) + ((seconds >> 4) * 10); +} + +/** + * Set time Epoch format + * + */ +void EdgeControl_RealTimeClockClass::setEpoch() +{ + struct tm time; + time.tm_sec = getSeconds(); + time.tm_min = getMinutes(); + time.tm_hour = getHours(); + time.tm_mday = getDays(); + time.tm_mon = getMonths() - 1; + time.tm_year = getYears() + 100; + time_t seconds; + _rtc_maketime(&time, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT); + set_time(seconds); +} + +/** + * Set time with Epoch format + * + * + * @param seconds number of seconds (time_t type) + */ +void EdgeControl_RealTimeClockClass::setEpoch(time_t seconds) +{ + struct tm time; + _rtc_localtime(seconds, &time, RTC_FULL_LEAP_YEAR_SUPPORT); + + setSeconds(time.tm_sec); + setMinutes(time.tm_min); + setHours(time.tm_hour); + setDays(time.tm_mday); + setMonths(time.tm_mon + 1); + setYears((time.tm_year - 100)); + set_time(seconds); +} + +/** + * Set time with Epoch format + * + * Convert the input values to Epoch format + * example: Tue, 06 Jul 2021 11:55:27 GMT -> 1625572527 + * + * @param years number of years + * @param mohths number of months + * @param days number of days + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + */ +void EdgeControl_RealTimeClockClass::setEpoch(uint8_t years, uint8_t months, uint8_t days, uint8_t hours, uint8_t minutes, uint8_t seconds) +{ + struct tm time; + time_t utcsec; + + time.tm_sec = seconds; + time.tm_min = minutes; + time.tm_hour = hours; + time.tm_mday = days; + time.tm_mon = months - 1; + time.tm_year = years + 100; // year since 1900 + + _rtc_maketime(&time, &utcsec, RTC_FULL_LEAP_YEAR_SUPPORT); + set_time(utcsec); +} + +/** + * Get epoch number + * Convert real time to difference between actual time and Epoch(Unix time) + * Saved into time_t type + * + * example: 1625572527 -> Tue, 06 Jul 2021 11:55:27 GMT + * + * @return number of seconds after Unix time (time_t type) + */ +time_t EdgeControl_RealTimeClockClass::getEpoch() +{ + struct tm time; + time_t seconds; + + time.tm_sec = getSeconds(); + time.tm_min = getMinutes(); + time.tm_hour = getHours(); + time.tm_mday = getDays(); + time.tm_mon = getMonths() - 1; + time.tm_year = getYears() + 100; // year since 1900 + + _rtc_maketime(&time, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT); + return seconds; +} + +/** + * Enable alarm + * + */ +void EdgeControl_RealTimeClockClass::enableAlarm() +{ + writeByte(PCF8563T_STATUS_2_REG, (readByte(PCF8563T_STATUS_2_REG) & PCF8563T_STATUS_2_CLEAR_INT) | PCF8563T_STATUS_2_AIE_MASK); +} + +/** + * Disable alarm + * + */ +void EdgeControl_RealTimeClockClass::disableAlarm() +{ + writeByte(PCF8563T_STATUS_2_REG, (readByte(PCF8563T_STATUS_2_REG) & PCF8563T_STATUS_2_INT_OFF)); +} + +/** + * Clear alarm status + * + */ +void EdgeControl_RealTimeClockClass::clearAlarm() +{ + writeByte(PCF8563T_STATUS_2_REG, (readByte(PCF8563T_STATUS_2_REG) & PCF8563T_STATUS_2_CLEAR_INT) | PCF8563T_STATUS_2_AIE_MASK); +} + +/** + * Set alarm's minute + * + * @param minutes minute(s) value for the Alarm (byte type) + */ +void EdgeControl_RealTimeClockClass::setMinuteAlarm(uint8_t minutes) +{ + uint8_t dec = minutes / 10; + uint8_t unit = minutes - (dec * 10); + uint8_t min_alarm = PCF8563T_MINUTE_ALARM_ON & ((dec << 4) + unit); + writeByte(PCF8563T_MINUTE_ALARM_REG, min_alarm); +} + +/** + * Disable and clear the minute of the Alarm + * + */ +void EdgeControl_RealTimeClockClass::disableMinuteAlarm() +{ + writeByte(PCF8563T_MINUTE_ALARM_REG, readByte(PCF8563T_MINUTE_ALARM_REG) | PCF8563T_MINUTE_ALARM_AE_M_MASK); +} + +/** + * Set Alarm's hour + * + * @param hours hour(s) value for the Alarm (byte type) + */ +void EdgeControl_RealTimeClockClass::setHourAlarm(uint8_t hours) +{ + uint8_t dec = hours / 10; + uint8_t unit = hours - (dec * 10); + uint8_t hour_alarm = PCF8563T_HOUR_ALARM_AE_H_MASK & ((dec << 4) + unit); + writeByte(PCF8563T_HOURS_REG, hour_alarm); // check formula on datasheet val + 6 * (val / 10) +} + +/** + * Disable and clear the hour of the Alarm + * + */ +void EdgeControl_RealTimeClockClass::disableHourAlarm() +{ + writeByte(PCF8563T_HOUR_ALARM_REG, readByte(PCF8563T_HOUR_ALARM_REG) | PCF8563T_HOUR_ALARM_AE_H_MASK); +} + +/** + * Set Alarm's day + * + * @param days day value for the Alarm (byte type) + */ +void EdgeControl_RealTimeClockClass::setDayAlarm(uint8_t days) +{ + uint8_t dec = days / 10; + uint8_t unit = days - (dec * 10); + uint8_t day_alarm = PCF8563T_DAY_ALARM_ON & ((dec << 4) + unit); + writeByte(PCF8563T_DAY_ALARM_REG, day_alarm); +} + +/** + * Disable and clear the day of the Alarm + * + */ +void EdgeControl_RealTimeClockClass::disableDayAlarm() +{ + writeByte(PCF8563T_DAY_ALARM_REG, readByte(PCF8563T_DAY_ALARM_REG) | PCF8563T_DAY_ALARM_AE_D_MASK); +} + +void EdgeControl_RealTimeClockClass::writeByte(uint8_t regAddres, uint8_t data) +{ + Wire.beginTransmission(PCF8563T_ADDRESS); + Wire.write(regAddres); + Wire.write(data); + Wire.endTransmission(); +} + +uint8_t EdgeControl_RealTimeClockClass::readByte(uint8_t regAddres) +{ + Wire.beginTransmission(PCF8563T_ADDRESS); + Wire.write(regAddres); // Day Register + Wire.endTransmission(); + Wire.requestFrom(PCF8563T_ADDRESS, 1); + + return Wire.read(); +} + +EdgeControl_RealTimeClockClass RealTimeClock {}; diff --git a/src/EdgeControl_RealTimeClock.h b/src/EdgeControl_RealTimeClock.h new file mode 100644 index 0000000..fcca651 --- /dev/null +++ b/src/EdgeControl_RealTimeClock.h @@ -0,0 +1,60 @@ +/* + This file is part of the Arduino Edge Control library. + Copyright (C) 2022 Arduino AG (http://www.arduino.cc/) + SPDX-License-Identifier: MPL-2.0 + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at https://mozilla.org/MPL/2.0/. +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#define IRQ_RTC IRQ_CH6 + +class EdgeControl_RealTimeClockClass { + +public: + EdgeControl_RealTimeClockClass(); + bool begin(); + void setYears(uint8_t years); + void setMonths(uint8_t months); + void setDays(uint8_t days); + void setHours(uint8_t hours); + void setMinutes(uint8_t minutes); + void setSeconds(uint8_t seconds); + + uint8_t getYears(); + uint8_t getMonths(); + uint8_t getDays(); + uint8_t getHours(); + uint8_t getMinutes(); + uint8_t getSeconds(); + + void setEpoch(); + void setEpoch(uint8_t years, uint8_t months, uint8_t days, uint8_t hours, uint8_t minutes, uint8_t seconds); + void setEpoch(time_t seconds); + time_t getEpoch(); + + void enableAlarm(); + void disableAlarm(); + void clearAlarm(); + void setMinuteAlarm(uint8_t minutes); + void disableMinuteAlarm(); + void setHourAlarm(uint8_t hours); + void disableHourAlarm(); + void setDayAlarm(uint8_t days); + void disableDayAlarm(); + +private: + void writeByte(uint8_t regAddres, uint8_t data); + uint8_t readByte(uint8_t regAddres); +}; + +extern EdgeControl_RealTimeClockClass RealTimeClock; From 33b5ba7f41b8c7fb9be287913612d18dcec1c108 Mon Sep 17 00:00:00 2001 From: Giampaolo Mancini Date: Thu, 13 Jan 2022 17:50:56 +0100 Subject: [PATCH 2/2] Fix spelling --- .../Application/IrrigationSimple/Helpers.cpp | 8 +- .../IrrigationSimple/TimeHelpers.cpp | 2 +- .../IrrigationSimple/TimeHelpers.h | 4 +- .../IrrigationSimpleLCD/Helpers.cpp | 8 +- .../IrrigationSimpleLCD/TimeHelpers.cpp | 2 +- .../IrrigationSimpleLCD/TimeHelpers.h | 4 +- .../Application/LowPowerDataLogger/Helpers.h | 10 +- examples/Application/RTCClock/Helpers.h | 10 +- .../Basic/RealTimeClock_LowPower/Helpers.h | 132 ++++++++++++++++++ .../RealTimeClock_LowPower.ino | 109 +++++++++++++++ 10 files changed, 265 insertions(+), 24 deletions(-) create mode 100644 examples/Basic/RealTimeClock_LowPower/Helpers.h create mode 100644 examples/Basic/RealTimeClock_LowPower/RealTimeClock_LowPower.ino diff --git a/examples/Application/IrrigationSimple/Helpers.cpp b/examples/Application/IrrigationSimple/Helpers.cpp index 534a61b..b426cae 100644 --- a/examples/Application/IrrigationSimple/Helpers.cpp +++ b/examples/Application/IrrigationSimple/Helpers.cpp @@ -3,23 +3,23 @@ /** * Set system and TimeAlarm clock from compile datetime or RTC */ -void setSystemClock(String compileDate, String compileTime) +void setSystemClock(String buildDate, String buildTime) { // Retrieve clock time from compile date... - auto buildTime = compileDateTimeToSystemTime(compileDate, compileTime, true, 2); + auto buildDateTime = buildDateTimeToSystemTime(buildDate, buildTime, true, 2); // ... ore use the one from integrated RTC. auto rtcTime = time(NULL); // Remember to connect at least the CR2032 battery // to keep the RTC running. - auto actualTime = rtcTime > buildTime ? rtcTime : buildTime; + auto actualTime = rtcTime > buildDateTime ? rtcTime : buildDateTime; // Set both system time and the alarms one set_time(actualTime); setTime(actualTime); Serial.print("Compile Date and Time: "); - Serial.println(getLocaltime(buildTime)); + Serial.println(getLocaltime(buildDateTime)); Serial.print("RTC Date and Time: "); Serial.println(getLocaltime(rtcTime)); Serial.print("System Clock: "); diff --git a/examples/Application/IrrigationSimple/TimeHelpers.cpp b/examples/Application/IrrigationSimple/TimeHelpers.cpp index 4451990..9162b6b 100644 --- a/examples/Application/IrrigationSimple/TimeHelpers.cpp +++ b/examples/Application/IrrigationSimple/TimeHelpers.cpp @@ -1,7 +1,7 @@ #include "TimeHelpers.h" // Convert compile time to system time -time_t compileDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) +time_t buildDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) { char s_month[5]; int year; diff --git a/examples/Application/IrrigationSimple/TimeHelpers.h b/examples/Application/IrrigationSimple/TimeHelpers.h index ec5c3ba..3164616 100644 --- a/examples/Application/IrrigationSimple/TimeHelpers.h +++ b/examples/Application/IrrigationSimple/TimeHelpers.h @@ -4,8 +4,8 @@ #include // Convert compile time to system time -time_t compileDateTimeToSystemTime(const String, const String, bool local_time, int tz); +time_t buildDateTimeToSystemTime(const String, const String, bool local_time, int tz); String getLocaltime(); String getLocaltime(const time_t &build_time); String getLocaltime(const char *fmt, bool local_time, int); -String getLocaltime(const time_t build_time, const char *fmt, bool local_time, int tz); \ No newline at end of file +String getLocaltime(const time_t build_time, const char *fmt, bool local_time, int tz); diff --git a/examples/Application/IrrigationSimpleLCD/Helpers.cpp b/examples/Application/IrrigationSimpleLCD/Helpers.cpp index becd575..2be8900 100644 --- a/examples/Application/IrrigationSimpleLCD/Helpers.cpp +++ b/examples/Application/IrrigationSimpleLCD/Helpers.cpp @@ -3,23 +3,23 @@ /** * Set system and TimeAlarm clock from compile datetime or RTC */ -void setSystemClock(String compileDate, String compileTime) +void setSystemClock(String buildDate, String buildTime) { // Retrieve clock time from compile date... - auto buildTime = compileDateTimeToSystemTime(compileDate, compileTime, true, 2); + auto buildDateTime = buildDateTimeToSystemTime(buildDate, buildTime, true, 2); // ... ore use the one from integrated RTC. auto rtcTime = time(NULL); // Remember to connect at least the CR2032 battery // to keep the RTC running. - auto actualTime = rtcTime > buildTime ? rtcTime : buildTime; + auto actualTime = rtcTime > buildDateTime ? rtcTime : buildDateTime; // Set both system time and the alarms one set_time(actualTime); setTime(actualTime); Serial.print("Compile Date and Time: "); - Serial.println(getLocaltime(buildTime)); + Serial.println(getLocaltime(buildDateTime)); Serial.print("RTC Date and Time: "); Serial.println(getLocaltime(rtcTime)); Serial.print("System Clock: "); diff --git a/examples/Application/IrrigationSimpleLCD/TimeHelpers.cpp b/examples/Application/IrrigationSimpleLCD/TimeHelpers.cpp index 4451990..9162b6b 100644 --- a/examples/Application/IrrigationSimpleLCD/TimeHelpers.cpp +++ b/examples/Application/IrrigationSimpleLCD/TimeHelpers.cpp @@ -1,7 +1,7 @@ #include "TimeHelpers.h" // Convert compile time to system time -time_t compileDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) +time_t buildDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) { char s_month[5]; int year; diff --git a/examples/Application/IrrigationSimpleLCD/TimeHelpers.h b/examples/Application/IrrigationSimpleLCD/TimeHelpers.h index ec5c3ba..3164616 100644 --- a/examples/Application/IrrigationSimpleLCD/TimeHelpers.h +++ b/examples/Application/IrrigationSimpleLCD/TimeHelpers.h @@ -4,8 +4,8 @@ #include // Convert compile time to system time -time_t compileDateTimeToSystemTime(const String, const String, bool local_time, int tz); +time_t buildDateTimeToSystemTime(const String, const String, bool local_time, int tz); String getLocaltime(); String getLocaltime(const time_t &build_time); String getLocaltime(const char *fmt, bool local_time, int); -String getLocaltime(const time_t build_time, const char *fmt, bool local_time, int tz); \ No newline at end of file +String getLocaltime(const time_t build_time, const char *fmt, bool local_time, int tz); diff --git a/examples/Application/LowPowerDataLogger/Helpers.h b/examples/Application/LowPowerDataLogger/Helpers.h index e47cc8d..5d9db8d 100644 --- a/examples/Application/LowPowerDataLogger/Helpers.h +++ b/examples/Application/LowPowerDataLogger/Helpers.h @@ -58,7 +58,7 @@ int getAverageInputRead(int pin, const size_t loops) } // Convert compile time to system time -time_t compileDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) +time_t buildDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) { char s_month[5]; int year; @@ -108,22 +108,22 @@ String getLocaltime(const time_t& build_time) /** * Set system clock from compile datetime or RTC */ -void setSystemClock(String compileDate, String compileTime) +void setSystemClock(String buildDate, String buildTime) { // Retrieve clock time from compile date... - auto buildTime = compileDateTimeToSystemTime(compileDate, compileTime, true, 2); + auto buildDateTime = buildDateTimeToSystemTime(buildDate, buildTime, true, 2); // ... ore use the one from integrated RTC. auto rtcTime = time(NULL); // Remember to connect at least the CR2032 battery // to keep the RTC running. - auto actualTime = rtcTime > buildTime ? rtcTime : buildTime; + auto actualTime = rtcTime > buildDateTime ? rtcTime : buildDateTime; // Set both system time set_time(actualTime); DebugSerial.print("Compile Date and Time: "); - DebugSerial.println(getLocaltime(buildTime)); + DebugSerial.println(getLocaltime(buildDateTime)); DebugSerial.print("RTC Date and Time: "); DebugSerial.println(getLocaltime(rtcTime)); DebugSerial.print("System Clock: "); diff --git a/examples/Application/RTCClock/Helpers.h b/examples/Application/RTCClock/Helpers.h index 87392bd..f0ffa10 100644 --- a/examples/Application/RTCClock/Helpers.h +++ b/examples/Application/RTCClock/Helpers.h @@ -6,7 +6,7 @@ // Convert compile time to system time -time_t compileDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) +time_t buildDateTimeToSystemTime(const String date, const String time, bool local_time = true, int tz = 0) { char s_month[5]; int year; @@ -56,22 +56,22 @@ String getLocaltime(const time_t& build_time) /** * Set system clock from compile datetime or RTC */ -void setSystemClock(String compileDate, String compileTime) +void setSystemClock(String buildDate, String buildTime) { // Retrieve clock time from compile date... - auto buildTime = compileDateTimeToSystemTime(compileDate, compileTime, true, 2); + auto buildDateTime = buildDateTimeToSystemTime(buildDate, buildTime, true, 2); // ... ore use the one from integrated RTC. auto rtcTime = time(NULL); // Remember to connect at least the CR2032 battery // to keep the RTC running. - auto actualTime = rtcTime > buildTime ? rtcTime : buildTime; + auto actualTime = rtcTime > buildDateTime ? rtcTime : buildDateTime; // Set both system time set_time(actualTime); Serial.print("Compile Date and Time: "); - Serial.println(getLocaltime(buildTime)); + Serial.println(getLocaltime(buildDateTime)); Serial.print("RTC Date and Time: "); Serial.println(getLocaltime(rtcTime)); Serial.print("System Clock: "); diff --git a/examples/Basic/RealTimeClock_LowPower/Helpers.h b/examples/Basic/RealTimeClock_LowPower/Helpers.h new file mode 100644 index 0000000..ff26c31 --- /dev/null +++ b/examples/Basic/RealTimeClock_LowPower/Helpers.h @@ -0,0 +1,132 @@ +#pragma once + +#include +#include +#include + +// Convert build time to UNIX time +time_t getBuildDateTime(bool local_time = true, int tz = 0) +{ + char s_month[5]; + int year; + + tm t; + time_t seconds; + + static const char month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + + sscanf(__DATE__, "%s %d %d", s_month, &t.tm_mday, &year); + sscanf(__TIME__, "%2d %*c %2d %*c %2d", &t.tm_hour, &t.tm_min, &t.tm_sec); + + // Find where is s_month in month_names. Deduce month value. + t.tm_mon = (strstr(month_names, s_month) - month_names) / 3 + 1; + t.tm_year = year - 1900; + _rtc_maketime(&t, &seconds, RTC_FULL_LEAP_YEAR_SUPPORT); + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + seconds += (3600UL) * tz; + } else { + seconds -= (3600UL) * tz; + } + } + + return seconds; +} + +String getRTCDate() +{ + // APIs to get date fields. + auto years = RealTimeClock.getYears(); + auto months = RealTimeClock.getMonths(); + auto days = RealTimeClock.getDays(); + + char buf[12] {}; + + snprintf(buf, 11, "20%02d-%02d-%02d", years, months, days); + + return String(buf); +} + +String getRTCTime() +{ + // APIs to get time fields. + auto hours = RealTimeClock.getHours(); + auto minutes = RealTimeClock.getMinutes(); + auto seconds = RealTimeClock.getSeconds(); + + char buf[11] {}; + + snprintf(buf, 10, "%02d:%02d:%02d", hours, minutes, seconds); + + return String(buf); +} + +String getRTCDateTime() +{ + auto date = getRTCDate(); + auto time = getRTCTime(); + + auto dateTime = date + ' ' + time; + + return dateTime; +} + +String getLocaltime() +{ + char buffer[32]; + tm t; + _rtc_localtime(time(NULL), &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t); + return String(buffer); +} + +String getLocaltime(const time_t& build_time) +{ + char buffer[32]; + tm t; + _rtc_localtime(build_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 32, "%Y-%m-%d %k:%M:%S", &t); + return String(buffer); +} + +String getLocaltime(const char* fmt, bool local_time = true, int tz = 0) +{ + char buffer[64]; + time_t tmp_time = time(NULL); + tm t; + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + tmp_time -= (3600UL) * tz; + } else { + tmp_time += (3600UL) * tz; + } + } + + _rtc_localtime(tmp_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 64, fmt, &t); + return String(buffer); +} + +String getLocaltime(const time_t build_time, const char* fmt, bool local_time = true, int tz = 0) +{ + char buffer[64]; + time_t tmp_time = build_time; + tm t; + + if (!local_time) { + if (tz > 200) { + tz = 0x100 - tz; // Handle negative values + tmp_time -= (3600UL) * tz; + } else { + tmp_time += (3600UL) * tz; + } + } + + _rtc_localtime(tmp_time, &t, RTC_FULL_LEAP_YEAR_SUPPORT); + strftime(buffer, 64, fmt, &t); + return String(buffer); +} diff --git a/examples/Basic/RealTimeClock_LowPower/RealTimeClock_LowPower.ino b/examples/Basic/RealTimeClock_LowPower/RealTimeClock_LowPower.ino new file mode 100644 index 0000000..114dc8e --- /dev/null +++ b/examples/Basic/RealTimeClock_LowPower/RealTimeClock_LowPower.ino @@ -0,0 +1,109 @@ +/* + Arduino Edge Control - RTC Low Power Example + + This sketch shows how to use the RTC (PCF8563T) on the Arduino + Edge Control and how to configure and use the RTC on Low Power mode. + + Circuit: + - Arduino Edge Control + - CR2032 Battery + - Optional: Arduino Edge Control LCD + Button brekout + +*/ + +#include "Helpers.h" +#include +#include + +void setup() +{ + Serial.begin(9600); + + for (auto timeout = millis() + 2500l; !Serial && millis() < timeout; delay(250)) + ; + + Serial.println("Hello, Arduino Edge Control!"); + + EdgeControl.begin(); + + Power.on(PWR_3V3); + Power.on(PWR_VBAT); + + Wire.begin(); + delay(500); + + Serial.print("Initializating the Real Time Clock..."); + while (!RealTimeClock.begin()) { + Serial.println(" failed! Retrying..."); + delay(250); + } + Serial.println(" done!"); + + // Set the RTC only when LCD's PowerOn button is pressed. + // YMMV. + if (digitalRead(POWER_ON) == LOW) { + auto buildDateTime = getBuildDateTime(); + RealTimeClock.setEpoch(buildDateTime); + Serial.print("Build "); + } + + Serial.print("Date: "); + Serial.println(getRTCDateTime()); + + delay(5000); + + Wire.end(); + Serial.end(); + Serial1.end(); + + Power.off(PWR_3V3); + Power.off(PWR_VBAT); + + mbed::mbed_file_handle(STDIN_FILENO)->enable_input(false); + PluggableUSBD().deinit(); +} + +void loop() +{ + delay(10000); +} + +void powerDown() +{ + pinMode(I2C_SDA, INPUT_PULLDOWN); + pinMode(I2C_SCL, INPUT_PULLDOWN); + pinMode(I2C_SDA1, INPUT_PULLDOWN); + pinMode(I2C_SCL1, INPUT_PULLDOWN); + + pinMode(VBAT_PROBE, INPUT_PULLDOWN); + + pinMode(CMD_TRIAC_1, INPUT_PULLDOWN); + pinMode(CMD_TRIAC_2, INPUT_PULLDOWN); + pinMode(CMD_TRIAC_3, INPUT_PULLDOWN); + pinMode(CMD_TRIAC_4, INPUT_PULLDOWN); + + pinMode(SENSOR_COMMON, INPUT_PULLDOWN); + pinMode(SENSOR_CALIB, INPUT_PULLDOWN); + pinMode(SENSOR_INPUT_ADC, INPUT_PULLDOWN); + pinMode(SENSOR_CAPTURE_A, INPUT_PULLDOWN); + pinMode(SENSOR_CAPTURE, INPUT_PULLDOWN); + + pinMode(PULSE_DIRECTION, INPUT_PULLDOWN); + pinMode(PULSE_STROBE, INPUT_PULLDOWN); + + pinMode(SD_CS, INPUT_PULLDOWN); + + pinMode(QSPIDCS, INPUT_PULLDOWN); + pinMode(GPIOCLK, INPUT_PULLDOWN); + pinMode(QSPID0, INPUT_PULLDOWN); + pinMode(QSPID1, INPUT_PULLDOWN); + pinMode(QSPID2, INPUT_PULLDOWN); + pinMode(QSPID3, INPUT_PULLDOWN); + + pinMode(IRQ_CH1, INPUT_PULLDOWN); + pinMode(IRQ_CH2, INPUT_PULLDOWN); + pinMode(IRQ_CH3, INPUT_PULLDOWN); + pinMode(IRQ_CH4, INPUT_PULLDOWN); + pinMode(IRQ_CH5, INPUT_PULLDOWN); + pinMode(IRQ_CH6, INPUT_PULLDOWN); +}