Инструменты пользователя

Инструменты сайта


prog:ethernet:ptp_basis

Основы протокола PTP и 1923КХ028

(Данная статья не претендует на полноту и достоверность изложения. В ней представлены лишь основные моменты с которыми пришлось столкнуться при знакомстве с протоколом PTP и тем, как его поддерживает 1923KX028. В примерах нет полноценной реализации протокола РТР, а лишь единичные циклы обмена сообщениями, как это обычно рисуют на картинках про PTP. Примеры показывают лишь, что этих единичных циклов синхронизации достаточно, чтобы согласовать время между двумя устройствами. Ресурсы для изучения:

)

Протокол PTP используется для для высокоточной синхронизации времени между устройствами в сети Ethernet. Он позволяться согласовать и поддерживать внутреннее время нескольких устройств в сети с точностью до 10нс. Это особенно важно в промышленном Ethernet, когда есть необходимость, чтобы несколько устройств работали максимально согласованно.

Идея синхронизации времени достаточно проста - необходимо, чтобы устройства обменялись парой сообщений, тогда имея времена отправки и приема этих сообщений, можно высчитать разницу во времени между двумя устройствами. Для наглядности, рассмотрим рассчет времени по картинке:

В левой части представлен случай, когда время в обоих устройствах Ethernet одинаково. Тогда времена посылки и приема сообщений различаются только на время прохождения фрейма по кабелю (LinkDelay).

В правой части нарисован случай, когда время в устройствах разное, допустим оно отличается на некоторую величину - Offset. Тогда уравнения из первого случая изменяться с учетом этого смещения по времени. Далее, предполагается что фреймы идут между устройствами по одному и тому-же кабелю, например по витой паре. Соответственно, время прохождения первого и второго сообщений равны. При данном условии можно вывести уравнения для нахождения значений Offset и LinkTime на основе только времен t1, t2, t3, t4. Здесь важно отличать, что t1, t4 - это время согласно часам в Ethernet1 устройстве, а t2 и t3 это время по часам в устройстве Ethernet2. Т.е. прибавляя к t2 и t3 значение Offset, мы переводим это время во время устройства Ethernet1.

(Здесь можно найти аналогию в разнице во времени между Москвой и Лондоном, например. Когда в Лондоне время по Гринфичу, то в Москве оно +3 часа. Таким образом, Ethernet1 это Московское время и t1, t4 - это время по Москве, а Ethernet2 и t2, t3 - это время по Гринцичу. Применяя Offset = +3, мы переводим время из Гринвича в Московское.)

Чтобы согласовать время, какое-то одно из устройств в сети должно стать ведущим, а все остальные должны стать ведомыми и подстроить свои часы под время мастера. Устройство, которое будет раздавать время в домене называется GrandMaster. С некоторой периодичностью, устройства, претендующие на должность GrandMaster, рассылают сообщения ANNOUNCE, в котором указывают параметры своих внутренних часов - приоритет, точность хода времени и прочее. То устройство, у которого самые "лучшие" часы выигрывает и становится GrandMaster-ом. Выбор главных часов называется BMCA (Best Master Clock Algorithm)

Периодичность сообщений Announce составляет порядка 1сек, но в различных профилях это время может быть разным. (Профиль - это набор настроек протокола PTP. Например, есть профиль IEEE Std 802.1AS, который называется еще gPTP.)

Параметры в сообщении ANNOUNCE, которые сравниваются при BMCA (Best Master Clock Algorithm):

  • Priority1 - приоритет, настраиваемый пользователем для выбора конкретных часов в ручном режиме. Меньшее значение более приоритетное, диапазон: 0..255.
  • clockClass - класс часов по TAI (большая таблица Table 5 в стандарте IEC_61588. Значение 248 - Default, 6 - время от GPS получаемое по PTP).
  • clockAccuracy - Атрибут, определяющий ожидаемую точность часов, если данные часы будут мастером. (enum: 25нс, 100нс, 250нс…)
  • offsetScaledLogVariance - Атрибут, определяющий стабильность хода часов. Основан на теории дисперсии Аллана. Берется логарифм по основанию 2 от дисперсии, затем умножается на 256 и добавляется 0х8000. Итоговое число приводится в uint16_t.
  • Priority2 - пользовательский атрибут, для выбора конкретных часов из устройств с равным Priority1.
  • clockIdentity - Идентификатор часов, основан на MAC адресе устройства.

Итак, на нашей картинке, устройством которое раздает время является Ethernet1, а Ethernet2 должен подстроить свои часы на значение Offset. Но судя по картинке, Ethernet2 знает только времена t2 (rx_mess1) и t3 (tx_mess2). Времена t1 (tx_mess1) и t4 (rx_mess2) фиксируются в устройстве Ethernet1. Поэтому только двумя сообщениями mess1 и mess2 для синхронизации не обойтись, необходимы дополнительные сообщения, чтобы вернуть t1 и t4 в ведомое устройство Ethernet2. Только тогда Ethernet2 сможет рассчитать Offset по выведенным формулам и скорректировать свои часы.

Сообщения PTP

Сообщения PTP делатся на два типа:

Event Messages (Сообщения событий):

  • Sync - генерирует захват времен t1 (onSync_TX) и t2 (onSync_RX), режимы E2E и P2P.
  • Delay_Req - генерирует захват времен t3 (onDelayReq_TX) и t4 (onDelayReq_RX), режим E2E.
  • Pdelay_Req - генерирует захват времен t1 (onPDelayReq_TX) и t2 (onPDelayReq_RX), режим P2P
  • Pdelay_Resp - генерирует захват времен t3 (onPDelayResp_TX) и t4 (onPDelayResp_RX), режим P2P.

Это сообщения, при передаче и приеме которых, захватываются с высокой точностью времена t1, t2, t3, t4. Есть два режима синхронизации End-To-End (E2E) и Peer-To-Peer (P2P), у каждого режима свои сообщения Delay, но об этом чуть позже.

General Messages (Обычные сообщения ):

  • Follow_Up - передает точное время t1 (onSync_TX) в ведомое устройство, используется только в TwoStep режиме.
  • Delay_Resp - передает точное время t4 (onDelayReq_RX) в ведомое устройство, режим E2E.
  • Pdelay_Resp_Follow_Up - передает точное время t3 (onPdelayResp_TX) в ведомое устройство, режим P2P.
  • Announce - BMCA
  • Management - для настройки и управления
  • Signaling - используются для операций протокола безопасности

Эти сообщения не требуют захвата времени, они лишь передают необходимую информацию, время их отправки / приема не важно и не влияет на синхронизацию.

В протоколе РТР есть служебные сообщения - MANAGEMENT, SIGNALING. Они не используются непосредственно для синхронизации времени, они нужны для управления и настройки устройств в домене PTP. Сообщение ANNOUNCE, как уже было сказано, реализует алгоритм выбора главных часов BMCA (Best Master Clock Algorithm).

Режим End-To-End

В данном режиме все ведомые устройства обмениваются сообщениями непосредственно с мастером, который раздает время. Это может быть GrandMaster или BoundaryClock, о котором чуть ниже. На примере двух устройств обмен сообщениями выглядит следующим образом:

Синхронизация в режиме E2E, TwoStep:

  • SYNC: Мастер-часы посылают фрейм SYNC с периодичностью, которая задана в используемом профиле. В профиле 802.1AS это 8 раз в секунду, в профиле PowerProfile - 1 раз в секунду. Основные передаваемые параметры здесь:
    • originTimestamp - время отправки сообщения. Здесь надо передать время t1, но оно будет известно лишь в момент прохождения фреймом блока PHY. Только поддерживающие PTP OneStep режим блоки PHY умеют вставить время t1 в данное поле "на лету". В данном случае, для передачи t1 используется последующее сообщение FollowUp. Такой режим называется TwoStep.
    • seqID - SequenceID, это индекс отправляемых фреймов SYNC
    • flags0 - флаг TWO_STEP, говорит ведомому о том, что PHY мастера не умеет "на лету" заменять поле originTimestamp в процессе отправки SYNC. Поэтому время t1 будет передано в сообщении FollowUp.
    • logMessInterval - мастер говорит ведомому с какой периодичностью будет посылать SYNC, чтобы ведомый мог использовать этот период в алгоритмах подстройки времени, например, в PID алгоритме. Значение является степенью двойки, 2logMessInterval. Так, если logSyncInterval = 0, то 2logSyncInterval = 1, т.е. один SYNC в секунду.
  • FOLLOW_UP: Это сообщение используется чтобы передать ведомому точное время отправления фрейма SYNC.
    • preciseOriginTimestamp - в этом параметре посылается время t1, т.е. точное время отправки фрейма SYNC.
    • seqID - значение из фрейма SYNC. По этому значению ведомый проверяет относится ли полученный FollowUp фрейм к тому фрейму Sync, что он принял и для которого запомнил время t2.
  • DELAY_REQ: После получения фрейма SYNC ведомый должен как можно быстрее послать сообщение DELAY_REQ. Момент отправки данного сообщения дает время t3. На данной картинке ведомый один, но в общем случае мастер передает SYNC на все устройства в сети. И если каждый из устройств ответит ему сообщением DELAY_REQ, то мастер может не успеть обработать такое большое количество запросов. Поэтому ведомый может синхронизироваться не на каждый SYNC и отсюда у сообщений DELAY_REQ и DELAY_RESP свой отдельный счетчик seqID, обозначен на картинке индексом m. Периодичность DELAY_REQ должна быть выбрана:
    • от 1 DELAY_REQ на 1 сообщение SYNC при logMinDelayReqInterval = logSyncInterval
    • до 1 DELAY_REQ на 32 сообщений SYNC при logMinDelayReqInterval = logSyncInterval + 5
    • (Параметр периода сообщений задается как степень двойки, т.е. 25 = 32)
  • DELAY_RESP: Зафиксировав время приема фрейма DelayReq, мастер возвращает это веремя t4 в параметре receiveTimestamp ответного фрейма DELAY_RESP. В поле seqID используется значение из входящего фрейма, чтобы ведомый понял на какой фрейм получит ответ. Если индекс seqID не совпадет, то ведомый поймет, что мастер ответил на просроченный запрос и данный цикл синхронизации провален. Если же seqID совпал и ведомый получил все необходимые для рассчета времена t1, t2, t3, t4, то он может рассчитать разницу во времени, выполнить какие-либо усредняющие фильтрации и применить Offset к своим часам.

Необходимость постоянной синхронизации связана с тем, что как бы ни были точны часы в различных устройствах Ethernet, за интервал между SYNC набегает некоторое рассогласование во времени. Поэтому кроме периодической синхронизации времени устройства PTP реализуют

  • аппаратные средства для корректировки хода времени - ускорение / замедление хода часов
  • или рассчитывают коррекцию времени локальных часов в часы мастера по какому-либо аппроксимирующему алгоритму.

В микросхеме 1923KX028 заложены аппаратные возможности корректировки хода часов.

Синхронизация в режиме E2E, OneStep:

Синхронизация в режиме OneStep отличается лишь тем, что нет сообщения FollowUp. Такая синхронизация возможна лишь тогда, когда PHY умеет аппаратно на лету изменять поле originTimestamp сообщения SYNC, вставляя туда текущее время, как время отправки t1. Технически это может быть не сам PHY, а некоторая аппаратная реализация на стыке блоков PHY-MAC, т.к. timestamp рекомендуется захватывать в момент приема/передачи заголовка фрейма, т.е. сразу после преамбулы.

Timestamp - это значение времени в данный момент. В PTP timestamp состоит из 48-битного поля секунд и 32-битного поля наносекунд:

typedef __PACKED_STRUCT {
	uint16_t            seconds_msb;
	uint32_t            seconds_lsb;
	uint32_t            nanoseconds;
} ptp_timestamp_t;

Данное время отсчитывается от эпохи (Epoch), которую надо выбрать для домена:

  • TAI: 1 Января 1970 00:00:00
  • UTC: 31 Декабря 1969 23:59:51.999918

Фрейм PTP может передаваться либо на уровне L2 или внутри UDP фрейма. Поэтому PHY должен еще поменять необходимые значения CRC. (Если правильно понял, то для UDP введено специальное поле после фрейма PTP, которое изменяется вслед за timestamp и correction так, чтобы значение CRC фрейма UDP сохранилось. Но это требует подтверждения…) Это все повествование к тому, что реализация OneStep режима достаточно кропотливая задача, поэтому стандарт предоставляет возможность передать времена отправки SYNC c помощью сообщения FOLLOW_UP.

При частоте 100Mbps один бит передается за 10нс, байт за 80нс. В случае работы фрейма на уровне L2, заголовок PTP лежит сразу за заголовком фрейма L2, который состояит из MAC_Dest[6], MAC_Src[6], FrameType[2]. Получается, что после захвата timestamp передатчик доходит до заголовка PTP после передачи 14 байт, что составляет 14 * 80нс = 1120нс = 1,12мкс.

В микросхеме 1923KX028 заложена аппаратная возможность вставки времени отправления в сообщение SYNC для всех поддерживаемых скоростей обмена - 10Mbps / 100Mbps / 1Gbps.

Задержка распространения в коммутаторе, режим E2E

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

Суть работы таких коммутаторов заключается в том, чтобы вносить в проходящие сквозь них фреймы, время (ResidenceTime), затраченное на ретрансляцию через данный коммутатор. Общее время ретрансляции накапливается в поле Сorrection заголовка фрейма PTP. Рассмотрим это на следующем рисунке:

В коммутаторе 1923КХ028 16 портов, но для упрощения картинки взаимодействие показано на трех портах.

  • SYNC - Коммутатор, принимая фрейм SYNC пересылает его на все остальные свои порты. При этом сохраняются значения времени, когда фрейм SYNC был принят t_rx1 и когда передан на каждый из портов t_tx2, t_tx3. Разница между этими временами дает ResidenceTime - время на ретрансляцию фрейма (rt21 и rt31). Иными словами это время на которое фрейм задержался в коммутаторе.
  • FOLLOW_UP - В данном фрейме мастер часы передают в поле preciseOriginTimestamp точное время отправки фрейма SYNC (t1). Коммутатор транслирует этот фрейм так-же на все свои остальные порты, но меняет поле Correction фрейма для каждого порта. К значению этого поля прибавляется ResidenceTime фрейма SYNC для данного порта. Таким образом, каждый из ведомых абонентов Ethernet_B и Ethernet_C получает:
    • t1_SyncTx - время посылки мастером фрейма SYNC, общее для абонентов
    • t2_SyncRx_B / t2_SyncRx_C - время приема SYNC, свое для каждого абонента
    • SyncCorr_B / SyncCorr_C - время, на которое фрейм SYNC задерживался на ретрансляцию проходя через коммутаторы, (один или несколько коммутаторов).

Если теперь из разности t2 и t1 вычесть коррекцию, то мы получим время, которое фрейм SYNC шел только по кабелю. Т.е. это LinkDelay из предыдущей картинки. Получается, что вычитая коррекцию, мы сводим случай с коммутаторами к простейшему варианту, где взаимодействуют напрямую два устройства. Иными словами, наличие коммутатора теперь "прозрачно" для абонентов. Когда коммутатор работает в таком режиме, то он называется TransparencyClock - прозрачные часы.

  • DELAY_REQ - Каждое из ведомых часов отвечает своим фреймом DELAY_REQ.
    • Коммутатор при этом фиксирует времена приема и выдачи каждого фрейма. Как и с фреймом SYNC, эти времена используются для вычисления ResidenceTime (rt21 и rt31).
    • Каждое устройство РТР имеет свой уникальный идентификатор, который передается в заголовке каждого фрейма в поле portIdent. ПО коммутатора должно запомнить из какого порта пришел фрейм с определенным portIdent. Потому что, когда начнут приходить ответные фреймы DELAY_RESP, то надо понимать куда какой фрейм отправить. Иначе придется кидать каждый DELAY_RESP в каждый порт, а это при большом количестве портов и коммутаторов в связке создаст лавину никому не нужных пакетов. Пакеты РТР отправляются с мильтикастовыми МАС и IPV4/IPV6 адресами, что исключает возможность использовать их для маршрутизации.
  • DELAY_RESP - Мастер часы отвечают на каждый DELAY_REQ фреймом DELAY_RESP. Здесь, аналогично ранее рассмотренному, возвращаются времена приема DELAY_REQ t4_B, t4_C и значение seqID из принятого фрейма.
    • В фрейме DELAY_RESP есть дополнительное поле requestingPortIdentity, сюда записывается portIdent из принятого фрейма DELAY_REQ. Т.е. это адресат, кому предназначен ответ DELAY_RESP. Коммутатор, принимая DELAY_RESP находит в ранее сохраненной таблице в каком порту находится requestingPortIdentity. Именно в этот порт и будет переслан данный фрейм DELAY_RESP.
    • Поле Correction при выходе из мастер-часов нулевое. Коммутатор добавляет в это поле значение ResidenceTime от ретрансляции соответствующего фрейма DELAY_REQ.
    • Таким образом, каждый из ведомых абонентов Ethernet_B и Ethernet_C имеет:
      • t3_ReqTx_B / t3_ReqTx_C - время отправки ведомым фрейма DELAY_REQ, свое для каждого абонента
      • t4_ReqRx_B / t4_ReqRx_C - время приема мастером DELAY_REQ, свое для каждого абонента
      • ReqCorr_B / ReqCorr_C - суммарное время, на которое фрейм DELAY_REQ задерживался на ретрансляцию проходя через коммутаторы.

Т.е. логика учета времени ретрансляции для SYNC и DELAY_REQ одинакова. Итоговая формула в общем случае учитывает поле коррекции. Если коммутаторов по дороге не встретилось, то коррекция нулевая и формула вырождается к простейшему виду для двух абонентов.

Поле Correction является 64-разряным числом (uint64_t), значение получается умножением наносекунд на 216. Пример из стандарта на PTP: Если residenceTime = 2.5ns, то 2.5 * 216 = 163840 = 0x28000. Младшие 16-бит составляют субнаносекунды, и на сколько я понял, чаще всего они не используются. При ретрансляции через 1923КХ028 данные 16 бит используются в служебных целях, чтобы объяснить EМАС блоку как правильно обновить поле коррекции. Но об этом позже.

Поскольку Ethernet фреймы передаются старшим байтом вперед Big-Endgian, а ядро Cortex использует Little-Endian адресацию, то при заполнении полей фрейма необходимо делать реверсию байт (если эти поля состоят больше чем из одного байта). В библиотеке MDR_PackV6 для этого есть функции REV_BYTES16, REV_BYTES32, REV_BYTES64. Для REV_BYTES16, REV_BYTES32 используется специальные инструкции для ядра, а REV_BYTES64 реализован через два REV_BYTES32.

  #define REV_BYTES32(x)  __REV(x)
  #define REV_BYTES16(x)  __REVSH(x)

  ptpFrame.header.correction = REV_BYTES64(residenceTime_ns << 16);

В OneStep режиме синхронизация представлена на следующем рисунке:

Здесь, Ethernet_A вставляет таймштамп отправки фрейма SYNC в поле originTimestamp прямо на лету. А коммутатор так-же на лету высчитывает время ResidenceTime фрейма SYNC и добавляет его к полю коррекции транслируемого фрейма. В результате надобность в фрейме FOLLOW_UP отпадает, все необходимые данные каждый из ведомых получает сразу при приеме фрейма SYNC.

Типы PTP устройств

Стандарт предлагает следующие типы устройств PTP:

  • TransparentClock - это коммутатор в рассмотренном выше режиме работы, когда коммутатор просто пропускает сквозь себя сообщения между мастером и ведомыми устройствами. По картинке видно, что на один фрейм SYNC возвращается запрос DELAY_REQ от каждого ведомого и на каждый запрос мастеру необходимо ответить фреймом DELAY_RESP. Микросхема коммутатора 1923KX028 имеет 16 портов, и если на каждом висит по абоненту, то придет 15-ть DELAY_REQ. Если же на одном из портов абонентом окажется еще один коммутатор, то придет много сообщений и от этого коммутатора. В итоге на мастер часы ложится большая нарузка, с которой он может и не справится.
  • BoundaryClock - Поэтому есть выход в том, чтобы коммутатор имел свои собственные часы, которые бы он синхронизовал с вышестоящим мастером (parentClock), а всем своим абонентам он раздавал бы уже свое внутреннее время. Такое устройство называется BoundaryClock, что означает "граничные часы". Причем эти часы могут получать время от мастера в одном режиме работы, а раздавать ведомым в другом режиме работы (E2E / P2P / One-Two step). Т.е. это еще своего рода конвертор режимов работы PTP, т.к. позволяет разные части сети PTP настроить по разному. Недостаток применения BoundaryClock заключается в том, что накапливается некоторое рассогласование по времени между гранд-мастером и часами подключенными через несколько BoundaryClock.
  • OrdinaryClock - это обычное Ethernet устройство, поддерживающее протокол PTP. В нем есть таймер отсчитывающий свое время или другой источник времени, например сигнал от GPS или атомных часов. Если такое устройство выигрывает алгоритм выбора мастера BMSA, то оно становится GrandMaster-ом и раздает свое время всем остальным устройствам в сети. Если устройство проигрывает выборы, то оно подстраивает свои часы под часы мастера.
  • Management - это устройство для мониторинга и конфигурирования сети. (Судя по всему. Пока не было возможности познакомиться с ним поближе. В management сообщениях есть действия - GET, SET, RESPONCE, COMMAND, ACKNOWLEDGE. Т.е. они позволяют устанавливать и получать всякие параметры, отрабатывать запросы - ответы.)

Режим Peer-To-Peer, P2P

Ранее рассмотренный режим End-To-End подразумевает то, что каждое ведомое устройство взаимодействует непосредственно с источником времени - GrandMaster или BoundaryClock. Все сообщения проходят весь путь, как-бы от "конца-до-конца", "источник времени" - "конечный абонент". При этом TransparencyClock пропускают сквозь себя весь трафик.

Есть другой подход к синхронизации, который называется Peer-To-Peer. Он отличается тем, что сообщения DELAY_REQ доходят только до ближайшего устройства в сети, а не до источника времени. Это ближайшее устройство отвечает сообщением DELAY_RESR. Получается, что каждое устройство по паре DELAY_REQ - DELAY_RESR может рассчитать время прохождения фрейма до ближайшего абонента - meanPathDelay. Только сообщения здесь другие, с префиксом от Peer - PDELAY_REQ и PDELAY_RESP. Сигналы SYNC и FOLLOW_UP проходят весь путь, так-же как и раньше, только в поле коррекции вставляется помимо ResidenceTime еще и время прохождения сигнала между абонентами.

Рассмотрим вариант синхронизации Peer-To-Peer на примере:

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

  • SYNC и FOLLOW_UP - Мастер-часы посылают фрейм синхронизации и FOLLOW_UP абсолютно так-же, как это было в режиме End-To-End. "Прозрачные часы" при ретрансляции SYNC высчитывывают ResidenceTime, который аналогично режиму E2E добавляется в поле коррекции проходящего следом фрейма FOLLOW_UP. Но помимо этого в поле correction суммируется так-же время на прохождение фрейма от мастер-часов Ethernet_A, до Port_1 коммутатора. В этом и состоит отличие режима Peer-To-Peer. Каждый абонент знает время доставки пакета от ближайшего соседа по проводам. Точнее от ближайшего соседа в сторону мастер-часов. Это время, называемое meanPathDelay, определяется каждым соседом с помощью сообщений PDELAY_REQ и PDELAY_RESP, которые запускаются со своей периодичностью. К приходу фрейма SYNC время meanPathDelay уже должно быть рассчитано и судя по названию даже с усреднением.
  • PDELAY_REQ - Это аналог сообщения DELAY_REQ в E2E режиме, оно периодически посылается каждыми ведомым абонентом.
    • В данном случае Port1 микросхемы 1923KX028 является ведомым по отношению к Ethernet_A, поэтому он посылает запрос PDelayReq и фиксирует время выхода данного фрейма - T1. Port1 стал "ведомым" когда получил самый первый входящий фрейм Sync, остальные порты 1923KX028 остались "мастерами" для подключенных к ним абонентов.
    • Со стороны Ethernet_B, который так-же является ведомым, так-же периодически посылаются запросы PDELAY_REQ к ближайшему соседу. На картинке это Port2 микросхемы 1923KX028. (Взаимосвязи во времени отправки мужду ведомыми нет, каждый инициирует свой запрос сам по себе.)
  • PDELAY_RESP - каждый сосед (Ethernet_A и Port2), получающий PDELAY_REQ должен зафиксировать время прихода этого фрейма Т2 и передать это время в ответном фрейме PDELAY_RESP. Время приема ответного фрейма PDELAY_RESP T4 фиксируется абонентом инициировавшим запрос, в данном случае, это Port1 и Ethernet_B.
  • PDELAY_RESP_FOLLOW_UP - Данный фрейм используется в TwoStep режиме, чтобы передать время отправления фрейма PDELAY_RESP, T3. Тогда у ведомого, что инициировал запрос PDELAY_REQ, будут в наличии все данные для рассчета задержки прохождения фрейма между двумя устройствами (по кабелю) - Т1, Т2, Т3, Т4. В формуле на картинке указаны так-же значения Correction которые могут так-же передаваться в упомянутых выше фреймах, но не указаны на схеме. В этих полях может передаваться коррекция несимметричности передачи фрейма при посылке разными абонентами. На схеме подразумевается что несимметричность нулевая, поэтому поля Correction не указаны.

Случай, указанный на рисунке, не единственный вариант измерения времени meanPathDelay. В документации предлагаются такие варианты:

  • PDELAY_RESP возвращает разницу мужду T2 и T3 (OneStep режим, PDELAY_RESP_FOLLOW_UP - не используется). Это возможно, т.к. (T2 - T1) + (T4 - T3) = (T4 - T1) + (T2 - T3). Получается, что можно сразу передать необходимую разницу времен, вместо передачи двух значений. Для данного варианта PHY должен на лету взять таймштамп отправки, вычесть его из таймштампа приема PDELAY_REQ и записать результат в PDELAY_RESP.requestReceiptTimestamp передаваемого фрейма. 1923КХ028 такую штуку проворачивать не умеет.
  • PDELAY_RESP_FOLLOW_UP возвращает разницу T2 и T3. Здесь логика рассчета такая-же, но требований "OnFly" к аппаратуре нет.
  • PDELAY_RESP возвращает T2, а PDELAY_RESP_FOLLOW_UP возвращает T3. Это тот вариант, что представлен на картинке.

Преимуществом P2P режима считается то, что генерится меньший трафик и достигается большая точность, поскольку учитывается даже время прохождения фрейма по кабелю. Так-же считается, что в случае удаления (отказа) одного из узлов, восстановление системы произойдет быстрее, т.к. каждый нод знает локальную задержку до соседа, и там где связь не нарушена, эта задержка никак не изменится.

Стоит отметить, что на L2 уровне используются разные multicast МАС_destination адреса для фреймов:

  • 01-80-C2-00-00-0E : Для сообщений PDelay_Req, PDelay_Resp, Pdelay_Resp_Follow_up. Сообщения с таким МАС адресом не должны ретранслироваться дальше по сети!
  • 01-1B-19-00-00-00 : Для всех остальных сообщений. Ретранслируются дальше по сети.
  • 88F7 : значение поля EtherType.

Адреса destination IPv4 и IPv6:

  • 224.0.0.107 : IPv4 destination address для сообщений PDelay_Req, PDelay_Resp, Pdelay_Resp_Follow_up
  • 224.0.1.129 : IPv4 destination address для всех остальных
  • FF02::6B : IPv6 destination address для сообщений PDelay_Req, PDelay_Resp, Pdelay_Resp_Follow_up
  • FF0x::181 :IPv6 destination address для всех остальных

Порты для UDP (User Datagram Protocol) header:

  • 319 : destination port number для сообщений Sync, Delay_Req, Pdelay_Req, Pdelay_Resp
  • 320 : destination port number для всех остальных

Поддержка PTP в 1923КХ028

Для аппаратной поддержки OneStep режима PTP в микросхеме Ethernet коммутатора 1923КХ028 реализовано две возможности:

  • Вставка на лету таймтампа отправки в фрейм SYNC.
  • Изменение на лету поля коррекции при отправке фрейма SYNC

SYNC One-Step Timestamp

  // EMAC Blocks Addresses
  #define AXI_EMAC1_BASE_ADDR                 0x660000
  #define AXI_EMAC2_BASE_ADDR                 0x670000
  #define AXI_EMAC3_BASE_ADDR                 0x680000
  ....

  // Register Address
  #define AXI_EMAC_NETCTRL		      0x0000 
  
    //1588 One Step Sync Mode. Write 1 to enable. 
    // Replace timestamp field in the 1588 header for TX Sync Frames with current TSU timer value
    #define AXI_EMAC_NETCTRL_OSSMODE_EN_Pos       24
    #define AXI_EMAC_NETCTRL_OSSMODE_EN_Msk       0x01000000UL
    
    // 1588 One Step Correction Field Update. 
    // Set this bit high to enable updating the correction field of PTP 1588 version 2 sync frames 
    // by adding current TSU timer value.
    #define AXI_EMAC_NETCTRL_OSS_CORRECTION_Pos   27  
    #define AXI_EMAC_NETCTRL_OSS_CORRECTION_Msk	  0x08000000UL

В 1923КХ028 имеется встроенный таймер TSU, который считает время в секундах и наносекундах. В каждом из 16-ти блоков EMAC поддержка PTP включается отдельно. Если в регистре AXI_EMAC_NETCTRL блока МАС выставить 24-й бит, то при отправке фрейма SYNC, в поле фрейма originTimestamp будет выведено текущее время TSU. Данный режим использется, когда 1923КХ028 реализует OrdinaryClock в состоянии GrandMaster или BoundaryClock в OneStep режиме. Т.е. это те режимы, в которых 1923КХ028 раздает остальным свое локальное время от TSU.

Структура фрейма SYNC:

  typedef __PACKED_STRUCT {
    uint8_t             mess_transp;
    uint8_t             version;    
    uint16_t            messLen;    
    uint8_t             domainNum;
    uint8_t             _reserved1;
    uint8_t             flags[2];
    uint64_t            correction;
    uint32_t            _reserved2;
    ptp_port_ident_t    srcPortId;
    uint16_t            seqId;
    uint8_t             control;
    int8_t              logMessInterval;
  } ptp_header_t;

  typedef __PACKED_STRUCT  {
    ptp_header_t      hdr;
    ptp_timestamp_t   originTimestamp;
  } ptp_msg_sync_t;

SYNC One-Step Correction

Когда коммутатор реализует TransparencyClock в OneStep режиме, то он должен обновлять поле коррекции фрейма SYNC. Включается эта опция битом 27 того же регистра AXI_EMAC_NETCTRL в каждом из блоков ЕМАС. Коммутатор 1923КХ028 обновляет коррекцию следующим образом:

  • EMAC принимает входящий фрейм и распознает его как SYNC. В первом служебном заголовке из 48 байт сохраняется время приема фрейма - секунды и наносекунды таймера TSU.
  • Чтобы фрейм попал на обработку в HOST необходимо чтобы в таблице МАС был прописан МАС адрес фреймов РТР и действие для него - PUNT.
  • Управляющее ПО на HOST-е получает захваченный фрейм SYNC. Для того чтобы EMAC исправил поле Correction при отправке, данное поле необходимо подготовить:
    • Очистить сладшие 16 бит - здесь младшие 16 бит, ответственные за субнано секунды, используются в служебных целях для указания МАС блоку как правильно обновить поле коррекции при выдаче в линию.
    • Если значение равно максимальному 0xFFFFFFFFFFFF0000, то выставить бит 15 и ничего больше не делать. Иначе:
      • В бит 8 записать младший бит секунд из таймшатма приема фрейма.
      • Вычесть из значения коррекции наносекунды таймшампа приема фрейма. Если результат получился отрицательным, то выставить бит 14.
      • Записать в коррекцию абсолютное значение разницы из предыдущего шага.

Теперь, когда EMAC будет отправлять данный фрейм, то он выведет в поле коррекции сумму между временем на тот момент (таймштампом отправки) и полем correction. А т.к. мы записали correction = inp_correction - timeRx, то сложение со времени отправки даст время residenceTime:

out_correction = inp_correction - timeRx + timeTx = inp_correction + residenceTime

Таким образом в поле Correction происходит добавление ResidenceTime.

Timestamps в режиме TwoStep

Аппаратной поддержки для прочих event-сообщений, кроме SYNC, в 1923КХ028 нет. Но для ПО управления достаточно получать время приема сообщения и время выдачи, чтобы обеспечить передачу всех необходимых для синхронизации значений. Когда нет поддержки "на лету" используется режим TwoStep. В общем случае получение хостом таймштампов приема и отправки происходяит следующим образом:

  • EMAC принимает фрейм и распознает, что это фрейм PTP. В 48-байтном служебном заголовке сохраняется таймштамп приема фрейма.
  • Чтобы фрейм попал на обработку в HOST необходимо чтобы в таблице МАС был прописан МАС адрес фреймов РТР и действие для него - PUNT. В случае P2P режима необходимо прописать оба МАС адреса, потому что SYNC идет с Forwarding MAC, а Peer фреймы с NoForwarding МАС.
  • Управляющее ПО на HOST-е получает захваченный фрейм. Далее согласно рисунку для TransparencyClock запоминается время приема фрейма, а сам фрейм рассылается на прочие порты коммутатора - один или несколько, в зависимости от того, какой это фрейм.
  • Каждый EMAC, отправивший фрейм, сформирует свой служебный фрейм длиной 0x18 байт с информацией об отправке. В нем будет сохранен таймштамп выдачи фрейма в линию. Этот служебный фрейм не посылается автоматоматически на Хост, т.к. это не входной фрейм из сети. В этом фрейме нет и МАС адреса назначения, поэтому запись в МАС таблице в данном случае не сработает. Чтобы ПО могло получить этот служебный фрейм необходимо включить SNOOPING, что в переводе означает шпионить. В классификаторе есть два набора регистров, куда нужно прописать МАС адреса РТР протокола, тогда фреймы-репорты будут приходить на Хост и ПО сможет обработать таймштампы отправки так, как это было представлено на рисунках выше. (Разница между приходом фрейма и его посылкой дает ResidenceTime, которое передается затем в поле коррекции проходящих следом фреймов.)
  //- csr_snoop_spl_mcast_addr1_lsb 31:0 R/W SPL multicast address1 lsb 32 bits [31:0]
  //- csr_snoop_spl_mcast_addr1_msb 15:0 R/W SPL multicast address1 msb remaining 16 bits
  #define AXI_CLASS_SNOOP_SPL_MCAST_ADDR1_LSB 0x368 
  #define AXI_CLASS_SNOOP_SPL_MCAST_ADDR1_MSB 0x36C 

  //- csr_snoop_spl_mcast_addr2_lsb 31:0 R/W SPL multicast address2 lsb 32 bits [31:0]
  //- csr_snoop_spl_mcast_addr2_msb 15:0 R/W SPL multicast address2 msb remaining 16 bits    
  #define AXI_CLASS_SNOOP_SPL_MCAST_ADDR2_LSB 0x370 
  #define AXI_CLASS_SNOOP_SPL_MCAST_ADDR2_MSB 0x374 

В памяти LMEM коммутатора, принятые фреймы выглядит следующим образом (на примере SYNC по сравнению с обычным фреймом):

Видно, что в PTP фрейме заполнен таймштамп приема. (Подробнее о работе 1923КХ028 и фреймах в памяти можно прочитать в Спецификация 1923KX028 - Описание принципа работы)

На следующей картинке показано как выглядит фрейм SYNC в памяти 1986ВЕ3Т при посылке в Port2 (EMAC2) 1923КХ028. Чуть ниже показано как принятый от 1986ВЕ3Т фрейм расположен в памяти LMEM 1923КХ028. Этот фрейм коммутатор пересылает в Port3 (EMAC3), отчего получает фрейм-репорт об отправке, так-же показанный в памяти LMEM:

На что обратить внимание:

  • Длина сообщения исходящего из 1986ВE3Т составляет 0х3А байт. Длина 0х4С в принятом сообщении складывается из исходной длины 0х3А и длины заголовка из 4-х 32-разрядных слов (16 байт). В этом заголовке сохраняется информация о приеме:
    • откуда пришел фрейм, в данном случае EMAC2 (0x01 в 0x02000160)
    • причина захвата на Хост
    • таймштамп приема фрейма и бит валидности таймштампа
  • Информация в LMEM хранится в виде 32-разрядных слов, вероятно поэтому 0х3А (inpFrameLen) + 16 (hdrLen) округляется до 32-разрядного целого - до 0х4С.
  • Длина фрейма-репорта составляет 24 байта (0х18). Из полезной информации здесь удалось распознать:
    • таймштамп отправки
    • номер порта, который послал фрейм. В данном случае это EMAC3
    • (значение 0х81000001 присутствует во всех репортах об отправке. Что это конкретно не известно, но поскольку это значение не меняется, то данное значение используется в драйвере PTP как маркер репорта, наряду с длиной в 0х18 байт.)
  • таймштампы приема и отправки формируются по времени TSU. При запуске программы секунды TSU были выставлены в значение 0x33333333, чтобы было заметно, где в LMEM находится таймштамп. Порядок байт должен быть BigEndian, т.е. получается, что секунды приема фрейма это 0х33333422, а секунды отправки 0х33333446. Разница получается 0х24, это 36 секунда. Это и есть время residenceTime при пересылке данного фрейма. Такое большое значение обусловлено тем, что шла пошаговая отладка между захватом фрейма и получением фрейма репорта (с вычитыванием памяти LMEM). В рабочем режиме пересылка фрейма занимает наносекунды. В OneStep режиме типовое значение это 0xED0F8, т.е. 971000 наносекунд. Приблизительно такое значение приходит в поле коррекции при пересылке между портами, когда управляющее ПО работает по SPI. А оно не только вычитывает фрейм по SPI для обработки, но и записывает обратно фрейм для инжекции в порт назначения. Если ПО работает на Хосте по ePCI, то задержка должна получиться значительно ниже.

TSU - источник времени в 1923КХ028

TSU - это встроенный 102-битный таймер, который есть в каждом блоке EMAC. Биты этого тамера:

  • 48 старших бит считают секунды
  • 30 средних бит считают наносекунды
  • 24 младщих быит считают суб-наносекунды

54 младших бита сбрасываются в 0 когда достичают значения секунды.

Согласно спецификации, необходимо настроить только один TSU в EMAC1, а для остальных 15-ти EMAC выставить бит использования внешнего источника времени - бит 23 регистра AXI_EMAC_NETCTRL. Это логично, потому что, важно чтобы ход времени был одинаков для всех портов.

  // EMAC Reg Address
  #define AXI_EMAC_NETCTRL		      0x0000

  // External TSU timer enable
  #define AXI_EMAC_NETCTRL_TSU_EN_Pos       23
  #define AXI_EMAC_NETCTRL_TSU_EN_Msk	    0x00800000UL

Для настройки TSU необходимо прописать количество тиков таймера на 1нс в регистр AXI_EMAC_TSU_TIM_INC. Необходимое значение указано в спецификации. При этом, в регистре AXI_EMAC_CTRL должен быть выставлен нормальный режим хода часов - это режим когда на каждый тик тактовой частоты TSU ходят на один шаг AXI_EMAC_TSU_TIM_INC. Частота тактирования TSU составляет 50МГц.

  // Reg address
  #define AXI_EMAC_TSU_TIM_INC    0x01DC
  // 1ns step value
  #define CFG_TSU_INC_PER_1NS     0x14

  // TSU Init
  MDR_KX028_WriteAXI(AXI_EMAC1_BASE_ADDR + AXI_EMAC_TSU_TIM_INC, CFG_TSU_INC_PER_1NS);
  
  // TSU inc mode
  #define AXI_EMAC_CTRL          0x08A0 
    #define AXI_EMAC_CTRL_TSU_MODE_NORMAL         0x0030UL  - CFG_TSU_INC_PER_1NS на один тик частоты
    #define AXI_EMAC_CTRL_TSU_MODE_ALTER          0x0010UL  - некоторый шаг на несколько тиков
    #define AXI_EMAC_CTRL_TSU_MODE_ADJUST         0x0020UL  - подстраиваемый режим, +- 1нс от внешних сигналов
    #define AXI_EMAC_CTRL_TSU_MODE_NORMAL_STROBE  0x0000UL  - при strobe = 1 секунды растут на каждый тик частоты,
                                                              наносекунды сбрасываются в 0, иначе NORMAL режим

Для коррекции хода времени есть регистр, который задает количество суб-наносекунд на которые увеличивается таймер на каждый тактовый тик совместно с шагом CFG_TSU_INC_PER_1NS.

  // TSU CLOCK_TO_NSEC (RW):
  // sub-ns value by which the 1588 timer will be incremented each clock cycle. 
  #define AXI_EMAC_TSU_INC_SUB_NSEC     0x1BC
    #define AXI_EMAC_TSU_INC_SUB_NS_INCR_Pos      0
    #define AXI_EMAC_TSU_INC_SUB_NS_INCR_Msk      0x0000FFFFUL
    #define AXI_EMAC_TSU_INC_SUB_NS_INCR_LSB_Pos  24
    #define AXI_EMAC_TSU_INC_SUB_NS_INCR_LSB_Msk  0xFF000000UL 

Значение TSU, соответствующее событиям захвата PTP, сохраняется в поля таймштампа фреймов. Но значение времени можно считать напрямую, как и записать. Для этого есть регистры:

  // TSU TIME (RW):
  #define AXI_EMAC_TSU_TIM_MSB_SEC      0x1C0
  #define AXI_EMAC_TSU_TIM_SEC          0x1D0
  #define AXI_EMAC_TSU_TIM_NSEC         0x1D4

48-битное значение секунд инкрементируется, когда счетчик наносекунд досчитывает до значения 1-й секунды. Запись старших 16-бит секунд (MSB) применяется в регистр при записи младших 32- бит, это сделано чтобы обновление времени происходило одномоментно.

Для подстройки текущего времени есть специальный регистр. Запись в этот регистр увеличивает или уменьшает значение наносекунд в таймере TSU. Сюда необходимо записать Offset полученный из формул описанных выше, если необходимо синхронизовать время TSU c GrandMaster-ом:

  // TSU TIME CORRECTION (WO)
  #define AXI_EMAC_TSU_TIM_ADJUST       0x1D8
    #define AXI_EMAC_TSU_TIM_ADJ_INC_Pos       0
    #define AXI_EMAC_TSU_TIM_ADJ_INC_Msk       0x0x3FFFFFFFUL
    #define AXI_EMAC_TSU_TIM_ADJ_NEG_Pos       31
    #define AXI_EMAC_TSU_TIM_ADJ_NEG_Msk       0x80000000UL

В EMAC блоке, за сохранение таймштампа в BufferDescriptors (BD), которые потом передаются в LMEM и далее захватываются на Хост отвечают следующие регистры:

  //  TIMESTAMP INSERTION CTRL
  #define AXI_EMAC_TX_BD_CTRL           0x4CC
  #define AXI_EMAC_RX_BD_CTRL           0x4D0
    // TX/RX Descriptor Timestamp Insertion mode, 
    //  00: TS insertion disable, (byDefault)
    //  01: TS inserted for PTP Event Frames only, 
    //  10: TS inserted for All PTP Frames only, 
    //  11: TS insertion for All Frames "
    #define AXI_EMAC_TX_BD_CTRL_TS_DIS          0x0000UL
    #define AXI_EMAC_TX_BD_CTRL_TS_PTP_EVENTS   0x0010UL
    #define AXI_EMAC_TX_BD_CTRL_TS_PTP_FRAMES   0x0020UL
    #define AXI_EMAC_TX_BD_CTRL_TS_ALL_FRAMES   0x0030UL

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

В TSU можно задать значение времени, при достижении которого будет выставлен флаг события в регистре прерываний AXI_EMAC_ISR. Но чтобы зафиксировать данное "прерывание" необходимо периодически опрашивать данный регистр и смотреть значение бита 29:

  //  TSU COMPARE TIME VALUE
  #define AXI_EMAC_TSU_NSEC_CMP         0x0DC
  #define AXI_EMAC_TSU_SEC_CMP          0x0E0
  #define AXI_EMAC_TSU_MSB_SEC_CMP      0x0E4
  
  // Interrupt Status
  #define AXI_EMAC_ISR		        0x0024 
    #define AXI_EMAC_ISR_EvntTSU_Pos        29
    #define AXI_EMAC_ISR_EvntTSU_Msk        0x20000000UL  

Так-же есть регистры из которых можно считать значения последних захваченных таймштампов:

  // TSU CAPTURED PTP EVENT TIMES (RO):
  //  PTP Event timestamps
  #define AXI_EMAC_TSU_PTP_TX_MSB_SEC   0x0E8
  #define AXI_EMAC_TSU_PTP_TX_SEC       0x1E0
  #define AXI_EMAC_TSU_PTP_TX_NSEC      0x1E4
  #define AXI_EMAC_TSU_PTP_RX_MSB_SEC   0x0EC
  #define AXI_EMAC_TSU_PTP_RX_SEC       0x1E8
  #define AXI_EMAC_TSU_PTP_RX_NSEC      0x1EC
  
  //  PTP Peer Timestamps
  #define AXI_EMAC_TSU_PEER_TX_MSB_SEC  0x0F0
  #define AXI_EMAC_TSU_PEER_TX_SEC      0x1F0
  #define AXI_EMAC_TSU_PEER_TX_NSEC     0x1F4      
  #define AXI_EMAC_TSU_PEER_RX_MSB_SEC  0x0F4
  #define AXI_EMAC_TSU_PEER_RX_SEC      0x1F8
  #define AXI_EMAC_TSU_PEER_RX_NSEC     0x1FC

Реализация в ПО

Для проверки обмена PTP фреймами было реализовано несколько проектов. Когда появится возможность, проекты будут представлены на GitHub.

PTP_FrameTester

Целью данного проекта было научиться формировать фреймы PTP и чтобы Wireshark их распознавал. Проект может быть запущен на 1986ВЕ1Т или 1986ВЕ3Т. В нем по кнопке RIGHT меняется тип фрейма, так перебираются все типы фреймов PTP. А по кнопке UP посылается фрейм текущего типа в РС.

Файл ptp_messages_upd.pcapng находится внутри проекта, что позволяет посмотреть как выглядит фрейм "изнутри".

PTP_TimeSync

Целью данного проекта было согласовать времена между двумя контроллерами с Ethernet. Для этого по кнопке UP на одной из плат запускался цикл обмена сообщениями.

В качестве индикатора согласования времен использовались аппаратные выводы ШИМ, которые выводили импульсы на внешние пины подключенные к осциллографу. Рассогласование между фронтов показывает текущую разницу во времени. В качестве источника времени ипользовалась пара таймеров в составном режиме. Один таймер считал тики CPU_CLOCK, до достижения секунды, а второй таймер считал события CNT == ARR первого таймера, т.е. считал секунды. Переключение ШИМ происходит по этому же событию младшего таймера CNT == ARR, т.е. раз в секунду. При согласовании времен, переключения ШИМ должны стать синхронными. По кнопке DOWN значение младшего таймера сбрасывается в 0, разрущая синхронизацию по времени и импульсы расходятся. Нажатие на UP выравнивает фронты ШИМ.

В зависимости от ключей сборки доступны варианты синхронизации:

  • E2E - OneStep
  • E2E - TwoStep
  • P2P - OneStep
  • P2P - TwoStep

Проект запускался на связках:

  • 1986ВЕ1Т - 1986ВЕ3Т
  • 1986ВЕ3Т сам с собой, т.к. в нем два блока Ethernet. Такой вариант проще в отладке, потому что все времена отправки-приема доступны в одном отладчике.

ptp_ve3_lo.jpg

При запуске внутри одного 1986ВЕ3Т "часы" обоиx абонентов (пары таймеров) работают от одной частоты, поэтому после синхронизации времени сигналы ШИМ продолжают идти согласованно. При синхронизации по кнопке UP времена согласуются с разбросом в ~15нс, при рабочей частоте 1986ВЕ3Т 80МГц (период 12,5нс)

ptp_ve3_sync1_lo.jpgptp_ve3_sync2_lo.jpg

При синхронизации в паре 1986ВЕ1Т - 1986ВЕ3Т синхронизация выставляла часы аналогично, но фронты тут-же разбегались, т.к. источники тактовых частоты различны и поэтому разбежка увеличивается со временем. В данном случае действительно нужен периодичный обмен циклами синхронизации, как это и предусмотрено протоколом, а так-же коррекция хода самих часов.

В 1986ВЕ1Т/3Т нет возможности коррекции хода "часов" (таймеров), а учитывать погрешность математически достаточно трудозатратно. Данные работы не проводились.

Режима работы PTP выбирается в файлах:

  // main.c - E2E or P2P
  #define  USE_PTP_MODE_E2E     0
  
  // MD_PTP_Config.h - TwoStep or OneStep
  #define CFG_PTP_TWO_STEP      1  

Поддержка в прошивке MARS1

Позднее, "в разрыв" между двумя блоками Ethernet платы 1986ВЕ3Т была включена плата MARS1 на базе коммутатора 1923KX028. А в прошивке была реализована поддержка режима TransparencyClock.

Программная поддержка PTP была включена в паки MDR_Pack_v6 и MDR_1923KX028:

  • PTP_Frames - функции формирования фреймов PTP для проектов PTP_FrameTester и PTP_TimeSync.
  • PTP_Handlers - функции реализующие циклы синхронизации для проекта PTP_TimeSync.
  • 1923КХ028_Mode2_PTP - поддержка циклов синхронизации времени с проектом PTP_TimeSync.

Режим работы PTP выбирается в файлах:

  // MDR_1923KX028_Config.h - Enable or Disable
  #define CFG_PTP_ENABLE        1
  
  // KX028_PTP_Config.h  - E2E or P2P
  #define  USE_PTP_MODE_E2E     1

Настройки того, какие порты 1923KX028 обслуживать в режиме PTP задается в этом-же файле KX028_PTP_Config.h. В режиме PTP_TranspClock параметр isModeP2P не используется, поэтому нет необходимости задавать CFG_PTP_TWO_STEP:

//  Количество портов в режиме PTP
#define  PTP_PORT_COUNT       2
//  Тип устройства
#define  PTP_DEVICE           PTP_TranspClock
//  Настройки портов, которые будут работать в режиме PTP
#define  CFG_PTP_PORT_LIST_INIT  {  \
  .ports[0].emacInd = KX028_EMAC2,  \
  .ports[0].port.portIdent = {.clockIdent = PTP_CLOCK_IDENTITY_DEF, .portNum    = _htons(1)},  \
  .ports[0].port.numDomain = CFG_PTP_DOMAIN_NUMBER,  \
  .ports[1].emacInd = KX028_EMAC7,  \
  .ports[1].port.portIdent = {.clockIdent = PTP_CLOCK_IDENTITY_DEF, .portNum    = _htons(2)},  \
  .ports[1].port.numDomain = CFG_PTP_DOMAIN_NUMBER,  \
  .role = PTP_DEVICE,           \
  .isModeP2P = !USE_PTP_MODE_E2E,               \
  .isTwoStepMode = CFG_PTP_TWO_STEP,            \
  .usePeerFollowUp = true \
}

В плате MARS1 только EMAC2 подключен к внешнему PHY, этот порт подключался к ETH1 1986ВЕ3Т. ETH2 1986ВЕ3Т подключался к:

  • 5600ВВ3Т который подключен к EMAC3 по MII.
  • медному SFP модулю, который подключен к EMAC7 по SGMII.

При использовании 5600ВВ3Т удалось синхронизовать фронты ШИМ с погрешностью +-400нс. А при использовании SFP разброс фронтов был порядка +-100нс. Для чистоты эксперимента, хотелось бы, чтобы оба EMAC были использованы с одинаковым подключением напрямую к PHY. Но в плате MARS1 такой вариант не возможен, а дополнительные микросхемы в связке (5600ВВ3Т и Marvell управляющий SFP) дают разброс при синхронизации. Т.к. возникает перекос в пути следования фрейма, а при выведении самых первых формул мы полагались на условие что LinkDelay1 равен LinkDelay2. Т.е. время следования фрейма в одну сторону и обратно одинаково. В данном случае это не так, отсюда и возникает разброс. На практике "перекос" LinkDelay1 и LinkDelay2 можно нивелировать выставляя его в поле Correction вместо нуля. Но это требует ручной настройки каждых часов под конкретную сеть.

Типовой разброс PWM при синхронизации через MARS1 в режиме TransparencyClock, используются порты EMAC2 (1986ВЕ1_PHY) - EMAC7 (SFP module):

Предполагается, что с использованием 1923КХ028 напрямую с PHY разбежка в синхронизации будет значительно ниже.

В качестве итога, можно скачать, что в микросхеме 1923КХ028 есть все необходимое для реализации протокола PTP!

prog/ethernet/ptp_basis.txt · Последние изменения: 2021/02/04 14:53 — vasco