STM32F103x. Часы RTC, настройка по серверам точного времени

Александр Левчук dslev@yandex.ru

Предисловие

Основные сведения об RTC STM32F103x.

Калибровка RTC

Литература

 


Часть 1 Основные сведения о USB

Часть 2. Описание проекта

STM32. Работаем в среде Visual Studio + VisualGDB + CubeMX

STM32. FATFS + DMA + CUBEMX

 

Предисловие

В Интернете можно найти много статей на тему установки и коррекции часов для STM32F103x. Часто выражается сожаление упрощенной реализацией часов RTC в микроконтроллере STM32F103x, не позволяющей сохранить дату при питании от батареи, а также отсутствие встроенного календаря. Такая проблема существует, если следовать рекомендациям разработчика устройства и использовать предоставляемые библиотеки стандартным способом. Однако существует возможность избежать указанных проблем и реализовать полноценный календарь с питанием от малогабаритной батареи. При этом еще упростить программу и существенно уменьшить размер занимаемой памяти. Далее рассмотрим, как можно программно реализовать часы с календарем и будильником, которые питаются от дополнительной батареи и сохраняются в памяти при сбросе или отключении основного питания. Также рассмотрим реализацию установки, и калибровки часов по серверу точного времени, данные от которого передаются из хоста через интерфейс USB (виртуальный СОМ порт).

Вы можете обратиться к автору за дополнительными материалами (исходники).

 

 

Исходный код Unix-времени и его две основные функции можно найти на Wiki. В сети есть еще варианты функций, но вариант из Wiki оказался более оптимальным. Незначительная синтаксическая модернизация функций из Wiki для использования в среде CubeMX и замена функций HAL RTC на собственные позволила:
- реализовать полноценный календарь, основанный на UNIX time и сохраняющий данные на длительный период при питании от резервной часовой батареи
- сократить размер занимаемой памяти более чем на 3000 байтов, без учета дополнительного кода для сохранения календаря при сбросе или выходе из режима ожидания.

На рисунке приводится код файла rtc.h, содержащий объявления структуры Unix-времени и некольких функций, которые объявляются в обрамлении комментариев /*USER CODE BEGIN...*/. В этом файле единственная функция, созданная CubeMX, MX_RTC_Init(void). Указанная функция изначально вызывается из main.c, этот вызов заменяется на вызов собственной функции mx_RTC_Init(void). Все функции собственной разработки имеют имена с первым префиксом в нижнем регистре. Функции из файла stm32f1xx_hal_rtc.c не используюся по прямому назначению и служат только как источник некоторых фрагментов кода библиотеки HAL и библиотеки LL.

Калибровка RTC

Основным фактором, влияющем на частоту кварцевого генератора, является изменение температуры окружающей среды. Для ослабления его влияния применяется один из двух способов — термостатирование или термокомпенсация. В RTC применяется термокомпенсация, суть которой состоит в удалении импульсов, каждые 32 секунды (для частоты 32768Гц), из входной частоты счетчика. Число удаляемых импульсов может быть от 0 до 127. Подробно можно ознакомиться в AN2604 STM32F101xx and STM32F103xx RTC calibration.

 

/* Define to prevent recursive inclusion ------------------------*/

#ifndef __rtc_H

#define __rtc_H

#ifdef __cplusplus

 extern "C" {

#endif

 

/* Includes ----------------------------------------------------*/

#include "main.h"

 

/* USER CODE BEGIN Includes */

#include <stdbool.h>

 

/* USER CODE END Includes */

 

extern RTC_HandleTypeDef hrtc;

 

/* USER CODE BEGIN Private defines */

typedef struct _XTM

{ /* date and time components */

       uint8_t tm_sec;

       uint8_t tm_min;

       uint8_t tm_hour;  /* 0-23 */

       uint8_t tm_mday;  /* 1-31 */

       uint8_t tm_wday;  /* 0 – 6; Sunday = 0 */

       uint8_t tm_mon;   /* 1-12 */

       uint16_t tm_year; /* 19xx, 20xx*/

}XTM;

 

#define _TBIAS_YEAR 1900

#define DAY_IN_YEAR 365

#define SEC_IN_DAY 86400

#define SEC_IN_WEAK 604800

#define SEC_IN_HOUR 3600

#define SEC_IN_MIN 60

 

#define _TBIAS_DAYS ((70 * (uint32_t)DAY_IN_YEAR) + 17)

#define _TBIAS_SECS (_TBIAS_DAYS * (uint32_t)SEC_IN_DAY)

#define MONTAB(year) (((year & 03) || (year == 0)) ? mos : lmos)

#define Daysto32(year, mon) (((year - 1) / 4) + MONTAB(year)[mon])

 

#define BKP_TM_LO  RTC_BKP_DR1

#define BKP_TM_HI  RTC_BKP_DR2

 

/* USER CODE END Private defines */

 

void MX_RTC_Init(void);

 

/* USER CODE BEGIN Prototypes */

void mx_RTC_Init(void);

HAL_StatusTypeDef rtc_SetTimeUnix(RTC_HandleTypeDef *hrtc, uint32_t utm);

uint32_t rtc_GetTimeUnix(RTC_HandleTypeDef *hrtc);

HAL_StatusTypeDef rtc_SetTimeAlarmUnix(RTC_HandleTypeDef *hrtc, uint32_t utm);

uint32_t rtc_GetTimeAlarmUnix(RTC_HandleTypeDef *hrtc);

 

void rtc_write32_BKUP(uint32_t bkup1, uint32_t bkup2, uint32_t data);

uint32_t rtc_read32_BKUP(uint32_t bkup1, uint32_t bkup2);

 

/* USER CODE END Prototypes */

 

#ifdef __cplusplus

}

#endif

#endif /*__ rtc_H */

 

 

Основные сведения об RTC STM32F103x

На рисунке показана упрощенная схема RTC из описания "RM0008.Reference manual". Дополнительно показаны 42 16-битных регистра для хранения пользовательских данных, которые также питаются от батареи часов RTC. Схема достаточно простая, содержит предварительный делитель, который формирует частоту 1Гц и 32-битный счетчик секундных импульсов. В паре со счетчиком работает регистр будильника, который выдает сигнал прерывания при совпадении значений счетчиков. Часть схемы с подписью "powered in Standby" может питаться от дополнительной батареи.

В указанном документе описаны только технические данные RTC. Реализация функционирования выполнена программно и с ее возможностями можно ознакомится в файле stm32f1xx_hal_rtc.c, который является частью HAL драйверов. HAL драйверы предназначены для интерактивного, простого в применении построения приложений. Подробно HAL драйверы описаны в UM1850.Description of STM32F1 HAL and Low-layer drivers. HAL используется с STM32CubeMX, графическим приложением, которое позволяет легко генерировать коды инициализации на языке С для всего семейства STM32. Вернемся к программной реализации RTC, описанной в файле stm32f1xx_hal_rtc.c. Перевод гласит следующее.

Версия RTC, используемая в семействах STM32F1, является версией V1. Все функции, поддерживаемые версией V2 для других семейств, не поддерживаются на F1.
Как и в V2, основными функциями RTC управляет аппаратная часть (HW). Но особенностью F1 программная реализация (SW) даты.
В результате есть некоторые ограничения по сравнению с другими семьями:
- Поддерживается только 24 часовой формат HAL (формат 12 часов не поддерживается).
- Дата сохраняется в SRAM. Если MCU находится в режиме STOP или STANDBY, дата будет потеряна. Пользователь должен реализовать способ сохранения даты перед входом в режим пониженного энергопотребления (пример снабжен пакетом прошивки на основе резервных регистров).
- Дата автоматически обновляется каждый раз, когда вызывается HAL_RTC_GetTime или HAL_RTC_GetDate.
- Обнаружение тревоги ограничено 1 днем. Срок действия истекает только 1 раз (повторение тревоги не требуется, необходимо запрограммировать новый сигнал тревоги).

Таким образом, программная реализация даты выполнена так, что необходимо приложить определенные усилия (написать немало кода) для ее сохранения и восстановления при сбросе и выходе из режима ожидания. При питании от батареи и отключения основного питания на срок более суток восстановление даты невозможно, поскольку дата в SRAM обнуляется, а счетчик считает только до 86400 секунд (сутки). Тоже касается и будильника, он ограничен одними сутками. При использовании стандартного решения для RTC, использование батареи позволит отключать питание только на сутки. В дополнение скажу, что только инициализация времени и даты (вызов 2-х функций) в стандартном исполнении занимает в памяти ~2700 байтов. Если обратится к документу Reference manual и коду, созданному CubeMX, то обнаружится, что доступ к счетчику RTC_CNT и RTC_ALR осуществляется, как к двум раздельным регистрам по 16 бит. В тоже время реализация часов от CubeMX использует только младшие половины счетчика и регистра, старшие всегда равны нулю (по результатам отладки). Такая реализация вызывает некоторые вопросы, которые остаются без ответа.

Если обратится к Windows, то там для отсчета времени используется 32 битный таймер (в новых ОС он расширен до 64 бит) и С библиотека time.h. Аналогично в ОС типа Unix. В стандартной библиотеке STM32 также есть файл time.h. Напрашивается решение отказаться от кода CubeMX и использовать счетчик и регистр полностью с библиотекой time.h. Что и было сделано. Однако в процессе отладки выяснилось, что вызов только одной функции mktime из time.h сразу добавляет ~10 кбайт памяти. Пришлось отказаться и от этого подхода. Для использования времени и календаря в большинстве случаев достаточно только преобразований из 32 битной величины в календарь в понимании человека и наоборот. Наиболее простой и экономный вариант использовать собственную реализацию UNIX-времени. Однако UNIX-время использует 32 битный таймер, что вызывает проблему 2038 года, когда счетчик обнулится. Проблема в Windows решается использованием 64 битных переменных. Можно достаточно просто решить проблему 2038 года и для RTC, достаточно выделить для этой цели один из регистров BKP, но эта задача пока не актуальна.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Число удаляемых импульсов определяется следующим образом. Изначально, при проектировании устройства, следует в CubeMX установить режим работы, когда на Tamper контакт выдается частота 512 Гц. Этот режим должен существовать постоянно, поскольку окружающая температура может изменяться в значительных пределах и может потребоваться повторная калибровка. Затем следует измерить эту частоту с помощью точного частотомера и расчитать величину отклонения ppm = ((F - Fnom) / Fnom) * 106. Далее по таблице из AN2604 определятся величина, которую нужно установить в регистре калибровки. Эта величина сохраняется при питании часов от батарейки.

Другой вариант определения калибровочной величины по уходу часов за 30 суток работы, по той же таблице. В этом варианте контакт Tamper оказыается не нужным и может использоваться для других целей.

Оба варианта обладают существенными недостатками, заключающимися в том, что потребуется либо перепрограмировать устройство, либо принимать дополнительные меры по стабилизации температуры. Оба этих варианта могут оказаться неприемлимыми для реализации. Предлагается иное решение. Практически все устройства в настоящее время реализуют виртуальный СОМ порт на интерфейсе USB. Следовательно, можно реализовать виртуальный СОМ порт и производить калибровку по данным сервера точного времени используя планшет или ноутбук с выходом в Интернет. Перепрограмировать устройство не нужно, частотомер также не нужен, все вычисления возлагаются на хост, который передает команду загрузки данных в RTC.

Литература.

Мартин М. Инсайдерское руководство по STM32

Агуров П.В. - Практика программирования USB - 2006

Datasheet STM32F103xET6

Description of STM32F1 HAL and Low-layer drivers

Reference Manuals

USB Complete. The Developer’s Guide, Fifth Edition, Jan Axelson

В начало

STM32F103x. Часы RTC, настройка по серверам точного времени