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

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


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МГц.

prog/ethernet/notes.txt · Последние изменения: 2019/09/25 09:46 — vasco