-
I've been scratching my head for a couple of days as to why I can't get the STM32LowPower/RTC library to work reliably on our hardware. Taking this slightly modified version of the examples #include <Arduino.h>
#include "STM32LowPower.h"
#include <ArduinoLog.h>
#include "CustomPins.h"
#include "STM32RTC.h"
Logging logger;
// HardwareSerial stlinkSerial(PIN_VCP_RX, PIN_VCP_TX);
HardwareSerial stlinkSerial(rx_pin2debug, tx_pin2debug);
STM32LowPower lowPower;
static const char *mydate = __DATE__;
static const char *mytime = __TIME__;
static byte seconds = 0;
static byte minutes = 0;
static byte hours = 0;
static byte weekDay = 1;
static byte day = 0;
static byte month = 0;
static byte year = 0;
static STM32RTC::Hour_Format hourFormat = STM32RTC::HOUR_24;
static STM32RTC::AM_PM period = STM32RTC::AM;
STM32RTC &rtc = STM32RTC::getInstance();
volatile int alarmMatch_counter = 0;
static uint8_t conv2d(const char *p)
{
uint8_t v = 0;
if ('0' <= *p && *p <= '9')
v = *p - '0';
return 10 * v + *++p - '0';
}
void print2digits(int number)
{
if (number < 10)
{
stlinkSerial.print("0"); // print a 0 before if the number is < than 10
}
stlinkSerial.print(number);
}
void alarmMatch(void *data)
{
// This function will be called once on device wakeup
// You can do some little operations here (like changing variables which will be used in the loop)
// Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
uint32_t epoc;
uint32_t epoc_ms;
uint32_t sec = 0;
uint32_t _millis = 1000;
if (data != NULL)
{
_millis = *(uint32_t *)data;
}
sec = _millis / 1000;
#ifdef STM32F1xx
// Minimum is 1 second
if (sec == 0)
{
sec = 1;
}
epoc = rtc.getEpoch(&epoc_ms);
#else
_millis = _millis % 1000;
epoc = rtc.getEpoch(&epoc_ms);
// Update epoch_ms - might need to add a second to epoch
epoc_ms += _millis;
if (epoc_ms >= 1000)
{
sec++;
epoc_ms -= 1000;
}
#endif
alarmMatch_counter++;
rtc.setAlarmEpoch(epoc + sec, STM32RTC::MATCH_SS, epoc_ms);
}
// sample input: date = "Dec 26 2009", time = "12:34:56"
void initDateTime(const char *date, const char *time)
{
year = conv2d(date + 9);
// Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
switch (date[0])
{
case 'J':
month = (date[1] == 'a') ? 1 : ((date[2] == 'n') ? 6 : 7);
break;
case 'F':
month = 2;
break;
case 'A':
month = date[2] == 'r' ? 4 : 8;
break;
case 'M':
month = date[2] == 'r' ? 3 : 5;
break;
case 'S':
month = 9;
break;
case 'O':
month = 10;
break;
case 'N':
month = 11;
break;
case 'D':
month = 12;
break;
}
day = conv2d(date + 4);
hours = conv2d(time);
if (hourFormat == rtc.HOUR_12)
{
period = hours >= 12 ? rtc.PM : rtc.AM;
hours = hours >= 13 ? hours - 12 : (hours < 1 ? hours + 12 : hours);
}
minutes = conv2d(time + 3);
seconds = conv2d(time + 6);
}
// t: number of print
// d: delay between each print
// a: display alarm
void printDateTime(uint32_t t, uint32_t d, bool a)
{
for (uint32_t i = 0; i < t; i++)
{
// Print date...
print2digits(rtc.getMonth());
stlinkSerial.print("/");
print2digits(rtc.getDay());
stlinkSerial.print("/");
print2digits(rtc.getYear());
stlinkSerial.print("\t");
// ...and time
print2digits(rtc.getHours(&period));
stlinkSerial.print(":");
print2digits(rtc.getMinutes());
stlinkSerial.print(":");
print2digits(rtc.getSeconds());
if (hourFormat == rtc.HOUR_12)
{
stlinkSerial.print(period == rtc.AM ? " AM" : " PM");
}
if (a)
{
// Print day...
stlinkSerial.print("\t");
print2digits(rtc.getAlarmDay());
stlinkSerial.print("\t");
// ...and time
print2digits(rtc.getAlarmHours(&period));
stlinkSerial.print(":");
print2digits(rtc.getAlarmMinutes());
stlinkSerial.print(":");
print2digits(rtc.getAlarmSeconds());
if (hourFormat == rtc.HOUR_12)
{
stlinkSerial.print(period == rtc.AM ? " AM" : " PM");
}
}
stlinkSerial.println();
delay(d);
}
}
void setup()
{
// put your setup code here, to run once:
stlinkSerial.begin(115200);
while (!stlinkSerial)
{
;
}
stlinkSerial.println("*******************************************");
stlinkSerial.println("Started");
stlinkSerial.flush();
LowPower.begin();
rtc.setClockSource(STM32RTC::LSE_CLOCK);
rtc.begin();
rtc.setAlarmEpoch(rtc.getEpoch() + 10);
}
void loop()
{
stlinkSerial.println("Waking up!");
printDateTime(1, 0, false);
if (!rtc.isTimeSet())
{
stlinkSerial.println("Time did not persist.");
initDateTime(mydate, mytime);
rtc.setTime(hours, minutes, seconds);
rtc.setDate(weekDay, day, month, year);
printDateTime(1, 0, false);
}
else
{
stlinkSerial.println("Time persisted!");
printDateTime(1, 0, false);
}
stlinkSerial.print("Alarm match: ");
stlinkSerial.println(alarmMatch_counter);
stlinkSerial.flush();
stlinkSerial.println("Sleeping!");
delay(100);
LowPower.deepSleep();
stlinkSerial.begin(115200);
while (!stlinkSerial)
{
}
} In my logs I see
Which is so weird, as obviously the code is waking up, but the callback isn't being fired at all. So then I tried going low level and just writing almost exactly the same HAL code as the libraries #include <Arduino.h>
#include "Version.h"
#include "CustomPins.h"
#include <Notecard.h>
RTC_HandleTypeDef hrtc;
HardwareSerial stlinkSerial(rx_pin2debug, tx_pin2debug);
HardwareSerial notecardSerial(rx_pin2note, tx_pin2note);
volatile bool alarmTriggered = false;
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
// stlinkSerial.println("[INFO] Alarm A Interrupt Triggered!");
alarmTriggered = true; // Set the flag to indicate alarm fired
}
extern "C" void RTC_IRQHandler(void)
{
HAL_RTC_AlarmIRQHandler(&hrtc);
}
void LowPower_stop()
{
__disable_irq();
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
configIPClock();
SystemClock_Config();
__enable_irq();
HAL_Delay(10);
}
void resetRTCToZero()
{
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
// Initialize RTC peripheral
hrtc.Instance = RTC;
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 127;
hrtc.Init.SynchPrediv = 255;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
RTC_TimeTypeDef sTime;
sTime.Hours = 0;
sTime.Minutes = 0;
sTime.Seconds = 0;
sTime.TimeFormat = RTC_HOURFORMAT_24; // Default to 24-hour mode
sTime.SubSeconds = 0;
sTime.SecondFraction = 0;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
RTC_DateTypeDef sDate;
sDate.WeekDay = RTC_WEEKDAY_SATURDAY; // Default to Saturday
sDate.Month = 1; // January
sDate.Date = 1; // 1st day
sDate.Year = 0; // Year 2000
// Unlock RTC write protection
__HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);
__HAL_RCC_LSE_CONFIG(RCC_LSE_ON);
while (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY) == RESET)
{
stlinkSerial.println("[DEBUG] Waiting for LSE to stabilize...");
delay(100);
}
stlinkSerial.println("[INFO] LSE Clock Stable");
__HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_LSE);
__HAL_RCC_RTC_ENABLE();
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
stlinkSerial.println("[ERROR] RTC Initialization Failed!");
while (1)
;
}
// Set the time and date to zero
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
{
stlinkSerial.println("[ERROR] Failed to reset RTC time!");
}
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
{
stlinkSerial.println("[ERROR] Failed to reset RTC date!");
}
// Lock RTC write protection
__HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);
stlinkSerial.println("[INFO] RTC Reset to 0 (1970-01-01 00:00:00).");
}
void setupRTCAlarm()
{
// Clear Alarm A flag and interrupt
__HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRAF);
HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(RTC_IRQn);
__HAL_RTC_ALARMA_DISABLE(&hrtc);
__HAL_RTC_ALARMA_ENABLE(&hrtc);
// Get current time
RTC_TimeTypeDef currentTime;
if (HAL_RTC_GetTime(&hrtc, ¤tTime, RTC_FORMAT_BIN) == HAL_OK)
{
stlinkSerial.print("[INFO] Current Time: ");
if (currentTime.Hours < 10)
stlinkSerial.print("0");
stlinkSerial.print(currentTime.Hours);
stlinkSerial.print(":");
if (currentTime.Minutes < 10)
stlinkSerial.print("0");
stlinkSerial.print(currentTime.Minutes);
stlinkSerial.print(":");
if (currentTime.Seconds < 10)
stlinkSerial.print("0");
stlinkSerial.println(currentTime.Seconds);
RTC_AlarmTypeDef sAlarm;
sAlarm.Alarm = RTC_ALARM_A;
sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
uint8_t newSeconds = currentTime.Seconds + 10;
uint8_t carryMinutes = newSeconds / 60;
newSeconds %= 60;
uint8_t newMinutes = currentTime.Minutes + carryMinutes;
uint8_t carryHours = newMinutes / 60;
newMinutes %= 60;
uint8_t newHours = 0;
newHours = (currentTime.Hours + carryHours) % 24;
// WTF THIS IS WEIRD NEEDED ELSE ALL BREAKS
auto newNewHours = 0;
if (newHours == currentTime.Hours)
{
delay(1);
newNewHours = newHours;
}
sAlarm.AlarmTime.Seconds = newSeconds;
sAlarm.AlarmTime.Minutes = newMinutes;
sAlarm.AlarmTime.Hours = newNewHours;
sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
sAlarm.AlarmDateWeekDay = 1;
// Set Alarm A with interrupt
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
{
stlinkSerial.println("[ERROR] RTC Alarm A Setup Failed!");
while (1)
;
}
stlinkSerial.print("[INFO] Configured an alarm at time: ");
if (sAlarm.AlarmTime.Hours < 10)
stlinkSerial.print("0");
stlinkSerial.print(sAlarm.AlarmTime.Hours);
stlinkSerial.print(":");
if (sAlarm.AlarmTime.Minutes < 10)
stlinkSerial.print("0");
stlinkSerial.print(sAlarm.AlarmTime.Minutes);
stlinkSerial.print(":");
if (sAlarm.AlarmTime.Seconds < 10)
stlinkSerial.print("0");
stlinkSerial.println(sAlarm.AlarmTime.Seconds);
}
else
{
stlinkSerial.println("[ERROR] Failed to get current time!");
while (1)
;
}
}
bool attnISRTriggered = false; // Default to true for first interrupt
bool ignoreFutureRequests = false; // Default to true for first interrupt
void attnISR()
{
stlinkSerial.println("Got interrupt");
attnISRTriggered = true;
}
Notecard notecard;
void setup()
{
stlinkSerial.begin(115200);
while (!stlinkSerial)
{
;
}
stlinkSerial.println("***********************************************************");
stlinkSerial.println("[INFO] Program Starting...");
notecardSerial.begin(9600);
notecard.begin(notecardSerial);
notecard.setDebugOutputStream(stlinkSerial);
pinMode(ATTN_INPUT_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(ATTN_INPUT_PIN), attnISR, RISING);
// Configure RTC and Alarm A
resetRTCToZero();
setupRTCAlarm();
attnISRTriggered = false;
}
bool forceTimeout = false;
void loop()
{
stlinkSerial.println("[INFO] Entering Main Loop...");
// Check if the alarm was triggered
if (alarmTriggered)
{
stlinkSerial.println("[DEBUG] Alarm Trigger Flag Detected via RTC!");
alarmTriggered = false; // Clear the flag
// In real life this would probably die
stlinkSerial.println("[DEBUG] Disarming all the attn requests notecard");
ignoreFutureRequests = true;
setupRTCAlarm();
}
stlinkSerial.println("[INFO] Going to sleep...");
delay(100);
LowPower_stop(); // Should wake up via notecard
stlinkSerial.begin(115200);
while (!stlinkSerial)
{
}
}
Which gives me
So my questions:
At this point any help would be incredibly appreciated, even if it's "if I was you I would do x,y,z next" because I'm not entirely sure what x,y,z could be now :) |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 6 replies
-
Hi @Alan01252 |
Beta Was this translation helpful? Give feedback.
-
Hi @fpistm Sorry for not being clear! We have a custom board with a STM32F030xC as the stm32 in use. https://github.com/stm32duino/STM32LowPower.git with tags/1.2.5 In terms of the "default" example, I tried that. It seems to work, sort of, in that it sleeps, but the callback never fires, which is why I then attempted to use the timed example above. Here's the hal from the generated config
I'll get my collegue to post here too :) You just helped him re-instate his account so thank you for that too! |
Beta Was this translation helpful? Give feedback.
-
Gosh this was stupid sorry for the time waste, if you notice in the first code the interrupt isn't actually set... |
Beta Was this translation helpful? Give feedback.
Gosh this was stupid sorry for the time waste, if you notice in the first code the interrupt isn't actually set...