Run your noisy wall-clock only 12H/24

Posted by

It is sometimes disturbing to have such a clock running during the night because of its noise…

Standard low-cost wall clock

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.

2 Cells instead of 1 to power the STM32 board

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).

Quickly drawn Fritzing schematic… Motor is the clock mechanism

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)
{
}

Leave a Reply

Your email address will not be published. Required fields are marked *