Here's some corrected code. This prints correctly.
/*
* RTC_AutomaticExample
*
* This example sets the RTC (Real Time Clock) on the Portenta C33 automatically by
* retrieving the date and time from the computer you upload the sketch from, at the
* point when you start the upload.
*
* Next, it gets the current time from the RTC and prints it to the Serial Monitor.
* It then sets an RTC alarm to fire every time the seconds value of the time is zero.
* The alarm, which now goes off once a minute, triggers a callback that prints the
* current time to the Serial Monitor.
*
* Find the full UNO R4 WiFi RTC documentation here:
* https://docs.arduino.cc/tutorials/uno-r4-wifi/rtc
*/
// Include the RTC library
#include "RTC.h"
#include "IRQManager.h"
DayOfWeek convertDayOfWeek(String s)
{
if (s == String("Mon"))
{
return DayOfWeek::MONDAY;
}
if (s == String("Tue"))
{
return DayOfWeek::TUESDAY;
}
if (s == String("Wed"))
{
return DayOfWeek::WEDNESDAY;
}
if (s == String("Thu"))
{
return DayOfWeek::THURSDAY;
}
if (s == String("Fri"))
{
return DayOfWeek::FRIDAY;
}
if (s == String("Sat"))
{
return DayOfWeek::SATURDAY;
}
if (s == String("Sun"))
{
return DayOfWeek::SUNDAY;
}
}
Month convertMonth(String s)
{
if (s == String("Jan"))
{
return Month::JANUARY;
}
if (s == String("Feb"))
{
return Month::FEBRUARY;
}
if (s == String("Mar"))
{
return Month::MARCH;
}
if (s == String("Apr"))
{
return Month::APRIL;
}
if (s == String("May"))
{
return Month::MAY;
}
if (s == String("Jun"))
{
return Month::JUNE;
}
if (s == String("Jul"))
{
return Month::JULY;
}
if (s == String("Aug"))
{
return Month::AUGUST;
}
if (s == String("Sep"))
{
return Month::SEPTEMBER;
}
if (s == String("Oct"))
{
return Month::OCTOBER;
}
if (s == String("Nov"))
{
return Month::NOVEMBER;
}
if (s == String("Dec"))
{
return Month::DECEMBER;
}
}
RTCTime currentRTCTime()
{
// Get a compilation timestamp of the format: Wed May 10 08:54:31 2023
// __TIMESTAMP__ is a GNU C extension macro
// We can't use the standard macros __DATE__ and __TIME__ because they don't provide the day of the week
String timeStamp = __TIMESTAMP__;
// Extract the day of the week
int pos1 = timeStamp.indexOf(" ");
DayOfWeek dayOfWeek = convertDayOfWeek(timeStamp.substring(0, pos1));
// Extract the month
++pos1;
int pos2 = timeStamp.indexOf(" ", pos1);
Month month = convertMonth(timeStamp.substring(pos1, pos2));
// Extract the day
pos1 = ++pos2;
pos2 = timeStamp.indexOf(" ", pos1);
int day = timeStamp.substring(pos1, pos2).toInt();
// Extract the hour
pos1 = ++pos2;
pos2 = timeStamp.indexOf(":", pos1);
int hour = timeStamp.substring(pos1, pos2).toInt();
// Extract the minute
pos1 = ++pos2;
pos2 = timeStamp.indexOf(":", pos1);
int minute = timeStamp.substring(pos1, pos2).toInt();
// Extract the second
pos1 = ++pos2;
pos2 = timeStamp.indexOf(" ", pos1);
int second = timeStamp.substring(pos1, pos2).toInt();
// Extract the year
pos1 = ++pos2;
pos2 = timeStamp.indexOf(" ", pos1);
int year = timeStamp.substring(pos1, pos2).toInt();
return RTCTime(day, month, year, hour, minute, second, dayOfWeek, SaveLight::SAVING_TIME_INACTIVE);
}
RTCTime currentTime;
volatile boolean rtcAlarmFired;
uint8_t eventLinkIndex;
void alarmCallback() {
RTC.getTime(currentTime);
rtcAlarmFired = true;
}
void printAlarmInfo(){
Serial.print("An RTC alarm was triggered at: ");
Serial.print(currentTime.getYear());
Serial.print("-");
Serial.print(Month2int(currentTime.getMonth()));
Serial.print("-");
Serial.print(currentTime.getDayOfMonth());
Serial.print(" ");
Serial.print(currentTime.getHour());
Serial.print(":");
Serial.print(currentTime.getMinutes());
Serial.print(":");
Serial.println(currentTime.getSeconds());
}
void setup()
{
Serial.begin(115200);
while (!Serial) ;
// Initialize the RTC
RTC.begin();
// Get the current date and time when the sketch is uploaded and set the RTC
RTCTime timeToSet = currentRTCTime();
RTC.setTime(timeToSet);
// Retrieve the date and time from the RTC and print them
Serial.println("The RTC was just set to: ");
RTCTime currentTime;
RTC.getTime(currentTime);
Serial.print(currentTime.getYear());
Serial.print("-");
Serial.print(Month2int(currentTime.getMonth()));
Serial.print("-");
Serial.print(currentTime.getDayOfMonth());
Serial.print(" ");
Serial.print(currentTime.getHour());
Serial.print(":");
Serial.print(currentTime.getMinutes());
Serial.print(":");
Serial.println(currentTime.getSeconds());
// Create an alarm time with the seconds value set to zero
RTCTime alarmTime;
alarmTime.setSecond(0);
// Tell the RTC to only match on the seconds value
AlarmMatch alarmMatch;
alarmMatch.addMatchSecond();
// Set the alarm callback function
RTC.setAlarmCallback(alarmCallback, alarmTime, alarmMatch);
setupCAC();
}
const unsigned long oneMinute = 60000ul;
// volatile bool cacFired = false;
// volatile int errRep;
void loop()
{
static unsigned long pm = millis();
unsigned long cm = millis();
if(cm-pm >= oneMinute){
pm += oneMinute;
Serial.print("Millis triggered at: ");
Serial.println(cm);
}
if(rtcAlarmFired){
printAlarmInfo();
rtcAlarmFired = false;
}
// if(cacFired){
// Serial.println(errRep);
// cacFired = false;
// }
}
void cacFERRIHandler() {
// record CAC counter register
uint16_t result = R_CAC->CACNTBR;
// clear interrupt flags
R_CAC->CAICR |= (R_CAC_CAICR_FERRFCL_Msk);
R_ICU->IELSR[eventLinkIndex] &= ~(R_ICU_IELSR_IR_Msk);
// Static variable to keep track of old value to determine sign changes
static int16_t accumulatedError = 0;
// Calculate error and and add to running total
int16_t newAcc = accumulatedError + (result - 1465);
// If the accumulated error changes sign then we should adjust the trim
if((newAcc < 0 ) && (accumulatedError >= 0)){
adjustLocoTrim(-1);
}
else if ((newAcc > 0) && (accumulatedError <= 0)){
adjustLocoTrim(1);
}
accumulatedError = newAcc;
// errRep = accumulatedError;
// cacFired = true;
}
void adjustLocoTrim(int amount) {
// Unlock PRC0
// Write A5 to high 8 bits and PRCO_Msk in low bit
uint16_t curPRCR = R_SYSTEM->PRCR;
R_SYSTEM->PRCR = curPRCR | (0xA500) | (0x0001);
int8_t curLOCOtrim = R_SYSTEM->LOCOUTCR;
R_SYSTEM->LOCOUTCR = curLOCOtrim + amount;
// Lock protection register with old value.
R_SYSTEM->PRCR = curPRCR | (0xA500);
}
void setupCAC() {
R_MSTP->MSTPCRC &= ~((uint32_t)R_MSTP_MSTPCRC_MSTPC0_Msk);
// Calculating 48MHz HOCO divided by 32.768 LOCO using the same divider gives
// 48,000,000 / 32,768 == 1464.84375
// Using the 1/128 divider for LOCO makes it 5859.375
// set lower limit
R_CAC->CALLVR = 1462;
//set upper limit
R_CAC->CAULVR = 1467;
// Set source clock
//(EDGES=00 rising only, TCSS=11 1/32 divider, FMCS=010 HOCO, CACREFE=0 Disable CACREF pin input)
R_CAC->CACR1 = 0x34;
// set reference clock
// (DFS=00 no filter, RCDS=01 1/32 divider, RSCS=100LOCO, RPS=1 internal clock source)
R_CAC->CACR2 = 0x09;
// set interrupt (this function added to core by me)
IRQManager::getInstance().addMaskableInterrupt(0x47, cacFERRIHandler);
// Find which event link it gave us.
for(uint8_t i = 0; i < 32; i++){
volatile uint32_t val = R_ICU->IELSR[i];
if((val & 0xFF) == 0x47){
eventLinkIndex = i;
break;
}
}
// enable interrupt and clear any pending flag
R_CAC->CAICR = (R_CAC_CAICR_FERRIE_Msk | R_CAC_CAICR_FERRFCL_Msk);
// Set CFME in CACR0 to turn on the unit
R_CAC->CACR0 = (R_CAC_CACR0_CFME_Msk);
}
There's some stuff where I commented out that I had it printing the accumulated error from the isr. I was able to confirm that it does jump up into the 40s and then come down by around 10 per interrupt until it goes a little negative and then jumps back into the 40s. That's as expected. It's mostly running fast, but every now and then we let it run slow for a little bit to catch up.
However the results for the RTC test are what really matter.
For the case where I have the CAC turned off setupCAC();
is commented out.
21:46:08.596 -> The RTC was just set to:
21:46:08.596 -> 2023-10-18 21:45:50
21:46:18.535 -> An RTC alarm was triggered at: 2023-10-18 21:46:0
21:47:08.591 -> Millis triggered at: 61558
21:47:18.116 -> An RTC alarm was triggered at: 2023-10-18 21:47:0
21:48:08.592 -> Millis triggered at: 121558
21:48:17.665 -> An RTC alarm was triggered at: 2023-10-18 21:48:0
21:49:08.589 -> Millis triggered at: 181558
21:49:17.245 -> An RTC alarm was triggered at: 2023-10-18 21:49:0
21:50:08.583 -> Millis triggered at: 241558
21:50:16.794 -> An RTC alarm was triggered at: 2023-10-18 21:50:0
21:51:08.580 -> Millis triggered at: 301558
21:51:16.374 -> An RTC alarm was triggered at: 2023-10-18 21:51:0
21:52:08.612 -> Millis triggered at: 361558
21:52:15.955 -> An RTC alarm was triggered at: 2023-10-18 21:52:0
21:53:08.612 -> Millis triggered at: 421558
21:53:15.505 -> An RTC alarm was triggered at: 2023-10-18 21:53:0
21:54:08.608 -> Millis triggered at: 481558
21:54:15.086 -> An RTC alarm was triggered at: 2023-10-18 21:54:0
21:55:08.612 -> Millis triggered at: 541558
21:55:14.642 -> An RTC alarm was triggered at: 2023-10-18 21:55:0
21:56:08.615 -> Millis triggered at: 601558
21:56:14.228 -> An RTC alarm was triggered at: 2023-10-18 21:56:0
21:57:08.622 -> Millis triggered at: 661558
21:57:13.784 -> An RTC alarm was triggered at: 2023-10-18 21:57:0
21:58:08.603 -> Millis triggered at: 721558
21:58:13.350 -> An RTC alarm was triggered at: 2023-10-18 21:58:0
millis is doing pretty good, but the RTC is fast by about 400ms per minute.
When I uncomment setupCAC()
and let the CAC run the results:
21:59:42.952 -> The RTC was just set to:
21:59:42.952 -> 2023-10-18 21:59:24
22:00:18.935 -> An RTC alarm was triggered at: 2023-10-18 22:0:0
22:00:42.951 -> Millis triggered at: 61625
22:01:18.934 -> An RTC alarm was triggered at: 2023-10-18 22:1:0
22:01:42.922 -> Millis triggered at: 121625
22:02:18.969 -> An RTC alarm was triggered at: 2023-10-18 22:2:0
22:02:42.924 -> Millis triggered at: 181625
22:03:18.963 -> An RTC alarm was triggered at: 2023-10-18 22:3:0
22:03:42.920 -> Millis triggered at: 241625
22:04:18.965 -> An RTC alarm was triggered at: 2023-10-18 22:4:0
22:04:42.921 -> Millis triggered at: 301625
22:05:18.969 -> An RTC alarm was triggered at: 2023-10-18 22:5:0
22:05:42.928 -> Millis triggered at: 361625
22:06:18.976 -> An RTC alarm was triggered at: 2023-10-18 22:6:0
22:06:42.930 -> Millis triggered at: 421625
22:07:18.979 -> An RTC alarm was triggered at: 2023-10-18 22:7:0
22:07:42.954 -> Millis triggered at: 481625
22:08:19.085 -> An RTC alarm was triggered at: 2023-10-18 22:8:0
22:08:43.020 -> Millis triggered at: 541625
22:09:19.115 -> An RTC alarm was triggered at: 2023-10-18 22:9:0
Looks like the RTC got a lot more accurate once that CAC correction was turned on. At least compared to millis.