From f058214d421944fda3edd37f0793665f749bb02c Mon Sep 17 00:00:00 2001 From: Bogdan Ivanus Date: Fri, 24 Oct 2025 14:09:12 +0300 Subject: [PATCH] Introduced RTC library and configuration for Giga, H7, Opta, Nicla Sense and Nano 33 Ble. --- libraries/RTC/RTC.cpp | 491 ++++++++++++++++++ libraries/RTC/RTC.h | 87 ++++ libraries/RTC/examples/AlarmRTC/AlarmRTC.ino | 76 +++ .../CalibrationRTC/CalibrationRTC.ino | 40 ++ .../RTC/examples/EnhancedRTC/EnhancedRTC.ino | 72 +++ .../RTC/examples/SimpleRTC/SimpleRTC.ino | 23 + .../arduino_giga_r1_stm32h747xx_m7.conf | 6 + .../arduino_giga_r1_stm32h747xx_m7.overlay | 11 + .../arduino_nano_33_ble_nrf52840_sense.conf | 1 + ...arduino_nano_33_ble_nrf52840_sense.overlay | 5 + .../arduino_nano_33_ble_sense.overlay | 5 + .../arduino_nicla_sense_me_nrf52832.conf | 3 +- .../arduino_nicla_sense_me_nrf52832.overlay | 8 +- .../arduino_opta_stm32h747xx_m7.conf | 6 + .../arduino_opta_stm32h747xx_m7.overlay | 11 + .../arduino_portenta_h7_stm32h747xx_m7.conf | 6 + ...arduino_portenta_h7_stm32h747xx_m7.overlay | 11 + 17 files changed, 860 insertions(+), 2 deletions(-) create mode 100644 libraries/RTC/RTC.cpp create mode 100644 libraries/RTC/RTC.h create mode 100644 libraries/RTC/examples/AlarmRTC/AlarmRTC.ino create mode 100644 libraries/RTC/examples/CalibrationRTC/CalibrationRTC.ino create mode 100644 libraries/RTC/examples/EnhancedRTC/EnhancedRTC.ino create mode 100644 libraries/RTC/examples/SimpleRTC/SimpleRTC.ino diff --git a/libraries/RTC/RTC.cpp b/libraries/RTC/RTC.cpp new file mode 100644 index 000000000..26343b54d --- /dev/null +++ b/libraries/RTC/RTC.cpp @@ -0,0 +1,491 @@ +#include "RTC.h" +#include +#include +#include +#include +#include + +ArduinoRTC::~ArduinoRTC(){} + +bool ArduinoRTC::setYear(int year) +{ + bool status = false; + int currentYear, month, day, hour, minute, second; + int retVal = getTime(currentYear, month, day, hour, minute, second); + if(retVal == 0) + { + retVal = setTime(year, month, day, hour, minute, second); + if(retVal == 0u) + { + status = true; + } + } +} + +bool ArduinoRTC::setMonthOfYear(int month) +{ + bool status = false; + int year, currentMonth, day, hour, minute, second; + int retVal = getTime(year, currentMonth, day, hour, minute, second); + if(retVal == 0) + { + retVal = setTime(year, month, day, hour, minute, second); + if(retVal == 0u) + { + status = true; + } + } +} + +bool ArduinoRTC::setDayOfMonth(int day) +{ + bool status = false; + int year, month, currentDay, hour, minute, second; + int retVal = getTime(year, month, currentDay, hour, minute, second); + if(retVal == 0) + { + retVal = setTime(year, month, day, hour, minute, second); + if(retVal == 0u) + { + status = true; + } + } +} + +bool ArduinoRTC::setHour(int hour) +{ + bool status = false; + int year, month, day, currentHour, minute, second; + int retVal = getTime(year, month, day, currentHour, minute, second); + if(retVal == 0) + { + retVal = setTime(year, month, day, hour, minute, second); + if(retVal == 0u) + { + status = true; + } + } +} + +bool ArduinoRTC::setMinute(int minute) +{ + bool status = false; + int year, month, day, hour, currentMinute, second; + int retVal = getTime(year, month, day, hour, currentMinute, second); + if(retVal == 0) + { + retVal = setTime(year, month, day, hour, minute, second); + if(retVal == 0u) + { + status = true; + } + } +} + +bool ArduinoRTC::setSecond(int second) +{ + bool status = false; + int year, month, day, hour, minute, currentSecond; + int retVal = getTime(year, month, day, hour, minute, currentSecond); + if(retVal == 0) + { + retVal = setTime(year, month, day, hour, minute, second); + if(retVal == 0u) + { + status = true; + } + } +} + +int ArduinoRTC::getYear() +{ + int year, month, day, hour, minute, second; + int retVal = getTime(year, month, day, hour, minute, second); + if(retVal == 0) + { + return year; + } +} + +int ArduinoRTC::getMonth() +{ + int year, month, day, hour, minute, second; + int retVal = getTime(year, month, day, hour, minute, second); + if(retVal == 0) + { + return month; + } +} + +int ArduinoRTC::getDayOfMonth() +{ + int year, month, day, hour, minute, second; + int retVal = getTime(year, month, day, hour, minute, second); + if(retVal == 0) + { + return day; + } +} + +int ArduinoRTC::getHour() +{ + int year, month, day, hour, minute, second; + int retVal = getTime(year, month, day, hour, minute, second); + if(retVal == 0) + { + return hour; + } +} + +int ArduinoRTC::getMinutes() +{ + int year, month, day, hour, minute, second; + int retVal = getTime(year, month, day, hour, minute, second); + if(retVal == 0) + { + return minute; + } +} + +int ArduinoRTC::getSeconds() +{ + int year, month, day, hour, minute, second; + int retVal = getTime(year, month, day, hour, minute, second); + if(retVal == 0) + { + return second; + } +} + +#if defined(ARDUINO_GIGA) || defined(ARDUINO_PORTENTA_H7) || defined(ARDUINO_OPTA) +#define RTC_NODE DT_NODELABEL(rtc) + +ArduinoRTC::ArduinoRTC() +{ + rtc_dev = DEVICE_DT_GET(RTC_NODE); +} + +bool ArduinoRTC::begin() +{ + if (!device_is_ready(rtc_dev)) { + printk("RTC:: not ready\n"); + return false; + } + + // Register the alarm callback (even if not active yet) + rtc_alarm_set_callback(rtc_dev, alarmId, ArduinoRTC::alarmCallbackWrapper, this); + + return true; +} + +int ArduinoRTC::setTime(int year, int month, int day, int hour, int minute, int second) +{ + struct rtc_time time = { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + }; + return rtc_set_time(rtc_dev, &time); +} + +int ArduinoRTC::getTime(int &year, int &month, int &day, int &hour, int &minute, int &second) +{ + struct rtc_time time; + int ret = rtc_get_time(rtc_dev, &time); + if (ret < 0) return ret; + + year = time.tm_year + 1900; + month = time.tm_mon + 1; + day = time.tm_mday; + hour = time.tm_hour; + minute = time.tm_min; + second = time.tm_sec; + + return 0; +} + +// ------------------- ALARM API ------------------------- + +int ArduinoRTC::setAlarm(int year, int month, int day, int hour, int minute, int second, RTCAlarmCallback cb, void *user_data) +{ + struct rtc_time alarm_time = { + .tm_sec = second, + .tm_min = minute, + .tm_hour = hour, + .tm_mday = day, + .tm_mon = month - 1, + .tm_year = year - 1900, + }; + + uint16_t supported_mask = 0; + int ret = rtc_alarm_get_supported_fields(rtc_dev, alarmId, &supported_mask); + if (ret < 0) return ret; + + // Build the actual mask based on what we intend to set + uint16_t mask = 0; + if (supported_mask & RTC_ALARM_TIME_MASK_SECOND) mask |= RTC_ALARM_TIME_MASK_SECOND; + if (supported_mask & RTC_ALARM_TIME_MASK_MINUTE) mask |= RTC_ALARM_TIME_MASK_MINUTE; + if (supported_mask & RTC_ALARM_TIME_MASK_HOUR) mask |= RTC_ALARM_TIME_MASK_HOUR; + if (supported_mask & RTC_ALARM_TIME_MASK_MONTHDAY) mask |= RTC_ALARM_TIME_MASK_MONTHDAY; + if (supported_mask & RTC_ALARM_TIME_MASK_MONTH) mask |= RTC_ALARM_TIME_MASK_MONTH; + if (supported_mask & RTC_ALARM_TIME_MASK_YEAR) mask |= RTC_ALARM_TIME_MASK_YEAR; + + // Save user callback + userAlarmCallback = cb; + userAlarmCallbackData = user_data; + + return rtc_alarm_set_time(rtc_dev, alarmId, mask, &alarm_time); +} + +int ArduinoRTC::getAlarm(int &year, int &month, int &day, int &hour, int &minute, int &second) +{ + struct rtc_time alarm_time; + uint16_t mask = 0; + + int ret = rtc_alarm_get_time(rtc_dev, alarmId, &mask, &alarm_time); + if (ret < 0) return ret; + + year = alarm_time.tm_year + 1900; + month = alarm_time.tm_mon + 1; + day = alarm_time.tm_mday; + hour = alarm_time.tm_hour; + minute = alarm_time.tm_min; + second = alarm_time.tm_sec; + + return 0; +} + +int ArduinoRTC::cancelAlarm() +{ + // Seting time with value zero cancels it + struct rtc_time dummy = {0}; + return rtc_alarm_set_time(rtc_dev, alarmId, 0, &dummy); +} + +bool ArduinoRTC::isAlarmPending() +{ + int ret = rtc_alarm_is_pending(rtc_dev, alarmId); + return ret > 0; +} + +// ------------------- CALLBACKS ------------------------- + +void ArduinoRTC::alarmCallbackWrapper(const struct device *dev, uint16_t id, void *user_data) +{ + ArduinoRTC *self = static_cast(user_data); + if (self && self->userAlarmCallback) { + self->userAlarmCallback(self->userAlarmCallbackData); + } +} + +int ArduinoRTC::setUpdateCallback(RTCUpdateCallback cb, void *user_data) +{ + userUpdateCallback = cb; + userUpdateCallbackData = user_data; + + return rtc_update_set_callback(rtc_dev, ArduinoRTC::updateCallbackWrapper, this); +} + +void ArduinoRTC::updateCallbackWrapper(const struct device *dev, void *user_data) +{ + ArduinoRTC *self = static_cast(user_data); + if (self && self->userUpdateCallback) { + self->userUpdateCallback(self->userUpdateCallbackData); + } +} + +// ------------------- CALIBRATION ------------------------- + +int ArduinoRTC::setCalibration(int32_t calibration) +{ + return rtc_set_calibration(rtc_dev, calibration); +} + +int ArduinoRTC::getCalibration(int32_t &calibration) +{ + return rtc_get_calibration(rtc_dev, &calibration); +} + +#elif defined(ARDUINO_NANO33BLE) || defined(ARDUINO_NICLA_SENSE_ME) + +// ------------------- NRF Boards -------------------------- + +#define COUNTER_NODE DT_NODELABEL(rtc2) +LOG_MODULE_REGISTER(ArduinoRTC); + +// Static callback handler +void ArduinoRTC::alarmHandler(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data) +{ + ArduinoRTC *rtc = static_cast(user_data); + if (rtc->user_callback) { + rtc->user_callback(dev, chan_id, ticks, rtc->user_data); + } +} + +ArduinoRTC::ArduinoRTC() +{ + counter_dev = DEVICE_DT_GET(COUNTER_NODE); + timeOffset = 0; + user_callback = nullptr; + user_data = nullptr; +} + +// Initialize the RTC +bool ArduinoRTC::begin() +{ + if (!device_is_ready(counter_dev)) { + return false; + } + + counter_start(counter_dev); + return true; +} + +int ArduinoRTC::setTime(int year, int month, int day, int hour, int minute, int second) +{ + time_t target = datetimeToEpoch(year, month, day, hour, minute, second); + + uint32_t ticks; + counter_get_value(counter_dev, &ticks); + + uint32_t freq = counter_get_frequency(counter_dev); + if (freq == 0) { + return -1; + } + + timeOffset = target - (ticks / freq); + return 0; +} + +int ArduinoRTC::getTime(int &year, int &month, int &day, int &hour, int &minute, int &second) +{ + uint32_t ticks; + counter_get_value(counter_dev, &ticks); + + uint32_t freq = counter_get_frequency(counter_dev); + time_t now = timeOffset + (ticks / freq); + + epochToDatetime(now, year, month, day, hour, minute, second); + return 0; +} + +int ArduinoRTC::setAlarm(int year, int month, int day, int hour, int minute, int second, + void (*callback)(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data), + void *cb_user_data) +{ + time_t target_epoch = datetimeToEpoch(year, month, day, hour, minute, second); + uint32_t freq = counter_get_frequency(counter_dev); + uint32_t current_ticks; + + if (counter_get_value(counter_dev, ¤t_ticks) != 0) { + return -1; + } + + time_t current_epoch = timeOffset + (current_ticks / freq); + time_t delta_seconds = target_epoch - current_epoch; + + if (delta_seconds <= 0) { + return -1; + } + + uint32_t alarm_ticks = current_ticks + delta_seconds * freq; + + // Save user callback + user_callback = callback; + user_data = cb_user_data; + + alarm_cfg.flags = 0; // Absolute alarm + alarm_cfg.ticks = alarm_ticks; + alarm_cfg.callback = ArduinoRTC::alarmHandler; + alarm_cfg.user_data = this; + + int ret = counter_set_channel_alarm(counter_dev, 0, &alarm_cfg); + if (ret != 0) { + return ret; + } + + return 0; +} + +// Cancel alarm +void ArduinoRTC::cancelAlarm() +{ + counter_cancel_channel_alarm(counter_dev, 0); + user_callback = nullptr; + user_data = nullptr; +} + +// Utility functions +static const int days_in_month[] = { + 31, 28, 31, 30, 31, 30, + 31, 31, 30, 31, 30, 31 +}; + +static bool is_leap(int year) { + return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); +} + +time_t ArduinoRTC::datetimeToEpoch(int year, int month, int day, int hour, int minute, int second) +{ + int y = year; + int m = month; + time_t days = 0; + + for (int i = 1970; i < y; i++) { + days += is_leap(i) ? 366 : 365; + } + + for (int i = 1; i < m; i++) { + days += days_in_month[i - 1]; + if (i == 2 && is_leap(y)) { + days += 1; + } + } + + days += (day - 1); + + return (((days * 24 + hour) * 60 + minute) * 60 + second); +} + +void ArduinoRTC::epochToDatetime(time_t t, int &year, int &month, int &day, int &hour, int &minute, int &second) +{ + time_t seconds_in_day = t % 86400; + time_t days = t / 86400; + + hour = seconds_in_day / 3600; + minute = (seconds_in_day % 3600) / 60; + second = seconds_in_day % 60; + + year = 1970; + while (true) { + int days_in_year = is_leap(year) ? 366 : 365; + if (days >= days_in_year) { + days -= days_in_year; + year++; + } else { + break; + } + } + + int m = 0; + while (true) { + int dim = days_in_month[m]; + if (m == 1 && is_leap(year)) { + dim++; + } + + if (days >= dim) { + days -= dim; + m++; + } else { + break; + } + } + + month = m + 1; + day = days + 1; +} +#endif diff --git a/libraries/RTC/RTC.h b/libraries/RTC/RTC.h new file mode 100644 index 000000000..09823fde7 --- /dev/null +++ b/libraries/RTC/RTC.h @@ -0,0 +1,87 @@ +// RTC.h +#pragma once + +#include +#include +#include +#include +#include + +// Alarm callback types +typedef void (*RTCAlarmCallback)(void *user_data); +typedef void (*RTCUpdateCallback)(void *user_data); + +class ArduinoRTC { +public: + ArduinoRTC(); + bool begin(); + ~ArduinoRTC(); + + /* setters */ + bool setDayOfMonth(int day); + bool setMonthOfYear(int m); + bool setYear(int year); + bool setHour(int hour); + bool setMinute(int minute); + bool setSecond(int second); + + /* Getters */ + int getDayOfMonth(); + int getMonth(); + int getYear(); + int getHour(); + int getMinutes(); + int getSeconds(); + + int setTime(int year, int month, int day, int hour, int minute, int second); + int getTime(int &year, int &month, int &day, int &hour, int &minute, int &second); +#if defined(ARDUINO_GIGA) || defined(ARDUINO_PORTENTA_H7) || defined(ARDUINO_OPTA) + int setAlarm(int year, int month, int day, int hour, int minute, int second, + RTCAlarmCallback cb = nullptr, void *user_data = nullptr); + int cancelAlarm(); +#elif defined(ARDUINO_NANO33BLE) || defined(ARDUINO_NICLA_SENSE_ME) + int setAlarm(int year, int month, int day, int hour, int minute, int second, + void (*callback)(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data), + void *cb_user_data); + void cancelAlarm(); +#endif + +#if defined(ARDUINO_GIGA) || defined(ARDUINO_PORTENTA_H7) || defined(ARDUINO_OPTA) + // Optional APIs (only if supported) + int getAlarm(int &year, int &month, int &day, int &hour, int &minute, int &second); + bool isAlarmPending(); + int setUpdateCallback(RTCUpdateCallback cb, void *user_data); + int setCalibration(int32_t calibration); + int getCalibration(int32_t &calibration); +#endif + + +private: +#if defined(ARDUINO_GIGA) || defined(ARDUINO_PORTENTA_H7) || defined(ARDUINO_OPTA) + const struct device *rtc_dev; + + static void alarmCallbackWrapper(const struct device *dev, uint16_t id, void *user_data); + static void updateCallbackWrapper(const struct device *dev, void *user_data); + + RTCAlarmCallback userAlarmCallback = nullptr; + void *userAlarmCallbackData = nullptr; + + RTCUpdateCallback userUpdateCallback = nullptr; + void *userUpdateCallbackData = nullptr; + + uint16_t alarmId = 0; // default to alarm ID 0 +#elif defined(ARDUINO_NANO33BLE) || defined(ARDUINO_NICLA_SENSE_ME) + const struct device *counter_dev; + time_t timeOffset; + + // Alarm members + struct counter_alarm_cfg alarm_cfg; + void (*user_callback)(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data); + void *user_data; + + static void alarmHandler(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data); + + time_t datetimeToEpoch(int year, int month, int day, int hour, int minute, int second); + void epochToDatetime(time_t t, int &year, int &month, int &day, int &hour, int &minute, int &second); +#endif +}; \ No newline at end of file diff --git a/libraries/RTC/examples/AlarmRTC/AlarmRTC.ino b/libraries/RTC/examples/AlarmRTC/AlarmRTC.ino new file mode 100644 index 000000000..b19e95f4c --- /dev/null +++ b/libraries/RTC/examples/AlarmRTC/AlarmRTC.ino @@ -0,0 +1,76 @@ +/* +* This sketch sets an alarm 10 seconds in the future and handles it via a callback. +*/ + +#include "RTC.h" +#include + +ArduinoRTC rtc; + +char printBuffer[30]; // declare a buffer of large enough size for the message we want to display +int year, month, day, hour, minute, second; + +#if defined(ARDUINO_NICLA_SENSE_ME) || defined(ARDUINO_NANO33BLE) +void onAlarm(const struct device *dev, uint8_t chan_id, uint32_t ticks, void *user_data) { + char printBuffer[40]; + // Assuming user_data is a string or message you want to print + sprintf(printBuffer, "Alarm went off! Message: %s\n", (char *)user_data); + Serial.println(printBuffer); +} +#elif +void onAlarm(void *user_data) { + char printBuffer[40]; + sprintf(printBuffer, "Alarm went off! Message: %s\n", (char *)user_data); + Serial.println(printBuffer); +} +#endif + +void setup() { + int ret = 0xDEADBEEFu; // Starting with a custom value for the return which will definitely lead to failure if not changed to zero (i.e. success) by the functions below + char printBuffer[60]; + Serial.begin(115200); + delay(1000); + + if (!rtc.begin()) { + Serial.println("RTC not ready\n"); + return; + } + + int year, month, day, hour, minute, second; + ret = rtc.getTime(year, month, day, hour, minute, second); + if(ret != 0) + { + rtc.setTime(2025, 10, 21, 12, 0, 0); + } + + sprintf(printBuffer, "Current Time: %04d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second); + Serial.println(printBuffer); + + // Set alarm 10 seconds into the future + second += 5; + // Correct for minute rollover if necessary + if (second >= 60) { + second -= 60; + minute += 1; + } + + // The method also allows for registering a function callback which will be called when the alarm sets off and a display message which will be shown in the console + ret = rtc.setAlarm(year, month, day, hour, minute, second, onAlarm, (void *)"Wake up!!!"); + if (ret == 0) { + sprintf(printBuffer, "Alarm set for: %02d:%02d:%02d\n", hour, minute, second); + Serial.println(printBuffer); + } else { + sprintf(printBuffer, "Failed to set alarm (%d)\n", ret); + Serial.println(printBuffer); + } +} + +void loop() { + char printBuffer[30]; // declare a buffer of large enough size for the message we want to display + int y, m, d, h, min, s; + int status = rtc.getTime(y, m, d, h, min, s); + // Because the print() and println() functions do not support formatted output directly, we can use this trick to prepare a buffer with the string we want to show + sprintf(printBuffer, "Time is: %04d-%02d-%02d %02d:%02d:%02d", y, m, d, h, min, s); + Serial.println(printBuffer); + delay(1000); +} \ No newline at end of file diff --git a/libraries/RTC/examples/CalibrationRTC/CalibrationRTC.ino b/libraries/RTC/examples/CalibrationRTC/CalibrationRTC.ino new file mode 100644 index 000000000..8069ef028 --- /dev/null +++ b/libraries/RTC/examples/CalibrationRTC/CalibrationRTC.ino @@ -0,0 +1,40 @@ +#include "RTC.h" +#include + +// Doesn't work on the Opta for some reason. + + +ArduinoRTC rtc; + +void setup() { + char printBuffer[30]; + delay(1000); + Serial.begin(115200); + if (!rtc.begin()) { + printf("RTC not ready\n"); + return; + } + + int calib = 0; + if (rtc.getCalibration(calib) == 0) { + sprintf(printBuffer, "Current calibration: %d\n", calib); + Serial.println(printBuffer); + } else { + Serial.println("Failed to get calibration"); + } + + // Apply a small positive calibration (e.g., +1) + // This value is hardware-dependent, in a real application you should check the microcontroller's datasheet for the correct amount. + int32_t new_calib = calib + 1; + + if (rtc.setCalibration(new_calib) == 0) { + sprintf(printBuffer, "Calibration updated to: %d\n", new_calib); + Serial.println(printBuffer); + } else { + Serial.println("Failed to set calibration"); + } +} + +void loop() { + delay(5000); +} diff --git a/libraries/RTC/examples/EnhancedRTC/EnhancedRTC.ino b/libraries/RTC/examples/EnhancedRTC/EnhancedRTC.ino new file mode 100644 index 000000000..66f4f6670 --- /dev/null +++ b/libraries/RTC/examples/EnhancedRTC/EnhancedRTC.ino @@ -0,0 +1,72 @@ +#include "RTC.h" + +ArduinoRTC rtc; + +// 7-segment style representation for digits 0–9 and colon ":" +const char* bigDigits[11][3] = { + {" _ ", "| |", "|_|"}, // 0 + {" ", " |", " |"}, // 1 + {" _ ", " _|", "|_ "}, // 2 + {" _ ", " _|", " _|"}, // 3 + {" ", "|_|", " |"}, // 4 + {" _ ", "|_ ", " _|"}, // 5 + {" _ ", "|_ ", "|_|"}, // 6 + {" _ ", " |", " |"}, // 7 + {" _ ", "|_|", "|_|"}, // 8 + {" _ ", "|_|", " _|"}, // 9 + {" ", " . ", " . "} // colon ":" +}; + +void printBigTime(int h, int m, int s) { + // Format time as HH:MM:SS string + char timeStr[9]; + memset(timeStr, 0, sizeof(timeStr)); + char bigDigitsPrint[40]; + memset(bigDigitsPrint, 0, sizeof(bigDigitsPrint)); + snprintf(timeStr, sizeof(timeStr), "%02d:%02d:%02d", h, m, s); // This (and further such manipulations) is necessary because Serial.print() does not support formatted output like printf() + Serial.println(timeStr); + + + // Print each of the 3 lines row by row + for (int row = 0; row < 3; row++) { + for (int i = 0; timeStr[i] != '\0'; i++) { + char c = timeStr[i]; + if (c >= '0' && c <= '9') { + sprintf(bigDigitsPrint, "%s ", bigDigits[c - '0'][row]); + Serial.print(bigDigitsPrint); + } else if (c == ':') { + sprintf(bigDigitsPrint, "%s ", bigDigits[10][row]); + Serial.print(bigDigitsPrint); + } else { + Serial.print(" "); // Space or unknown + } + } + Serial.println(); + } + Serial.println(); +} + +void setup() { + Serial.begin(115200); + rtc.begin(); + bool status = rtc.setTime(2025, 9, 25, 7, 46, 0); // Initial time +} + +void loop() { + int y, m, d, h, min, s; + char printBuffer[60]; + int status = rtc.getTime(y, m, d, h, min, s); + + // Clear screen (optional line, works on many terminals, tested on Tera Term. Does not take effect in Arduino IDE console unfortunately) + Serial.println("\033[2J\033[H"); + + // Print date and time in plain format + sprintf(printBuffer, "Date: %04d-%02d-%02d\n", y, m, d); + Serial.println(printBuffer); + Serial.println("Time:"); + + // Print time in big digits + printBigTime(h, min, s); + + delay(1000); +} diff --git a/libraries/RTC/examples/SimpleRTC/SimpleRTC.ino b/libraries/RTC/examples/SimpleRTC/SimpleRTC.ino new file mode 100644 index 000000000..ae35d8ae2 --- /dev/null +++ b/libraries/RTC/examples/SimpleRTC/SimpleRTC.ino @@ -0,0 +1,23 @@ +#include "RTC.h" + +ArduinoRTC rtc; + +int year, month, day, hour, minute, second; +int previousSecond = 0; +char printBuffer[30]; // Allocate large enough buffer to hold the 28 characters of the output format "Time is: 2025-09-25 11:49:26" + +void setup() { + Serial.begin(115200); + if (!rtc.begin()) { + Serial.println("RTC not ready\n"); + return; + } + rtc.setTime(2025, 10, 21, 12, 0, 0); +} + +void loop() { + rtc.getTime(year, month, day, hour, minute, second); // Read back time from hardware + sprintf(printBuffer, "Time is: %04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second); + Serial.println(printBuffer); + delay(1000); +} \ No newline at end of file diff --git a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf index eaf599eaa..a209a9566 100644 --- a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf +++ b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.conf @@ -23,6 +23,12 @@ CONFIG_DAC=y CONFIG_PWM=y CONFIG_I2C_TARGET=y +CONFIG_CLOCK_CONTROL=y +CONFIG_RTC=y +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_RTC_CALIBRATION=y + CONFIG_ICACHE=y CONFIG_DCACHE=y CONFIG_CACHE_MANAGEMENT=y diff --git a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.overlay b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.overlay index 1bce0bdf3..b0b8c9774 100644 --- a/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.overlay +++ b/variants/arduino_giga_r1_stm32h747xx_m7/arduino_giga_r1_stm32h747xx_m7.overlay @@ -27,6 +27,17 @@ status = "okay"; }; +&rtc { + status = "okay"; + label = "RTC_0"; + + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, /* RTCAPB */ + <&rcc STM32_SRC_LSE RTC_SEL(1)>; /* Use LSI instead of LSE */ + + alarms-count = <2>; + alrm-exti-line = <17>; +}; + &i2c4 { status = "okay"; gc2145: gc2145@3c { diff --git a/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.conf b/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.conf index 1b7191cad..26c24ea8e 100644 --- a/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.conf +++ b/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.conf @@ -25,6 +25,7 @@ CONFIG_CDC_ACM_DTE_RATE_CALLBACK_SUPPORT=y CONFIG_ADC=y CONFIG_PWM=y +CONFIG_COUNTER=y CONFIG_LLEXT_STORAGE_WRITABLE=n CONFIG_SHELL_STACK_SIZE=2048 diff --git a/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.overlay b/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.overlay index ee99b2697..f0c3118df 100644 --- a/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.overlay +++ b/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_nrf52840_sense.overlay @@ -273,3 +273,8 @@ clock-frequency = ; }; +&rtc2 { + status = "okay"; + clock-frequency = <32768>; + prescaler = <1>; // Optional: sets the RTC tick to ~30.5 µs +}; diff --git a/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_sense.overlay b/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_sense.overlay index 6c8f9754d..898644154 100644 --- a/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_sense.overlay +++ b/variants/arduino_nano_33_ble_nrf52840_sense/arduino_nano_33_ble_sense.overlay @@ -196,3 +196,8 @@ pinctrl-1 = <&pwm2_sleep>; pinctrl-names = "default", "sleep"; }; + +&rtc2 { + status = "okay"; + prescaler = <1>; // Optional: sets the RTC tick to ~30.5 µs +}; diff --git a/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.conf b/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.conf index d8c4fc42d..dac71fad6 100644 --- a/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.conf +++ b/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.conf @@ -18,12 +18,13 @@ CONFIG_BT_BUF_CMD_TX_COUNT=10 #CONFIG_ADC=y #CONFIG_PWM=y +CONFIG_COUNTER=y CONFIG_LLEXT_STORAGE_WRITABLE=n CONFIG_SHELL_STACK_SIZE=1024 CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_LLEXT_HEAP_SIZE=15 -CONFIG_MAIN_STACK_SIZE=1024 +CONFIG_MAIN_STACK_SIZE=2048 CONFIG_BT_RX_STACK_SIZE=1024 CONFIG_BT_HCI_TX_STACK_SIZE=1024 diff --git a/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.overlay b/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.overlay index 47d9bfb22..5f0df0db9 100644 --- a/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.overlay +++ b/variants/arduino_nicla_sense_me_nrf52832/arduino_nicla_sense_me_nrf52832.overlay @@ -7,6 +7,12 @@ }; }; +&rtc2 { + status = "okay"; + clock-frequency = <32768>; + prescaler = <1>; // Optional: sets the RTC tick to ~30.5 µs +}; + / { zephyr,user { digital-pin-gpios = <&gpio0 10 0>, // 0: GPIO3 @@ -34,4 +40,4 @@ i2cs = <&i2c1>; spis = <&spi1>; }; -}; \ No newline at end of file +}; diff --git a/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.conf b/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.conf index ec12c78dc..aa99e94a6 100644 --- a/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.conf +++ b/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.conf @@ -22,6 +22,12 @@ CONFIG_ADC=y CONFIG_DAC=n CONFIG_PWM=n +CONFIG_CLOCK_CONTROL=y +CONFIG_RTC=y +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_RTC_CALIBRATION=y + CONFIG_ICACHE=y CONFIG_DCACHE=y CONFIG_CACHE_MANAGEMENT=y diff --git a/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.overlay b/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.overlay index eebf45e32..c2da8fa0d 100644 --- a/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.overlay +++ b/variants/arduino_opta_stm32h747xx_m7/arduino_opta_stm32h747xx_m7.overlay @@ -21,6 +21,17 @@ status = "okay"; }; +&rtc { + status = "okay"; + label = "RTC_0"; + + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSE RTC_SEL(1)>; + + alarms-count = <2>; + alrm-exti-line = <17>; +}; + &i2c1 { status = "okay"; pinctrl-0 = <&i2c1_scl_pb6 &i2c1_sda_pb7>; diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf index 6c0b575eb..8f9d2c9f7 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.conf @@ -35,6 +35,12 @@ CONFIG_SPI_ASYNC=y CONFIG_SPI_STM32_INTERRUPT=y CONFIG_I2C_TARGET=y +CONFIG_CLOCK_CONTROL=y +CONFIG_RTC=y +CONFIG_RTC_ALARM=y +CONFIG_RTC_UPDATE=y +CONFIG_RTC_CALIBRATION=y + CONFIG_NET_CORE_LOG_LEVEL_DBG=y CONFIG_NETWORKING=y diff --git a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay index 36643e3d9..db928ac31 100644 --- a/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay +++ b/variants/arduino_portenta_h7_stm32h747xx_m7/arduino_portenta_h7_stm32h747xx_m7.overlay @@ -14,6 +14,17 @@ status = "okay"; }; +&rtc { + status = "okay"; + label = "RTC_0"; + + clocks = <&rcc STM32_CLOCK_BUS_APB1 0x10000000>, + <&rcc STM32_SRC_LSI RTC_SEL(2)>; + + alarms-count = <2>; + alrm-exti-line = <17>; +}; + &i2c3 { status = "okay";