It is sometimes disturbing to have such a clock running during the night because of its noise…
My solution : run it only 12 hours / day. For example from 8:30AM to 8:30PM, then stop powering it, and return to normal at 8:30AM the next morning.
My quick prototype uses a STM32 Blue Pill board – it runs almost all of the time in sleep (STOP) mode, and wakes up on a RTC event, every 12 hours. The code only toggles the PB0 pin (open-drain), PC13 (for debugging – once done, remove the resistor that drives the LED). Also, remove the resistor that powers the ‘power’ status LED.
The clock should only use a few hundred microamps when turned off (all status LED removed), and the regular clock consumption when turned on (the few STM32 uA are negligible compared to the clock mechanism module consumption).
And the code (Platform.io, Low-Level ST32Cube API) is :
(Note that the clock will turn ON when first powered ON and/or reset)
/* Includes */
#include <stddef.h>
#define USE_FULL_LL_DRIVER
#include "stm32f1xx_ll_system.h"
#include "stm32f1xx_ll_utils.h"
#include "stm32f1xx_ll_bus.h"
#include "stm32f1xx_ll_rcc.h"
#include "stm32f1xx_ll_pwr.h"
#include "stm32f1xx_ll_rtc.h"
#include "stm32f1xx_ll_gpio.h"
#include "stm32f1xx_ll_exti.h"
static int i=0;
void mySystemInit(void)
{
LL_FLASH_SetLatency(LL_FLASH_LATENCY_0); // Default Flash timings
LL_FLASH_EnablePrefetch();
LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); // AHB,APB2,APB1
LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_4);
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_4);
// Init RTC (LSE, 32khz)
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR|LL_APB1_GRP1_PERIPH_BKP);
LL_PWR_EnableBkUpAccess();
LL_RCC_ForceBackupDomainReset();
LL_RCC_ReleaseBackupDomainReset();
LL_RCC_LSE_Enable(); // Enable LSE oscillator, Switch RTC clock to LSE
while ((RCC->BDCR & RCC_BDCR_LSERDY) != RCC_BDCR_LSERDY) {}
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
}
int main(void)
{
mySystemInit();
LL_RCC_EnableRTC();
while (!LL_RTC_IsActiveFlag_RTOF(RTC)) {}
LL_RTC_DisableWriteProtection(RTC);
LL_RTC_SetAsynchPrescaler(RTC,0x7FFF); // Writing RTC Prescaler requires DisableWriteProtection
LL_RTC_EnableWriteProtection(RTC); // Write (prescaler), when CNF=0
while (!LL_RTC_IsActiveFlag_RTOF(RTC)) {}
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
LL_GPIO_SetPinMode(GPIOC, LL_GPIO_PIN_13, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinSpeed(GPIOC, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_LOW);
LL_GPIO_SetPinOutputType(GPIOC, LL_GPIO_PIN_13, LL_GPIO_OUTPUT_OPENDRAIN);
LL_GPIO_SetOutputPin(GPIOC,LL_GPIO_PIN_13);
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_0, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_0, LL_GPIO_SPEED_FREQ_LOW);
LL_GPIO_SetPinOutputType(GPIOB, LL_GPIO_PIN_0, LL_GPIO_OUTPUT_OPENDRAIN);
LL_GPIO_SetOutputPin(GPIOB,LL_GPIO_PIN_0);
/* Enable the RTC Alarm Event only (no IT) */
LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_17);
LL_EXTI_EnableEvent_0_31(LL_EXTI_LINE_17);
LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_17);
restart:
LL_GPIO_TogglePin(GPIOC, LL_GPIO_PIN_13);
LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_0);
LL_RTC_ClearFlag_RS(RTC);
while (!LL_RTC_IsActiveFlag_RS(RTC)) {}
// i=LL_RTC_TIME_Get(RTC);
LL_RTC_ClearFlag_ALR(RTC);
while (!LL_RTC_IsActiveFlag_RTOF(RTC)) {}
LL_RTC_DisableWriteProtection(RTC);
i+=(12*3600);
LL_RTC_ALARM_Set(RTC,i);
LL_RTC_EnableWriteProtection(RTC);
while (!LL_RTC_IsActiveFlag_RTOF(RTC)) {}
/* Clear PDDS bit in PWR register to specify entering in STOP mode when CPU enter in Deepsleep */
CLEAR_BIT(PWR->CR, PWR_CR_PDDS);
/* Set SLEEPDEEP bit of Cortex System Control Register */
SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
/* Sleep Mode */
__WFE();
__NOP();
goto restart;
}
void SysTick_Handler(void)
{
}
void NMI_Handler(void)
{
}
void HardFault_Handler(void)
{
while (1) {}
}
void MemManage_Handler(void)
{
while (1) {}
}
void BusFault_Handler(void)
{
while (1) {}
}
void UsageFault_Handler(void)
{
while (1) {}
}
void SVC_Handler(void)
{
}
void DebugMon_Handler(void)
{
}
void PendSV_Handler(void)
{
}