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

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


prog:ethernet:notes

Начальные сведения о Ethernet

Основные понятия о работе Ethernet доступны в Википедии. Здесь собраны некоторые сведения, которые необходимо знать для работы с Ethernet в микроконтроллерах компании Миландр.

Рекомендую ознакомиться с данными Technical Notes, ссылки в формате pdf:

В данных документах детально расписана работа Ethernet и ознакомление с ними снимает множество вопросов о назначении тех или иных бит в регистрах блоков MAC и PHY, из которых, в свою очередь, и состоит блок Ethernet.

Тактирование 25МГц

Для работы блока Ethernet PHY нужна высокоточная частота тактирования 25МГц. Как правило, для этого используется отдельный генератор HSE2, запускаемый от внешнего резонатора на 25МГц. Дело в том, что внутренняя PLL имеет недопустимый по стандарту Ethernet джиттер, поэтому ее нельзя использовать для получения точной частоты. По этой причине, со второй ревизии микроконтроллера производителем реализован отдельный генератор HSE2.

Второй вариант - использовать вместо резонатора внешний генератор на 25МГц, подключенный ко входу OSC_IN. В данном случае в HSE необходимо включить режим ByPass, при котором внутренний генератор HSE не работает, а лишь пропускает входную частоту. Таким образом, на выходе HSE будут необходимые стабильные 25МГц для PHY. Но на вход PLL можно подавать частоту от 2МГц до 16МГц, поэтому необходимо включить делитель на 2. Теперь на выходе мультиплексора CPU_C1 получится частота 25МГц/2, что уже вписывается в условие < 16МГц.

Резонатор 25МГц на вход HSE (вместо генератора) использовать нельзя, потому что генератор HSE формирует выходную частоту в диапазоне 2-16МГц. А поскольку генератор не умеет делить/умножать частоту, а только делает из синусоидального сигнала прямоугольные импульсы, то это означает, что на вход HSE можно подключать резонатор с теми же частотами 2-16МГц. Для тактирования PHY и ядра от HSE можно использовать только внешний генератор!

На самом деле частота 25 МГц - это частота, на которой передаются данные между блоками MAC и PHY в режиме 100 Мбит/c. Данные передаются по интерфейсу MII.

(В 1986ВЕ8Т блок PHY отличается от остальных - Особенности блока PHY в 1986ВЕ8Т)

Буферы приема и передачи

Для обработки пакетов Ethernet выделена память размером 8Кбайт. Это отдельная память в блоке периферии, а не часть ОЗУ ядра.

Регистр Delimeter делит эту память на два буфера - буфер входных данных и буфер выходных данных. В зависимости от того, чего ожидается больше - входных или выходных данных, можно поделить общую память в необходимой пропорции. Например, если в задаче пользователя выходных данных генерируется много больше чем входных, то имеет смысл больше памяти выделить для передатчика. Т.е. выставить регистр Delimeter не в середину (0х1000), а в меньшее значение, например Delimeter = 0х800.

Буферы являются кольцевыми, поэтому для считывания и записи данных в каждый буфер выделено по два регистра Head и Tail, свои для приемника и передатчика. Head - указывает на начало действительных данных, Tail - на конец действительных данных. Соответственно регистры R_Head и R_Tail могут принимать значения [0 .. Delimeter-1], а регистры X_Head и X_Tail - [Delimeter .. 0x2000]. Данные регистры необходимы для "ручного" манипулирования данными в буферах, в так называемом линейном режиме.

Для наглядности данные в буферах выглядят так. Картинка соответствует передаче 6-ти фреймов с увеличивающейся длиной в 1986ВЕ8Т в режиме КЗ, т.е. блок МАС принимает то, что сам посылает. Блок Phy в обмене не участвует. В Payload в первых 4-х байтах передается индекс фрейма. В последние два байта записан импровизированный маркер длины пакета, по нему удобно отслеживать конец данных.

Режимы работы буферов

Всего реализовано три режима работы буферов - Линейный, автоматический и FIFO. В линейном режиме регистры R_Tail и X_Head изменяются аппаратно при приеме и передаче данных с линии, программист же должен модифицировать регистры R_Head и X_Tail. R_Head - при чтении из буфера полученных данных, X_Tail - при записи в буфер пакетов на отправку.

В автоматическом режиме происходит все тоже самое, только модифицировать регистры R_Head и X_Tail не надо. Они изменяются автоматически при чтении слова входных данных и при записи слова данных на отправку соответственно.

В режиме FIFO считывание входных данных происходит через чтение адреса 0х0000, отправка же через запись в адрес 0х0004. В SPL для ускорения работы с данными в этом режиме используется DMA. Регистры R_Head и X_Tail здесь не участвуют.

Следует отметить, что в случае, когда есть необходимость пропускать считывание из буфера входного пакета целиком, следует использовать линейный режим работы буферов. Только в нем есть возможность переместить указатель R_Head сразу за конец текущего пакета.

В SPL реализованы функции, которые инкапсулируют в себе работу с буферами во всех режимах. Изучение их реализации поможет в большем понимании принципов работы с буферами.

void ETH_SendFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_OutputBuffer, uint32_t BufLen);
uint32_t ETH_ReceivedFrame(MDR_ETHERNET_TypeDef * ETHERNETx, uint32_t * ptr_InputBuffer);

Отправка пакета

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

  1. Первым 32-х битным словом необходимо записать "Поле управления передачей пакета". В этом поле указывается длина пакета в байтах. Передатчик, когда считывает это слово, понимает, сколько последующих байт относится к данному пакету и должно быть передано. Данное слово должно располагаться по выровненному 32-битному адресу.
  2. После указания длины пакета в буфер записывается сам пакет обозначенной длины. В линейном режиме после записи пакета необходимо выставить указатель X_Tail на адрес, следующий за статусным словом (пункт 3).
  3. При передаче каждого слова передатчик перемещает указатель X_Head. После того, как передатчик осуществит посылку пакета в следующий выровненный 32-битный адрес, он запишет статус передачи пакета. Выставляется флаг прерывания от передатчика.

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

Прием пакета

Приемник принимает пакет с линии и записывает его в буфер.

  1. Первым 32-битным выровненным словом записывается "Поле состояния приема пакета". Это поле содержит биты статуса приема и длину пакета в байтах.
  2. Затем записываются данные самого пакета.

Со стороны приемопередатчика работа с буфером и регистрами всегда одинакова. Разница в режимах (линейный, автоматический и FIFO) сказывается только при обращении к буферу из ядра.

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

Поэтому, неравенство R_Tail и R_Head говорит о том, что в буфере есть данные для считывания и пользовательская программа может с ними работать.

Подключение

Для подключения друг к другу двух микроконтроллеров необходимо использовать кабель Crossover. В этом кабеле пины выходного сигнала с одной стороны идут к входным пинам с другой стороны.

При подключении к PC можно использовать любой кабель, поскольку сетевые карточки как правило поддерживают Auto-MDI(X) режим. При этом выводы на PC автоматически подстроятся на прием или выдачу сигнала.

При подключении двух устройств происходит процедура автосогласования (Autonegotiation) скорости обмена и дуплекса. Микроконтроллеры Миландр поддерживают скорости обмена 10Мбит/сек и 100Мбит/сек (Fast Ethernet). В режиме полудуплекса используется один кабель и обмен происходит то в одну сторону, то в другую. Микроконтроллер, то передает, то принимает данные. В полнодуплексном режиме прием и передача идут одновременно, каждый по своему кабелю. При автосогласовании выбирается режим, который поддерживают оба устройства и который обеспечивает максимальную скорость обмена. Приоритеты выбора режимов такие:

  1. 100BASE-TX Full Duplex
  2. 100BASE-TX Half Duplex
  3. 10BASE-T Full Duplex
  4. 10BASE-T Half Duplex

Подробнее о том, как происходит согласование описано здесь Интуит: Auto-Negotiation.

Процедура Autonegotiation не является обязательной и ее можно отключить. В таком случае режим обмена должен быть выбран одинаковым в обоих подключенных устройствах. Делается это в регистре PHY_Control. Так же, в блоке PHY есть регистры, значения которых влияют на процесс выбора скорости и дуплекса. Доступ к этим расширенным регистрам осуществляется через интерфейс MDIO.

Интерфейс MDIO

Контроллер Ethernet состоит из двух частей блока MAC и блока PHY. Обмен данными между этими блоками происходит по интерфейсу MII. Настройка же блока PHY производится по интерфейсу MDIO. Подробнее об этих интерфейсах на Вики: MII и Wiki: MDIO.

По стандарту, интерфейс MDIO позволяет адресовать до 31-го PHY устройства. Это обусловлено тем, что в обмене используется поле PHY_ADDR, который имеет ширину 5 бит. 0-й адрес является широковещательным, а остальные 31 - это адреса конкретного блока PHY. Соответственно для работы с блоком PHY необходимо в регистре PHY_Control задать поле PHYADDR[15..11]. И затем именно этот адрес необходимо указывать в транзакциях по MDIO. В библиотеке SPL в функции ETH_StructInit() поле PHYADDR задается равным 0x1C, но значение может быть любым другим (ненулевым).

Для работы с MDIO используются два регистра

  • MDIO_CTRL - регистр управления
  • MDIO_DATA - регистр данных для чтения и записи регистров PHY.

Именно в регистре MDIO_CTRL указывается PHY_ADDR для выбора блока PHY, с которым будет происходить обмен данными через регистр MDIO_DATA. В этом же регистре MDIO_CTRL указывается адрес внутреннего регистра PHY, текущая операция - чтение или запись, а так же частота обмена и прочее. Подробно биты расписаны в спецификации. В SPL работа с MDIO реализована в функциях:

uint32_t ETH_WritePHYRegister(MDR_ETHERNET_TypeDef * ETHERNETx, uint16_t PHYAddress, uint16_t PHYReg, uint16_t PHYValue);
uint16_t ETH_ReadPHYRegister(MDR_ETHERNET_TypeDef * ETHERNETx, uint16_t PHYAddress, uint16_t PHYReg);

К примеру, вот как можно выключить подключение на скорости 100Мбит/сек при Autonegotiation. Функция сбрасывает биты 7 и 8 в "Регистре рекомендации автоподстройки (4)". После вызова данной функции МК будет подключаться к PC на скорости 10Мбит/сек.

#define ETH_PHY_ADDR  0x1C   // - адрес указанный в PHY_Control

void PHY_100TX_Disable(void)
{
  volatile uint32_t regValue = ETH_ReadPHYRegister(MDR_ETHERNET1, ETH_PHY_ADDR, 4);
  regValue &= ~(3 << 7);
  ETH_WritePHYRegister(MDR_ETHERNET1, ETH_PHY_ADDR, 4, regValue);
}

В библиотечной (SPL) функции ETH_WritePHYRegister() была ошибка и если регистр у Вас не прописывается, проверьте сбрасывается ли бит OP при записи в ETH_MDIO_CTRL: tmpreg &= ~(1 « ETH_MDIO_CTRL_OP_Pos);

Вот исправленная версия:

uint32_t ETH_WritePHYRegister(MDR_ETHERNET_TypeDef * ETHERNETx, uint16_t PHYAddress, uint16_t PHYReg, uint16_t PHYValue)
{
  uint32_t tmpreg = 0;
  __IO uint32_t timeout = 0;
  /* Check the parameters */
  assert_param(IS_ETH_ALL_PERIPH(ETHERNETx));
  assert_param(IS_ETH_PHY_ADDRESS(PHYAddress));
  assert_param(IS_ETH_PHYReg(PHYReg));

  /* Get the ETHERNET MACMIIAR value */
  tmpreg = ETHERNETx->ETH_MDIO_CTRL;
  /* Keep only the CSR Clock Range CR[2:0] bits value */
  tmpreg &= ~ETH_MDIO_CTRL_DIV_Msk;

  tmpreg &= ~(1 << ETH_MDIO_CTRL_OP_Pos); // !!!-------  Исправление --------!!!
  
  /* Prepare the MII address register value */
  tmpreg |= (uint32_t)(PHYAddress << 8) | (PHYReg << 0) | (0 << ETH_MDIO_CTRL_OP_Pos) |
            (1 << ETH_MDIO_CTRL_RDY_Pos) | (1 << ETH_MDIO_CTRL_PRE_EN_Pos) | (1<<5);
  /* Give the value to the MII data register */
  ETHERNETx->ETH_MDIO_DATA = PHYValue;
  /* Write the result value into the MDIO_CTRL register */
  ETHERNETx->ETH_MDIO_CTRL = tmpreg;
  do{
	timeout++;
	tmpreg = ETHERNETx->ETH_MDIO_CTRL;
  }while(((tmpreg & ETH_MDIO_CTRL_RDY) == 0 ) && (timeout < PHY_READ_TO));

  /* Return ERROR in case of timeout */
  if(timeout == PHY_READ_TO){
    return ((uint16_t)ETH_ERROR);
  }
  /* Return SUCCESS */
  return ((uint16_t)ETH_SUCCESS);
}

Бит G_CFGh.EXT_EN

Бит EXT_EN регистра G_CFGl определен в спецификации как - "Включение режима дополнения коротких пакетов до размера SlotTime полем Extension".

Данный бит выставлен в регистре G_CFGl после Reset и предназначен для борьбы с коллизиями в Half Duplex режиме. О назначении SlotTime можно прочитать здесь.

Эта ссылка лучше Link - "По существу Время канала ST (slot time)- это минимальное время, в течении которого узел обязан вести передачу, занимать канал. Это время соответствует передаче кадра минимального допустимого размера, принятого стандартом Ethernet IEEE 802.3. Время канала связано с максимальным допустимым расстоянием между узлами сети - диаметром коллизионного домена."

При работе в Full Duplex необходимости в данном бите нет. Поэтому для работы в современных сетях, данный бит необходимо сбросить. К тому же, по некоторой информации, некоторые ревизии микроконтроллеров в режиме с EXT_EN работают некорректно. Либо не корректно работает ответная часть подключенная к МК. Определенности по данному вопросу пока нет.

По факту, при EXT_EN = 1 в конец пакета, отправляемого микроконтроллером, приписывается 10 дополнительных байт. Причем в любом случае, меньше ли отправляемый пакет минимального размера в 64 байта или больше.

Особенности блока PHY в 1986ВЕ8Т

Стоит отметить, что встроенный блок PHY в микроконтроллере 1986ВЕ8Т совсем другой и он позволяет работать только на скорости 10 Мбит/c. Для работы на больших частотах к блоку MAC можно подключить внешний PHY.

Чтобы правильно запустить PHY необходимо:

1. Сбросить блок в регистре PHY_CONTROL в 15 бит записать лог 1.

2. Произвести настройку, записав значения в регистры блока.

3. Запустить работу блока, сбросив лог 1 в 15 бите регистра PHY_CONTROL.

(При тактировании блока частотой 80 МГц, необходимо использовать значение поля LINK_PERIOD=0x8).

ИТОГО: Тактировать блок Ethernet PHY микроконтроллеров 1986ВЕ1Т, 1986ВЕ3Т необходимо внешней стабильной частотой 25МГц. Для тактирования PHY в 1986ВЕ8Т необходима внешняя стабильная частота 80МГц.

Внешний PHY в "Электросиле"

На отладочной плате для мк "Электросила" используется микросхема внешнего PHY - LAN8742A, которая подключена по интерфейсу RMII. Чтобы работать с внешним PHY необходимо:

  • Настроить необходимые выводы GPIO в функции RMII.
  • Блок Ethernet необходимо затактировать частотой Eth_Clock = 50МГц, которая необходима для прокачки данных через RMII. (Для работы по MII потребовалась бы частота в 25МГц, потому что линий данных в MII в два раза больше.)
  • Для обращения к регистрам PHY используется MDIO, частота которого не должна превышать 2,5МГц. Для этого частоту Eth_Clock надо поделить делителем DIV в регистре MDIO_CTRL.

Толкование регистров

Согласно п. "30.10 Режим детерминированного времени доставки." пакеты могут передаваться в привязке к отсчетам времени (с периодом BAG при DTRM_EN = 1). Т.е. если передатчик успевает в окно JitterWnd начать передачу, то он ее начинает. Если не успевает - то ожидает следующего отсчета периода BAG. BAG и JitterWnd выражаются в квантах времени, которые задаются из ETH_Clock делителем PSC.

1/TimeStep = ETH_Clock / (PSC + 1), что согласуется с 1мкс для 50МГц из спецификации.

IPG - межпакетный интервал и в соответствии с IEEE802.3 должен составлять 96 битовых интервалов. Описание в https://en.wikipedia.org/wiki/Interpacket_gap и далее по ссылкам есть более детальное описание.

Отличие на уровне МАС - Unicast, Broadcast, Multicast.

Нагрузочное тестирование с БЕРКУТ-ЕТ

При подключении платы 1986ВЕ1Т к Eternet тестеру БЕРКУТ-ЕТ обнаружилось, что при штатной настройке блока не удается получить 100% пропускной способности. Но если уменьшить межпакетный интервал IPG, то можно добиться увеличения показателей. (По стандарту IPG должен составлять 96 битовых интервалов.)

В программе реализован прием фрейма от БЕРКУТа и отправка его назад, соответственно со сменой МАС адресов. (Проект на GitHub под PACK от StartMilandr).

Частота микроконтроллера составляет 128МГц - максимальная для платы с резонатором 8МГц на HSE. Снижение IPG до 87 привело к достижению 100% пропускной способности на пакетах длиной более 256 байт:

berkut_ve1_128mhz_ipg96_87.jpg

Пока это просто информация к размышлению.

Заметки

  • При настройке блока Ethernet на работу в оптическом режиме (100Base-FX) не использовать режимы с Autonegotiation. Выставить конкретный режим работы.
prog/ethernet/notes.txt · Последние изменения: 2020/03/27 12:42 — vasco