STM32 RTC functions

5 minute read

Published:

Introduction

This post intends to explore the functions of the Real Time Clock (RTC) of STM32 microcontrollers. This time we also use CubeMX, the powerful code generator for STM32 MCUs.

The purpose for this post is to get familiar with the RTC for uCs and intend to use this for my next step of the research project.

My next work is to design a sensor node that could wakeup every minute (or other time period), and do the following functions:

  1. generate PWM waveforms to drive the LC shutter for a specific time (maybe 10-15 seconds).
  2. read data from the PIR sensor and temperature sensor
  3. send the data to the server (via Bluetooth, Wifi, ZigBee, etc)
  4. enter sleep mode.

Also, during the sleep mode, the MCU should be able to woken up by the motion of the person. This is done by attach an external pin from PIR sensor to the MCU.

Concerns

Right now the PIR sensors which is integrated with LC shutter is the AMN24112 analog PIR sensor, which require ADC to poll the signals. ADC consumes high power. If we really stick to this sensor model, it is difficult to wake up the MCU since the MCU is sensitive to the edge of the attached pin, but the analog signals from the PIR sensor is not analog.

Solutions:

  1. USe a second digital PIR sensor and attach the output pin to the wakeup pin.
  2. Add an comparator that could generate edge once the signal from the analog sensor reached certain level.

Alarm

Goal – Use an LCD-SSD1306, to show the calendar in real time, then add an “alarm” sign when the second reach 0 every minute. The “alarm” sign would disappear after 5 seconds.

Setup

After create the new project, setup the RTC and I2C1 as follows. Here we use two alarms, ALARMA and ALARMB. Note that the Alarm masks for date, hour, minute are enabled, to ignore the number in these fields. Remember to check the NVIC setting.

Pin setup

RTC setup

Code

Requirements:

  1. SSD1306 library. controllerstech.com/oled-display-using-i2c-stm32/
  2. Follow the instructions in this video to setup the correct path to the driver files.

After generaing code, code as followed:

Before main function, declare two RTC Type Def for date and time:

char CalendarString[50];
char TimeString[50];

RTC_DateTypeDef sDate;
RTC_TimeTypeDef sTime;

In main function:

Set the start time and date

  // set time and date
  sTime.Hours = 23;
  sTime.Minutes = 59;
  sTime.Seconds = 45;
  sDate.Year = 19;
  sDate.Month = RTC_MONTH_DECEMBER;
  sDate.Date = 31;

  HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
  HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

In while loop:

while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    // update the sTime and sDate. 
	  HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	  HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);

    // combine date and time to two strings
	  sprintf(CalendarString, "20%02d/%02d/%02d", sDate.Year, sDate.Month, sDate.Date);
	  sprintf(TimeString, "%02d:%02d:%02d", sTime.Hours, sTime.Minutes, sTime.Seconds);

	  // LCD display and update
	  SSD1306_GotoXY(0, 0);
	  SSD1306_Puts(CalendarString, &Font_11x18, 1);
	  SSD1306_GotoXY(0, 20);
	  SSD1306_Puts(TimeString, &Font_11x18, 1);
	  SSD1306_UpdateScreen();

	  HAL_Delay(1000);

  }

At the end, add two callback functions

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hrtc);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_RTC_AlarmAEventCallback could be implemented in the user file
   */
  //HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3);

  // update alarm when the second is 0
  SSD1306_GotoXY(0, 40);
  SSD1306_Puts("Alarm", &Font_11x18, 1);
  SSD1306_UpdateScreen();
}

void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(hrtc);

  /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_RTCEx_AlarmBEventCallback could be implemented in the user file
   */
  // update alarm when the second is 5
  SSD1306_GotoXY(0, 40);
  SSD1306_Puts("        ", &Font_11x18, 1);
  SSD1306_UpdateScreen();
}

Demo

Demo video

From the demo video, we could see that when the board start at 2019/12/31 23:59:45. When the time reached 2020/1/1 00:00:00, the “alarm” sign apears. After 5 seconds, it disappears. Not shown in the video, the “alarm” sign would appear every minute when the second is at 0, and disappear after 5 seconds.

Wakeup from standby mode

Low power mode of STM32

From the datasheet, the low power power is summerized in the table. Low power modeLow power mode

Besides the total shutdown, standby mode consumes the lowest power. Low powerLow power consumption

The feature of the standby mode is that when it wakes up, the MCU would run from the start (act like a reset). The SRAM would be cleared except the registers in backup domain.

Code

The corresponding sample code is as follows.

In main function (before while loop):

/* USER CODE BEGIN 2 */

  /* check the standby mode status */
  if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET){
	  // clear SB flag
	  __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);
  }

  // toggle LED
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
  HAL_Delay(1000);
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);

  // clear wakeup flag
  __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

  /*	Enable wakeup
   * 	The second parameter is the WakeupCounter
   * 	EXAMPLE 1:
   * 	the RTC is configured to use LSE (32.768kHz) as the clock source
   * 	The proposed wakeup time is 4 seconds.
   * 	Then the interval time of the counter is 1/(LSE/DIV).
   * 	Here, DIV is 16, t_interval = 1/(32768/16) = 1/2048 second
   * 	WakeupCounter = 4 seconds/t_interval = 8192 = 0x2000
   *
   * 	EXAMPLE 2: Clock source is RTC_WAKEUPCLOCK_CK_SPRE_16BITS, which is 1Hz
   * 	WakeupCounter = time_to_standby
   */
  HAL_RTCEx_SetWakeUpTimer(&hrtc, 0x2000, RTC_WAKEUPCLOCK_RTCCLK_DIV16);

  // enter standby mode
  HAL_PWR_EnterSTANDBYMode();


  /* USER CODE END 2 */