В STM32, конечно же, есть контроллер часов реального времени.
Для его запуска не обязательно даже иметь внешний кварц на 32.768 кГц, так как затактировать можно от внутреннего LSI-генератора на ~32 кГц (с возможностью калибровки) или внешнего основного кварца (с настраиваемым предделителем).
А ещё, как бонус, 20 регистров (80 байт) для хранения разных данных, питание им будет идти от батарейки, от которой часы и работают, когда нет основного питания.
Возможностей у часов много, они подробно описаны в RM, остановимся пока на базовом уровне...
читать дальшеОсновные регистры, которые надо знать, чтоб запустить RTC в минимальном режиме:
RCC_BDCR — выбор источника и включение тактирования RTC, управление внешним кварцем на 32.768 кГц;
RCC_CFGR — предделитель частоты внешнего основного кварца для RTC (чтоб на RTC шёл сигнал с частотой 1 МГц);
RTC_TR — регистр с текущим состоянием времени (запись возможна только при инициализации);
RTC_DR — регистр с текущей датой (аналогично);
RTC_CR — основная настройка режима работы часов;
RTC_ISR — регистр инициализации, с его помощью можно ввести часы в одноимённый режим;
RTC_PRER — внутренний предделитель тактовго сигнала;
RTC_CALIBR — подстройка часов (с шагом в 2 ppm в минус и 4 ppm в плюс);
RTC_WPR — разблокировка защиты от записи;
Так-то регистров там ещё много, но пока фиг с ними.
Итак, контроллер включился первый раз, все регистры часов сброшены, тактирование на модуль не поступает. Для теста попробуем включить часы от внутреннего источника тактирования LSI (на STM32F4-Discovery есть место под внешний часовой кварц, но он не распаян: X3). Конечно, при ресете, от такого источника часы накроются медным тазом, но пофиг.
1. Первым делом надо запустить внутренний генератор на 32 кГц.
В регистре RCC_CSR есть два флага: LSIRDY и LSION. Логика проста: выставляем флаг LSION, чтобы генератор завёлся, и ждём, когда он стабилизируется. Это будет показано появлением флага LSIRDY. После этого генератор можно использовать.
Для внешнего кварца логика такая же, только флаги LSERDY и LSEON находятся в регистре RCC_BDCR.
2. Регистры энергонезависимого домена (RCC_BDCR к ним относится) защищены от записи. Чтобы это исправить, надо запустить тактирование модуля управления питанием (POWER), установив флаг PWREN в регистре RCC_APB1ENR, а затем и флаг DBF (бит 8) в регистре PWR_CR. Защита отключится. Иначе можно долго гадать, какого же флаг RTCEN не хочет ставиться, когда BDRST прекрасно это делает.
3. На всякий случай сбросим состояние энергонезависимого домена, установив и сбросив флаг BDRST в том же регистре RCC_BDCR.
4. Далее включим тактирование часов (RTCCLK) от этого источника: в регистре RCC_BDCR надо выбрать источник тактирования флагами RTCSEL (биты 9-8, за LSI отвечает значение 2) и включить его флагом RTCEN (бит 15). После выбора источника тактирования часов, менять его уже нельзя, только полным сбросом домена (всё тот же BDRST).
5. Тактирование на модуль часов подано. Теперь можно их инициализировать. После запуска все важные регистры часов защищены от записи. Чтобы её отключить, надо по очереди записать в регистр RTC_WPR два числа: 0xCA и 0x53, в таком вот порядке. Запись любых иных чисел вернёт защиту снова.
6. Когда защита отключена, в регистре RTC_ISR надо установить флаг INIT (бит 7), при этом часы будут остановлены и станет возможно их значения изменить. Но сначала надо подождать установки флага INITF там же, как свидетельство готовности.
7. Дальше настраивается предделитель, который должен выдавать сигнал с частотой 1 Гц. Тут тоже хитрый процесс.
Сначала записывается значение в синхронный предделитель, потом в асинхронный. Даже если нужно установить только одно из них, актов записи должно быть два!
Для LSI синхронный предделитель равен 249, асинхронный 127. Для LSE синхронный предделитель становится 255, асинхронный такой же.
8. Часы готовы к загрузке начальных значений в регистры RTC_TR и RTC_DR. Формат времени (12/24) выбирается флагом FMT (бит 6) в регистре RTC_CR, но это по желанию и после загрузки даты и времени.
Важное замечание: загружать надо сразу весь регистр целиком! То, что будет читаться из регистра сейчас не соответствует истине (там предыдущее значение сидит, бывшее при установке флага INIT). И оно обновится только после сброса этого же флага. Все операции |= и &= на самом регистре пойдут прахом.
9. После всего этого режим инициализации отключается сбросом флага INIT и часы начинают идти. А ещё теперь в регистре RTC_ISR установлен флаг INITS, который можно проверять при запуске контроллера насчёт наличия этой вот настройки часов.
10. Ну и на всякий случай следует в конце вернуть блокировки записи и т.д.
Успех!
Читать регистры TR и DR можно уже когда угодно.
Примерный код инициализации:
Код теста:
Проект настраивает RTC при запуске и считывает постоянно дату и время. Моргает, если секунда нечётная.
Интересные файлы:
rtc.c
rtc.h
Проект целиком.<< Предыдущее Следующее >>
@темы:
arm,
программизмы,
электроника,
stm32f4discovery,
stm32
Но, вроде, здесь можно подстраивать частоту (+-ppm да и выбирать частоту импульсов)? Или я путаю с другим контроллером? .з. Блин, везде часы и везде все разные по возможностям, надо рефман поглядеть.
У меня стоит кварц и я немного переделал процедуру инициализации под LSE. А именно:
читать дальше
Писать и читать пробовал следующими процедурами:
Что я не так делаю, а то не фурычит, читаются нули. Проц у меня STM32F407.
потому вынесите код
до проверки на инициализированность rtc =)
Для RTC эти флаги нужны только для настройки, а для BKP всегда. Ну либо снимать защиту DBP на время доступа к энергонезависимому домену — так будет даже лучше.
Огромное Вам СПАСИБО, выручили. Всё работает, но регистры 8 разрядные, больше чем 0xFF записать не удаётся.
// Сброс состояния часов
void rtc_Reset(void)
{
// Включим тактирование PWR
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
// Разрешим доступ к управляющим регистрам энергонезависимого домена
PWR->CR |= PWR_CR_DBP;
// Выберем его как источник тактирования RTC:
RCC->BDCR |= RCC_BDCR_BDRST;
RCC->BDCR &= ~RCC_BDCR_BDRST;
А часы не должны ведь каждый раз сбрасываться командой
RCC->BDCR |= RCC_BDCR_BDRST;
RCC->BDCR &= ~RCC_BDCR_BDRST;
Я имею ввиду случай когда подключена резервная батарейка и часы должны идти все время.
RSF нужно ждать после любого изменения в тактировании модуля RTC (что происходит при запуске контроллера), чтобы убедиться, что внутренние регистры синхронизировались с внешними.
Гость, не должно быть так. В отладчике смотрели?
Кстати, если считывать непосредственно после записи, может считаться и байда. Там же есть теневые регистры, которые могут обновить по запросу содержимое рабочих далеко не каждый такт. Часы работают от медленного генератора и синхронизироваться с ними надо. потому после установки времени надо некоторое время подождать, прежде чес считывать данные (там есть флаг какой-то, когда происходит обновление). Может, дело в этом, не знаю...
Ситуация такая, при отключении питания часы стоят, при включении процессор stm32f4 запускается только с ресета. Далее часы начинают работу со времени на момент выключения.
И еще не знаете, может у меня просто внешний кварц не запускается, а на внутреннем от батарейки не должен работать?
Внутренний работает только при основном питании.
Дополнительно, для нормального потребления от батарейки нужно PDR_ON посадить на + (может кому пригодится), если на 0, то при батарейке, ядро остается под питанием, и запуск будет только через ресет.
Про PDR_ON не знал =)