Вынеси программные часы, коррекцию по ProtoCAN RTCSETUP и атомарную метку логгера в переносимое ядро без глобального состояния. Подключи eCAN-A и CPU Timer2 отдельным портом F28335; зафиксируй календарные границы, переполнение, задержку RX и защиту IRQ в хостовых тестах.
13 KiB
Глобальное время
Программные часы с тактом 1 мс, синхронизацией даты и времени через ProtoCAN и атомарным получением метки для логгера. Ядро C99 не требует аппаратного RTC, операционной системы или динамической памяти. Порт TMS320F28335 включает eCAN-A и необязательный CPU Timer2. Все текстовые файлы — UTF-8.
Обмен при запуске
- Приложение инициализирует часы до разрешения IRQ и запускает источник 1 мс.
- После завершения инициализации всей платы вызывает
gt_ready()/gt_f28335_ready(). - Из main библиотека отправляет
DISCRETE/FLAGS,MsgBody=0x3000,Route=1, адрес самой платы,DLC=1,DATA=01. - Верхний уровень распознаёт пакет через
gt_parse_ready(), берёт свою текущую дату и посылает один broadcast всем платам, используяgt_make_rtc(). - Каждый узел принимает штатный
RTCSETUP, сравнивает время со своим, сохраняет величину коррекции и немедленно обновляет календарные часы. При отсутствии ответа узел повторяет готовность не чаще раза в секунду.
RTCSETUP полностью сохраняет действующий формат ProtoCAN.
Универсальное сообщение готовности здесь определено как новый профиль
DISCRETE/FLAGS; ранее такого общего пакета в базовом протоколе не было.
Подробный контракт обмена.
Код верхнего уровня для автоматической отправки времени подключается в его
приложении; библиотека предоставляет кодировщик и распознавание события старта.
Метка логгера
gt_get() одним атомарным чтением возвращает:
| Поле | Значение |
|---|---|
seconds, millisecond |
секунды от 2000-01-01 и доля 0..999 мс |
synchronized |
0 до первого корректного RTCSETUP, 1 после |
uptime_ms |
время работы modulo 2^32, независимое от переводов часов |
sync_uptime_ms |
момент приёма последнего опорного пакета |
generation |
номер принятой коррекции |
correction_ms |
последнее смещение, знаковое 64-битное значение в мс |
weekday |
фаза недели 0..6, продвигаемая при смене суток |
gt_timestamp_ms() формирует 64-битную метку от 2000 года.
gt_calendar() преобразует снимок в календарь и возвращает 0, пока дата неизвестна.
Для записей, которые должны различать переводы часов, сохраняйте также
generation, synchronized и/или uptime_ms. Календарное время может идти назад
после коррекции. Тайм-ауты следует считать по разности uptime_ms.
Без новых broadcast часы продолжают ход по локальному генератору;
возраст синхронизации равен (uint32_t)(uptime_ms - sync_uptime_ms).
#include "global_time_f28335.h" /* Подключает общую временную базу F28335. */
gt_stamp stamp; /* Содержит согласованную дату, миллисекунды и качество времени. */
gt_get(gt_f28335_clock(), &stamp); /* Допускается из main и ISR, включая ISR логгера. */
uint64_t time_ms = gt_timestamp_ms(&stamp); /* Перед сохранением календарной метки проверяется stamp.synchronized. */
Это фрагмент для функции потребителя. Формат хранения существующего логгера
библиотека не меняет. В частности, старое 32-битное поле time_ms в GAS logger
и v4 УМП не вмещает календарные миллисекунды: потребителю нужен собственный
формат абсолютной метки либо отдельная временная база и номер поколения.
Подключение TMS320F28335
Добавьте в сборку src/global_time.c и
ports/tms320f28335/global_time_f28335.c. Include-пути: include,
ports/tms320f28335, штатные TI DSP2833x_headers/include,
DSP2833x_common/include и include компилятора.
Ресурсы порта:
| Ресурс | Назначение |
|---|---|
| eCAN-A MBOX7 | RX точного RTCSETUP, любой приоритет, IRQ line0 |
| eCAN-A MBOX8 | TX готовности, ACK проверяется в main |
| CPU Timer2 / INT14 | необязательный собственный такт 1 мс |
Mailbox 0..6, скорость CAN, GPIO и глобальные маршруты PIE/CANGIM настраивает
приложение. DBO=0 обязателен; порт отвергает другую раскладку октетов.
MBOX7 использует CANOPC: кадр защищён от аппаратной перезаписи до копирования ISR.
В программной очереди хранится последний broadcast, поскольку более новый
опорный пакет заменяет предыдущий.
При запрещённых IRQ, после InitECan и InitPieVectTable:
int ok = gt_f28335_init_periph(5U); /* PERIPH5=Type1/ID5, то есть УМП1; номер берётся из конфигурации платы. */
if (ok) ok = gt_f28335_timer2_start(150000000UL); /* Частота CPU задаётся проектом в Гц; пример соответствует 150 МГц. */
gt_f28335_init() позволяет передать Type и ID непосредственно.
init_periph() поддерживает физические PERIPH 0..31: Type1/2 и ID0..15;
5 — УМП1, 6 — УМП2, 8 — задатчик. Порт инициализируется до подключения hooks.
Повторный init разрешён только при остановленном собственном Timer2,
отсутствующем TX и запрещённых глобальных IRQ.
Если Timer2 занят RTOS или приложением, не вызывайте timer2_start();
в существующем ISR с периодом ровно 1 мс вызывайте gt_f28335_tick_1ms().
Используйте один источник такта. Отдельный Timer2 продолжает отсчёт и при
медленном main, но длительная блокировка IRQ на несколько миллисекунд приводит
к потере тиков: аппаратный флаг прерывания не считает пропущенные периоды.
В существующем ECAN0INTA ISR перед очисткой общих CAN-флагов и PIEACK:
gt_f28335_rx_isr(); /* Копирует только MBOX7 и запоминает uptime при приёме, календарь проверяется позднее. */
Приложение должно разрешить соответствующий CAN IRQ: CANGIM.I0EN,
PIE group9 INTx5, CPU M_INT9; оставить свой обработчик остальных mailbox
и штатные подтверждения CANGIF/PIEACK. Порт не заменяет общий CAN ISR.
Глобальный EINT выполняет приложение после полной настройки.
После прикладной инициализации и в каждом проходе главного цикла соответственно:
gt_f28335_ready(); /* Выполняется один раз после загрузки параметров и запуска прикладных подсистем. */
gt_f28335_service(); /* Выполняется регулярно в main; обработка календаря и CAN не ждёт аппаратного ACK. */
Все атомарные чтения и обновления используют TI
__disable_interrupts() / __restore_interrupts(), сохраняя прежний INTM.
Транспорт ждёт подтверждение CANTA асинхронно и не перезаписывает занятый MBOX8.
При отсутствии других CAN-узлов передача остаётся аппаратному контроллеру
до восстановления шины. CAN ACK не подтверждает обработку пакета мастером;
приход корректного RTCSETUP прекращает повторные объявления готовности.
Точность и календарь
Разрешение локальных часов — 1 мс. Действующий RTCSETUP передаёт только целые секунды, поэтому сам формат не гарантирует синхронизацию плат с точностью 1 мс. Мастер должен посылать актуальное значение около секундной границы. Арбитраж CAN и задержка до RX ISR остаются погрешностью; задержка после RX ISR до обработки в main компенсируется по монотонному счётчику. Для точности между платами до 1 мс понадобится согласованное расширение проводного протокола.
Одна шкала времени выбирается верхним уровнем (рекомендуется UTC); кадр не
содержит часовой пояс. Входные годы 2000..2099, дата проверяется по григорианскому
календарю. Формат дня недели 0..6 соответствует проверке существующего
STM32-порта; профиль обозначает 0 как воскресенье. Для совместимости переданная
фаза недели сохраняется без дополнительной проверки соответствия дате.
Некоторые старые клиенты отображают неделю как 1..7; перед отправкой им нужен
перевод воскресенья 7 → 0.
Секундная шкала uint32_t от 2000 года переполнится в феврале 2136 года.
Период между захватом RX uptime и gt_receive() должен быть меньше 2^32 мс.
Проверки
Из корня templates:
python c/global-time/tests/run_tests.py
--cc задаёт GCC/Clang. Для отдельной TI C28x проверки передайте
--ti-cgt (каталог компилятора), --ti-headers (DSP2833x_headers/include)
и при необходимости --ti-common (DSP2833x_common/include).
Объекты и EXE создаются во временном каталоге. CMake также предоставляет
global_time, два CTest и опции GLOBAL_TIME_BUILD_F28335 /
GLOBAL_TIME_BUILD_TESTS; MCU проект задаёт свои TI include-пути.
Проверяются ошибки даты и кадра, високосный февраль, смена года, коррекции в обе стороны, компенсация очереди через переполнение uptime, ранний broadcast, повторы готовности, сохранение IRQ, изоляция eCAN mailbox, аппаратный ACK, значения периода Timer2 и его реальный ISR через назначенный вектор. TI-проверка компилирует исходники с large/COFF ABI и настоящими заголовками проекта 28335_periph. Полная линковка конкретной прошивки и проверка на плате в этот набор не входят.