STM32 RTC, Calendar.
Начнем с того, что RTC — это аббревиатура которая расшифровывается следующим образом Real-time clock или по-русски, часы реального времени. В былые времена, при использовании МК AVR в качестве RTC, использовал отдельную микросхему, общение с которой происходило по определенному протоколу. У STM32 RTC же представляет собой модуль, реализованный внутри МК.
У STM32 RTC обладает следующими возможностями:
А также некоторыми особенностями, которые хотелось бы упомянуть:
События по которым могут возникать прерывания:
Что касается питания, для непрерывной работы часов им необходим отдельный источник питания, в качестве которого зачастую выступает батарейка, которая подключается к ножке VBAT.
В качестве примера предлагаю рассмотреть как запустить часы и настроить календарь, но перед этим рассмотрим внутреннюю структуру RTC.
Для тактирования модуля RTC может использоваться один из трех источников:
Выбор источника тактирования настраивается битовым полем RTCSEL[1:0] в регистре RCC_BDCR
LSEON(LSE oscillator enable) — включение LSE.
LSERDY(LSE oscillator ready) — флаг готовности LSE.
LSEBYP(LSE oscillator bypass) — единица в этом бите позволяет тактировать RTC от внешнего источника. Внешний тактовый сигнал (меандр, синус или треугольник) со скважностью 50% подаётся только на вывод OSC32_IN, при этом вывод OSC32_OUT можно использовать в качестве GPIO.
LSEDRV LSE[1:0](oscillator drive capability) — определяет уровень возбуждения кварца.
RTCSEL[1:0]( RTC clock source selection) — выбор источникам тактового сигнала для RTCCLK.
RTCEN(RTC clock enable) — единица в этом бите включает тактирование RTC.
BDRST(Backup domain software reset) — единица в этом бите полностью сбрасывает значение Backup domain.
После того как выбран источник тактирования необходимо позаботится о том, чтобы счетные регистры RTC тактировались с частотой один 1Hz. Для понижения частоты тактирования до 1Hz предназначены два предделителя, синхронный и асинхронный.
Расчет их значений производится по формуле.
Изначально значения PREDIV_A = 127, PREDIV_S = 255, что позволяет из 32768 Hz получить 1 Hz .
Для установки времени выделен один 32-x битный регистр, разбитый на битовые поля.
Данные в нем хранятся в формате BCD, при чем единицы и десятки в отдельных битовых полях. Думаю пояснения требует только бит PM, отвечающий за формат хранения часов. Если в нем установлен ноль, часы будут тикать от 0 до 24 часов, если единица – от 1 до 12.
С датой все аналогично, она хранится в 32-х битном регистре, разбитом на битовые поля.
Ниже приведен код настройки и запуска часов для STM32F303.
В случае если RTC тактируется от внешнего кварца, необходимо инициализацию LSI заменить следующим кодом.
У STM32 RTC обладает следующими возможностями:
- Автоматическое пробуждение во всех режимах энергосбережения
- Независимый BCD таймер счетчик. Отсчет времени и календарь реализованы аппаратно, с возможностью настройки сигнализирующих прерываний.
- Программный флаг пробуждения с возможностью вызова прерывания.
- Два 32-х разрядных регистра, в которых хранятся секунды, минуты, часы(в 12 часовом или 24 часовом формате), день недели, день месяца, месяц и год. Секунды хранятся в двоичном формате, все остальное в двоично-десятичном.
- Компенсация длинны месяца(а также високосного года) выполняется автоматически. Также возможна компенсация летнего времени.
- Два 32-х разрядных регистра программируемых сигнализирующих прерываний.
- Наличие калибровки для компенсации отклонения кварцевого резонатора.
- После сброса область RTC защищена от случайной записи.
- До тех пор пока напряжение питания RTC остается в рабочем диапазоне, он будет работать в не зависимости от режима работы(Run mode, low-power mode or under reset).
А также некоторыми особенностями, которые хотелось бы упомянуть:
- Для повышения точности, можно синхронизировать часы с сетью 50 или 60Hz.
- Возможно записывать время возникновения события, так называемый Time-stamp.
- Определение вмешательства(tamper), при этом сбрасываются все backup регистры.
События по которым могут возникать прерывания:
- Alarm A
- Alarm B
- Wakeup interrupt
- Time-stamp
- Tamper detection
Что касается питания, для непрерывной работы часов им необходим отдельный источник питания, в качестве которого зачастую выступает батарейка, которая подключается к ножке VBAT.
В качестве примера предлагаю рассмотреть как запустить часы и настроить календарь, но перед этим рассмотрим внутреннюю структуру RTC.
Для тактирования модуля RTC может использоваться один из трех источников:
- LSI — низкочастотный внутренний RC-генератор на 40 KHz.
- LSE — внешний, "часовой" кварцевый резонатор на 32 768 Hz.
- HSE/32 — внешний высокочастотный кварцевый резонатор с предделителем 32.
Выбор источника тактирования настраивается битовым полем RTCSEL[1:0] в регистре RCC_BDCR
LSEON(LSE oscillator enable) — включение LSE.
LSERDY(LSE oscillator ready) — флаг готовности LSE.
LSEBYP(LSE oscillator bypass) — единица в этом бите позволяет тактировать RTC от внешнего источника. Внешний тактовый сигнал (меандр, синус или треугольник) со скважностью 50% подаётся только на вывод OSC32_IN, при этом вывод OSC32_OUT можно использовать в качестве GPIO.
LSEDRV LSE[1:0](oscillator drive capability) — определяет уровень возбуждения кварца.
- 00: нижний
- 01: между нижним и средним
- 10: между средним и высоким
- 11: высокий, значение по умолчанию
RTCSEL[1:0]( RTC clock source selection) — выбор источникам тактового сигнала для RTCCLK.
- 01: LSE выступает в качестве источника.
- 10: LSI выступает в качестве источника.
- 11: HSE/32 выступает в качестве источника.
RTCEN(RTC clock enable) — единица в этом бите включает тактирование RTC.
BDRST(Backup domain software reset) — единица в этом бите полностью сбрасывает значение Backup domain.
После того как выбран источник тактирования необходимо позаботится о том, чтобы счетные регистры RTC тактировались с частотой один 1Hz. Для понижения частоты тактирования до 1Hz предназначены два предделителя, синхронный и асинхронный.
Расчет их значений производится по формуле.
Изначально значения PREDIV_A = 127, PREDIV_S = 255, что позволяет из 32768 Hz получить 1 Hz .
Для установки времени выделен один 32-x битный регистр, разбитый на битовые поля.
Данные в нем хранятся в формате BCD, при чем единицы и десятки в отдельных битовых полях. Думаю пояснения требует только бит PM, отвечающий за формат хранения часов. Если в нем установлен ноль, часы будут тикать от 0 до 24 часов, если единица – от 1 до 12.
С датой все аналогично, она хранится в 32-х битном регистре, разбитом на битовые поля.
Ниже приведен код настройки и запуска часов для STM32F303.
#include "stm32f3xx.h"
//определяем новый тип, который содержит в себе структуру с битовыми полями
typedef struct sRTC_struct{
unsigned year : 6;
unsigned month : 4;
unsigned week : 3;
unsigned date : 5;
unsigned hour : 5;
unsigned minute :6;
unsigned sec : 6;
}RTC_struct;
//создаем экземпляр этого типа
volatile RTC_struct rtc;
void RTC_Init(RTC_struct volatile *value)
{
// Включаем LSI
RCC->CSR |= RCC_CSR_LSION;
// Ждем его готовности
while ( !(RCC->CSR & RCC_CSR_LSIRDY) ){}
// Включаем тактирование модуля PWR
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// После сброса регистры RTC находятся в защищенном домене
// Для разрешения записи необходимо поставить флаг в PWR->CR
PWR->CR |= PWR_CR_DBP;
// Выбераем источник тактирования RTC( от низкоскоростного внутреннего источника LSI(40 kHz) )
RCC->BDCR |= RCC_BDCR_RTCSEL_LSI;
// Включаем тактиование RTC
RCC->BDCR |= RCC_BDCR_RTCEN;
RTC_Update(value);
}
void RTC_Update(RTC_struct volatile *value)
{
uint32_t TR, DR;
// Выключаем защиту от записи
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// Входим в режим редактирования
RTC->ISR |= RTC_ISR_INIT;
// Ждем подтверждения входа в режим редактирования
while( !(RTC->ISR & RTC_ISR_INITF) ){};
// Устанавливаем асинхронный предделитель на 100(99+1).
RTC->PRER = (uint32_t)(99 << 16);
// Установим синхронный предделитель на 400(399+1).
RTC->PRER |= (uint32_t)399;
// Устанавливаем время
TR = ( ((uint32_t)(value->hour/10*16 + value->hour%10) << 16) | ((uint32_t)(value->minute/10*16 + value->minute%10) << 8) | ((uint32_t)value->sec/10*16 + value->sec%10) );
RTC->TR = TR;
// Устанавливаем дату
DR = (uint32_t)(value->year/10*16 + value->year%10) << 16 | (uint32_t)(value->week/10*16 + value->week%10) << 13 | (uint32_t)(value->month/10*16 + value->month%10) << 8 | (uint32_t)(value->date/10*16 + value->date%10);
RTC->DR = DR;
// Выходим из режима редактирования
RTC->ISR &= ~(RTC_ISR_INIT);
// Включаем защиту от записи
RTC->WPR = 0xFF;
}
В случае если RTC тактируется от внешнего кварца, необходимо инициализацию LSI заменить следующим кодом.
//Проверяем тикают ли часики
if(RTC->ISR & RTC_ISR_INITS) return;
//Включаем LSE
RCC->BDCR |= RCC_BDCR_LSEON;
// Ждем его готовности
while (!(RCC->BDCR & RCC_BDCR_LSEON)){}
//Выбираем LSE в качестве источника (кварц 32768)
RCC->BDCR |= RCC_BDCR_RTCSEL_LSE;
//Включаем тактирование RTC
RCC->BDCR |= RCC_BDCR_RTCEN;
Похожие статьи