STM32 RTC, Calendar.

STM32 RTC, Calendar.

Начнем с того, что RTC — это аббревиатура которая расшифровывается следующим образом Real-time clock или по-русски, часы реального времени. В былые времена, при использовании МК AVR в качестве RTC, использовал отдельную микросхему, общение с которой происходило по определенному протоколу. У STM32 RTC же представляет собой модуль, реализованный внутри МК.

У 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.
STM32 RTC, Calendar.

Для тактирования модуля RTC может использоваться один из трех источников:
  • LSI — низкочастотный внутренний RC-генератор на 40 KHz.
  • LSE — внешний, "часовой" кварцевый резонатор на 32 768 Hz.
  • HSE/32 — внешний высокочастотный кварцевый резонатор с предделителем 32.


Выбор источника тактирования настраивается битовым полем RTCSEL[1:0] в регистре RCC_BDCR
STM32 RTC, Calendar.

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 предназначены два предделителя, синхронный и асинхронный.
STM32 RTC, Calendar.

Расчет их значений производится по формуле.
STM32 RTC, Calendar.

Изначально значения PREDIV_A = 127, PREDIV_S = 255, что позволяет из 32768 Hz получить 1 Hz .

Для установки времени выделен один 32-x битный регистр, разбитый на битовые поля.
STM32 RTC, Calendar.

Данные в нем хранятся в формате BCD, при чем единицы и десятки в отдельных битовых полях. Думаю пояснения требует только бит PM, отвечающий за формат хранения часов. Если в нем установлен ноль, часы будут тикать от 0 до 24 часов, если единица – от 1 до 12.

С датой все аналогично, она хранится в 32-х битном регистре, разбитом на битовые поля.
STM32 RTC, Calendar.

Ниже приведен код настройки и запуска часов для 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;
комментарии
0