Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Кармин Новиелло - Освоение STM32.pdf
Скачиваний:
2751
Добавлен:
23.09.2021
Размер:
47.68 Mб
Скачать

Часы реального времени

469

HAL_StatusTypeDef HAL_RTC_WaitForSynchro(RTC_HandleTypeDef* hrtc);

Однако вызов данной функции необходим тогда и только тогда, когда мы хотим получить доступ к теневым регистрам сразу после системного сброса или выхода из режима пониженного энергопотребления, когда тактовый сигнал SYSCLK все еще находится на минимальной частоте (поскольку он подается от HSI-генератора). Если тактовый сигнал HCLK по меньшей мере в восемь раз выше, чем RTCCLK, то синхронизация теневых регистров происходит за несколько тактов. При использовании процедуры HAL_RTC_WaitForSynchro() важно помнить, что доступ в режиме записи к так называемому резервному домену питания – backup domain (который включает в себя периферийное устройство RTC) по умолчанию отключен для предотвращения повреждения периферийных регистров из-за нестабильного источника питания. Однако процедуре HAL_RTC_WaitForSynchro() необходим доступ в режиме записи к регистрам RTC, и поэтому нам необходимо разрешить доступ в режиме записи к резервному домену питания

с помощью макроса __HAL_RTC_WRITEPROTECTION_DISABLE(), как показано ниже:

1/* Отключение защиты от записи */

2__HAL_RTC_WRITEPROTECTION_DISABLE(&hrtc);

3/* Ожидание, в течение которого теневые регистры синхронизируются */

4HAL_RTC_WaitForSynchro(&hrtc);

5/* Снова включение защиты от записи для предотвращения повреждения регистров. */

6__HAL_RTC_WRITEPROTECTION_ENABLE(&hrtc);

Наконец, можно обойти доступ к теневым регистрам. В этом случае не обязательно ждать времени синхронизации, но согласованность регистров календаря должна проверяться программным обеспечением. Пользователь должен прочитать необходимые значения полей календаря дважды. Затем результаты двух последовательностей чтения сравниваются. Если результаты совпадают, то результат чтения правильный. Если они не совпадают, поля должны быть прочитаны еще раз, и третий результат чтения является действительным. Чтобы обойти теневые регистры, CubeHAL предоставляет функцию:

HAL_StatusTypeDef HAL_RTCEx_EnableBypassShadow(RTC_HandleTypeDef* hrtc);

Чтобы снова включить доступ к теневым регистрам, мы можем использовать функцию:

HAL_StatusTypeDef HAL_RTCEx_DisableBypassShadow(RTC_HandleTypeDef* hrtc);

18.2.2. Конфигурирование будильников

RTC в STM32 предоставляет два будильника, называемых Alarm A и Alarm B, которые имеют одинаковые функции. Будильник может быть сгенерирован в заданное время или/и дату, запрограммированные пользователем. Для конфигурации будильника мы используем функцию:

HAL_StatusTypeDef HAL_RTC_SetAlarm(RTC_HandleTypeDef *hrtc,

RTC_AlarmTypeDef *sAlarm, uint32_t Format);

Часы реального времени

470

В конечном итоге мы можем опросить будильник, пока не произошло событие, используя функцию:

HAL_StatusTypeDef HAL_RTC_PollForAlarmAEvent(RTC_HandleTypeDef *hrtc, uint32_t Timeout);

Будильник может быть сконфигурирован так, чтобы при срабатывании он выдавал специальное прерывание. RTC_Alarm_IRQn – IRQ, связанный с обоими будильниками, и для конфигурации будильника в режиме прерываний мы можем использовать следующую специальную процедуру:

HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc,

RTC_AlarmTypeDef *sAlarm, uint32_t Format);

Как и во всех процедурах обработки прерываний CubeHAL, нам нужно вызвать

HAL_RTC_AlarmIRQHandler() из ISR RTC_Alarm_IRQn. Для получения уведомления о событии

будильника, мы можем реализовать соответствующий обратный вызов:

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc);

Будильник может быть отключен с помощью функции:

HAL_StatusTypeDef HAL_RTC_DeactivateAlarm(RTC_HandleTypeDef *hrtc, uint32_t Alarm);

Структура RTC_AlarmTypeDef, используемая для конфигурации будильника, определена следующим образом:

typedef struct {

 

 

RTC_TimeTypeDef AlarmTime;

/* Задает членов времени будильника RTC

*/

uint32_t AlarmMask;

/* Задает маски будильника RTC.

*/

uint32_t AlarmSubSecondMask;

/* Задает маски подсекунд будильника RTC.

*/

uint32_t AlarmDateWeekDaySel;

/* Задает, включен ли будильник RTC на число

 

 

месяца или на день недели.

*/

uint8_t AlarmDateWeekDay;

/* Задает число месяца/день недели будильника RTC. */

uint32_t Alarm;

/* Задает будильник (A или B).

*/

} RTC_AlarmTypeDef;

 

 

AlarmTime: это поле является экземпляром структуры RTC_TimeTypeDef, рассмотрен-

ной ранее, и используется для установки времени будильника.

AlarmMask: будильник состоит из регистра того же размера, что и счетчик времени

RTC. Когда счетчик RTC совпадает со значением, заданным в регистре будильника, он генерирует событие. Поле AlarmMask определяет критерии сравнения между будильником и регистром времени RTC. Оно может принимать одно или несколько (путем их битового маскирования) значений, указанных в таблице 2. Например, если мы хотим, чтобы будильник сработал в 12:45:03, мы используем значение RTC_ALARMMASK_NONE. Если вместо этого мы хотим генерировать будильник каждый час в заданную минуту и секунду, мы можем использовать значение

RTC_ALARMMASK_HOURS.

Часы реального времени

471

Таблица 2: Доступные маски будильников для настройки их поведения

Значение маски

Поведение будильника

 

 

RTC_ALARMMASK_NONE

Все поля используются при сравнении будильника (например,

 

будильник срабатывает в 12:45:03)

RTC_ALARMMASK_SECONDS

RTC_ALARMMASK_MINUTES

RTC_ALARMMASK_HOURS

RTC_ALARMMASK_DATEWEEKDAY

RTC_ALARMMASK_ALL

Секунды не имеют значения при сравнении будильника (например, будильник срабатывает каждую секунду в 12:45)

Минуты не имеют значения при сравнении будильника (например, будильник срабатывает на 3-й секунде каждой

минуты в 12:XX)

Часы не имеют значения при сравнении будильника (например, будильник срабатывает на 3-й секунде каждой 45-й минуты)

День недели (или число месяца, если оно выбрано) не имеет значения при сравнении будильника (например, будильник срабатывает все дни в 12:45:03)

Будильник срабатывает каждую секунду

AlarmDateWeekDaySel: задает, установлен ли будильник на дату (число месяца) или

на день недели (понедельник, вторник и т. д.). Может принимать значение

RTC_ALARMDATEWEEKDAYSEL_DATE или RTC_ALARMDATEWEEKDAYSEL_WEEKDAY.

AlarmDateWeekDay: если для поля AlarmDateWeekDaySel установлено значение

RTC_ALARMDATEWEEKDAYSEL_DATE, то для этого поля должно быть установлено значе-

ние в диапазоне 1–31. И, напротив, если поле AlarmDateWeekDaySel установлено в RTC_ALARMDATEWEEKDAYSEL_WEEKDAY, то в этом поле должны быть установлены сим-

вольные константы RTC_WEEKDAY_MONDAY, RTC_WEEKDAY_TUESDAY и т. д.

AlarmSubSecondMask: регистр подсекунд времени RTC может использоваться для

генерации событий с гранулярностью (масштабом дробления) ниже секунды. Маскируя отдельные биты регистра подсекунд, можно генерировать события каждые 1/128 с, 1/64 с и так далее. Для получения дополнительной информации о возможностях масок и их влиянии на поведение будильника обращайтесь к официальному AN3371 от ST3. Данная функциональность позволяет, например, использовать RTC в качестве генератора временного отсчета для HAL. ST предоставляет такой пример в проектах CubeHAL. Обратитесь к нему за дополнительной информацией.

Alarm: задает сконфигурированный будильник и может принимать значения

RTC_ALARM_A и RTC_ALARM_B.

18.2.3. Блок периодического пробуждения

В следующей главе мы увидим, что микроконтроллеры STM32 предоставляют возможность выборочного отключения внутренних функций для снижения энергопотребления. Несколько режимов пониженного энергопотребления дают программистам возможность выбирать уровень энергопотребления, который наилучшим образом соответствует их потребностям, особенно при разработке устройств с батарейным питанием.

3 http://www.st.com/content/ccc/resource/technical/document/application_note/7a/9c/de/da/84/e7/47/8a/DM00025071.pdf/files/DM00025071.pdf/jcr:content/translations/en.DM00025071.pdf

Часы реального времени

472

RTC в STM32 имеет периодический блок временного отсчета и пробуждения, который может пробудить систему, когда микроконтроллер работает в режимах пониженного энергопотребления. Данный блок представляет собой программируемый 16-разрядный таймер нисходящего отсчета с автоперезагрузкой. Когда этот счетчик достигает нуля, устанавливается флаг и генерируется прерывание (если разрешено). Блок пробуждения имеет следующие возможности:

Программируемый таймер нисходящего отсчета с автоперезагрузкой.

Специальные флаг и прерывание способны вывести устройство из режима пони-

женного энергопотребления.

Выход альтернативной функции пробуждения, который можно направить на выход будильника RTC (выход распределяется между будильниками Alarm A, Alarm B или блоком пробуждения Wakeup), с конфигурируемой полярностью.

Полный набор предделителей для выбора желаемого периода ожидания.

Частота отсчета счетчика пробуждения может быть получена либо из источника RTCCLK и, в конечном итоге, дополнительно поделена, либо из тактового сигнала календаря (то есть после асинхронного и синхронного предделителей). Это дает возможность генерировать события пробуждения с частотой от 122 мкс до более 48 дней, когда выбран внешний тактовый сигнал от LSE-генератора.

Для конфигурации события пробуждения, CubeHAL предоставляет функцию:

HAL_StatusTypeDef HAL_RTCEx_SetWakeUpTimer(RTC_HandleTypeDef *hrtc, uint32_t WakeUpCounter, uint32_t WakeUpClock);

где параметр WakeUpCounter устанавливает значение автоперезагрузки (то есть период) счетчика пробуждения, а параметр WakeUpClock задает частоту счетчика, и он может принимать одно из значений, перечисленных в таблице 3.

Таблица 3: Доступные значения параметра WakeUpClock

Источник тактового сигнала

 

счетчика пробуждения

Описание

 

 

RTC_WAKEUPCLOCK_RTCCLK_DIV2

Источник тактового сигнала счетчика пробуждения уста-

 

новлен на RTCCLK/2.

RTC_WAKEUPCLOCK_RTCCLK_DIV4

Источник тактового сигнала счетчика пробуждения установлен на RTCCLK/4

RTC_WAKEUPCLOCK_RTCCLK_DIV8

Источник тактового сигнала счетчика пробуждения установлен на RTCCLK/8

RTC_WAKEUPCLOCK_RTCCLK_DIV16

Источник тактового сигнала счетчика пробуждения уста-

новлен на RTCCLK/16

RTC_WAKEUPCLOCK_CK_SPRE_16BITS Источник тактового сигнала счетчика пробуждения уста-

новлен на Тактовый сигнал Календаря

RTC_WAKEUPCLOCK_CK_SPRE_17BITS Источник тактового сигнала счетчика пробуждения уста-

новлен на Тактовый сигнал Календаря , и счетчик пробуж-

дения увеличивается на дополнительный бит (поэтому он может считать до 0x1FFFF).

Независимый IRQ (RTC_WKUP_IRQn) связан со счетчиком пробуждения, и его можно разрешить с помощью функции:

Часы реального времени

473

HAL_RTCEx_SetWakeUpTimer_IT(RTC_HandleTypeDef *hrtc, uint32_t WakeUpCounter, uint32_t WakeUpClock);

Как обычно, мы должны вызвать HAL_RTCEx_WakeUpTimerIRQHandler() из ISR и быть готовыми к оповещению о событии пробуждения, реализовав HAL_RTCEx_WakeUpTimerEventCallback(). В противном случае, если использовать счетчик пробуждения в режиме опроса, мы можем использовать HAL_RTCEx_PollForWakeUpTimerEvent() для обнаружения события пробуждения (что не очень полезно, если честно).

18.2.4.Генерация временной отметки и обнаружение несанкционированного доступа

Периферийное устройство RTC подключено к нескольким I/O в зависимости от используемого корпуса. Эти I/O могут использоваться для генерации временной отметки (timestamp) при изменении их состояния. Текущая дата/время сохраняются в специальных регистрах, а также срабатывает соответствующее прерывание, если оно разрешено.

Для конфигурации временной отметки CubeHAL предоставляет функцию:

HAL_RTCEx_SetTimeStamp(RTC_HandleTypeDef *hrtc, uint32_t TimeStampEdge, uint32_t RTC_TimeStampPin);

Параметр TimeStampEdge задает фронт вывода, на котором активирован режим временной отметки. Данный параметр может принимать одно из следующих значений:

RTC_TIMESTAMPEDGE_RISING и RTC_TIMESTAMPEDGE_FALLING. RTC_TimeStampPin задает вводы/вы-

воды, используемые для генерации временной отметки, и может принимать значение RTC_TIMESTAMPPIN_DEFAULT (которое обычно соответствует выводу PC13) или значение

RTC_TIMESTAMPPIN_PA0 или RTC_TIMESTAMPPIN_POS1 для задания альтернативного вывода

(обычно PA0 или PI8).

Чтобы разрешить прерывание, связанное с соответствующим IRQ TAMP_STAMP_IRQn, мы можем использовать функцию:

HAL_RTCEx_SetTimeStamp_IT(RTC_HandleTypeDef *hrtc, uint32_t TimeStampEdge, uint32_t RTC_TimeStampPin);

HAL_RTCEx_TamperTimeStampIRQHandler() является обработчиком, вызываемым из ISR, в то

время как HAL_RTCEx_TimeStampEventCallback() является соответствующим обратным вызовом. Если вместо этого мы хотим использовать функцию временной отметки в режиме опроса, мы можем использовать функцию:

HAL_RTCEx_PollForTimeStampEvent(RTC_HandleTypeDef *hrtc, uint32_t Timeout);

для опроса события временной отметки. Чтобы получить дату/время, сохраненные в регистрах временной отметки, мы можем использовать функцию:

HAL_RTCEx_GetTimeStamp(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTimeStamp,

RTC_DateTypeDef *sTimeStampDate, uint32_t Format);