Перейти к содержанию
    

Как правильно получать доли секунд от RTC STM32?

Понадобилось мне время поточнее.

 

В новом RTC у тех STM-ок, что поновее (вроде бы у всех, кроме F1) есть специальный регистр для этого - SSR.

Также есть два предделителя: синхронный и асинхронный.

Делаю такую инициализацию:

 

    static constexpr unsigned quartzFreqHz = 32768;  // частота кварца
    static constexpr unsigned asyncPrediv = 0x1F;      // асинхронный предделитель
    static constexpr unsigned syncPrediv = quartzFreqHz / (asyncPrediv + 1) - 1;  // синхронный предделитель
.....
    RTC->PRER = syncPrediv;
    RTC->PRER |= asyncPrediv << 16;

 

После этого я ожидаю, что в регистре SSR будут значения от 0 до 32768/(asyncPrediv+1) = 1024. Однако, запустив цикл вывода значений SSR на печать, я наблюдаю там числа от 0 до 1055(!). Возможно и более, я не очень долго смотрел.

 

Внимание, вопрос: почему так? Что я сделал не так? Кто-нибудь сталкивался с таким?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Внимание, вопрос: почему так? Что я сделал не так? Кто-нибудь сталкивался с таким?

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

Не знаю как точно это устроено в STM32, но в других МК, в которых я работал с внутренним RTC, он находится в отдельном домене питания и связь этого домена с системным доменом - последовательная. Т.е. RTC считает в своём домене, а при запросах чтения/записи IO-регистров RTC данные от него/к нему передаются через последовательный канал, что приводит к выставлению сигнала HALT ядру до момента завершения передачи. И передача может достигать нескольких сотен системных тиков (в зависимости от частоты ядра). Соответственно и время выполнения такой команды.

Так сделано по-крайней мере в МК Infenion и Tiva и сиё подробно расписано в даташитах. Сильно подозреваю что в STM32 дела обстоят аналогично.

Если действительно нужно быстро читать из часов реального времени, то можно задействовать любой general purpose timer, засинхронизировать его по edge секундного прерывания от RTC и работать уже с его счётчиком. Периодически подсинхронизируя этот таймер с RTC методом ФАПЧ.

Тогда и доли секунд и даже микросекунды реально будет получить без всяких задержек.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не, там и больше бывает. Сейчас вот увидел 1214.

 

Вот что получается, читаю примерно раз в 100 мс:

03:26:39,1050
03:26:39,945
03:26:39,839
03:26:39,734
03:26:39,629
03:26:39,523
03:26:39,418
03:26:39,312
03:26:39,207
03:26:39,102
03:26:39,1214
03:26:40,1109
03:26:40,1003
03:26:40,898
03:26:40,793
03:26:40,687
03:26:40,582
03:26:40,477
03:26:40,371
03:26:40,266
03:26:40,160
03:26:40,55
03:26:40,1168
03:26:41,1062
03:26:41,957

 

Видно, что счётчик этот перезаряжается раньше, чем перещёлкиваются секунды. И непонятным значением.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Неужели никто не сталкивался с таким?

Не применял дробную часть, нужды не было.

Сейчас под отладчиком посмотрел что в STM32L1 в SSR при стандартных делителях 128+256: как и ожидалось, диапазон от 0 до 0xFF. Так что может у вас, действительно, асинхронный делитель на 31 делит?

 

Кстати, а есть ли смысл в чтении дробной части? С "теневыми регистрами" вроде смысла нет. Если их отключить (BYPSHAD=1), то все равно читать нужно минимум дважды для исключения попадания на фронт клока, когда читаться будет лабуда. Точности нет...

 

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

Не знаю как точно это устроено в STM32, но в других МК, в которых я работал с внутренним RTC, он находится в отдельном домене питания и связь этого домена с системным доменом - последовательная. Т.е. RTC считает в своём домене, а при запросах чтения/записи IO-регистров RTC данные от него/к нему передаются через последовательный канал, что приводит к выставлению сигнала HALT ядру до момента завершения передачи. И передача может достигать нескольких сотен системных тиков (в зависимости от частоты ядра). Соответственно и время выполнения такой команды.

Так сделано по-крайней мере в МК Infenion и Tiva и сиё подробно расписано в даташитах. Сильно подозреваю что в STM32 дела обстоят аналогично.

В STM32 домены питания тоже разные, но шина между ними параллельная. Читается быстрее, но тоже есть ограничение на частоты доменов, присутствуют "теневые регистры", куда периодически копируется синхронная копия даты/времени, которая у них сбоит - errata :) , разные флаги синхронизации. Т.е. тоже - не подарок...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Так, с диапазоном разобрался: перепутал частоту внешнего кварца и внутреннего :)

 

Осталась проблема перескока счётчика субсекунд до переключения секунды:

 

00:00:05,408
00:00:05,303
00:00:05,198
00:00:05,92
00:00:05,1011  << вот здесь!
00:00:06,905
00:00:06,800

 

Думаю, это сейчас тоже победю, изменив последовательность чтения...

 

----

Добавлено:

 

Да, всё, порядок. Если читать сначала субсекунды, а потом время, то получается консистентно.

 

Добавил масштабирование [1023..0] -> [0..999], стало вообще отлично.

 

Спасибо всем, кто поучаствовал в обсуждении!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В STM32 домены питания тоже разные, но шина между ними параллельная. Читается быстрее, но тоже есть ограничение на частоты доменов, присутствуют "теневые регистры", куда периодически копируется синхронная копия даты/времени, которая у них сбоит - errata :) , разные флаги синхронизации. Т.е. тоже - не подарок...

Если нужны доли секунды то лучше вообще не использовать чтение регистров RTC. А синхронизировать работу одного из таймеров общего назначения с секундным импульсом.

Делал так, получал дискретность времени до мкс. Секундные импульсы брал с внешнего высокоточного генератора. И постоянно подсинхронизировал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для системы старт-финиш, синхронизирующейся по pps от GPS, я делал автоподстройку таймера. В данном случае тоже можно завести отдельный таймер, который автоподстраивать периодически по RTC. И будут вам и милли, и микросекунды при желании!

 

// плохо читаю комментарии, выше уже как раз-таки это посоветовали.

Изменено пользователем Эдди

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если контроллер в основном глубоко спит, и просыпается на десятки-сотни миллисекунд, то таймеры никак не помогут. А RTC с миллисекундами - очень даже удобен. Кстати, и будильник можно зарядить с точностью до миллисекунд.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...