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

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


prog:ethernet:test_cl

Тест Ethernet в режиме КЗ для 1986ВЕ1Т, 1986ВЕ3Т, 1986ВЕ8Т.

Тест реализован и прогонялся на следующих ревизиях микроконтроллеров:

  • 1986ВЕ1Т - ревизия 4 и 6.
  • 1986ВЕ3Т - ревизия 2
  • 1986ВЕ8Т - ревизия 4

В данном тесте передаются пакеты с постоянно увеличивающейся длиной. Кроме этого в тесте перебираются все три режима работы с буферами - линейный, автоматический и FIFO. Включен режим КЗ, т.е. данные не уходят в блок PHY. Блок МАС передает то, что сам посылает.

Напомню, что блоки МАС и PHY общаются по интерфейсу MII, этот интерфейс в данном случае не задействован.

Код проекта доступен на gitHub

Проекты для проверки реального соединения микроконтроллеров по кабелю доступны там же 1986ВЕ1Т к 1986ВЕ3Т и 1986ВЕ1Т к 1986ВЕ8Т. Статья будет позже.

После включения питания загорается первый светодиод на демоплате. Это индикация режима работы буферов с которым далее будет запущен Ethernet.

  • LED1 - линейный
  • LED2 - автоматический
  • LED3 - FIFO

Программа ожидает нажатия кнопок, варианты:

  • LEFT (KEY1 для ВЕ8) - сменить режим. Нажатиями выбираем необходимый режим, ориентируясь на LED1 - LED3.
  • UP (KEY2 для ВЕ8) - запуск теста. Будет настроен блок Ethernet и начнется обмен.

Выбранный режим перед запуском сохраняется в регистре BKP_REG0. Этот регистр не сбрасывается при Reset, таким образом, после Reset мы возвращаемся в установленный режим и можем сразу нажать UP для запуска обмена.

При тесте передаются фреймы длиной от FRAME_LEN_MIN до FRAME_LEN_MAX, по REPEAT_FRAME_LEN_COUNT раз для каждой длины.

#define FRAME_LEN_MIN   64
#define FRAME_LEN_MAX   1514

#define REPEAT_FRAME_LEN_COUNT 5

#define LED_FRAME_PERIOD  1000

Передатчик формирует фрейм и отправляет, приемник получает фрейм. Каждая передача и прием считаются, для индикации работы переключаются светодиоды:

  • LED1 - через LED_FRAME_PERIOD отправленных фреймов
  • LED2 - через LED_FRAME_PERIOD принятых фреймов

Передатчик в первые 4 байта Payload записывает индекс фрейма. В последние два байта я записываю импровизированный индикатор конца данных - байт 0xFF и байт текущей длины фрейма. Это позволяет при анализе данных в памяти видеть где закончились данные и начинается статус передачи (в памяти передатчика) или слово CRC (в памяти приемника).

Приемник получает фрейм и проверяет следующие параметры:

  • Длина фрейма - при ошибке загорается LED3.
  • Индекс фрейма - при ошибке загорается LED4.
  • Данные фрейма - при ошибке загорается LED5.
  • Равенство указателей (R_Head == R_Tail) и (X_Head == X_Teail), ошибка на LED6

При правильном исполнении теста должны мигать только светодиоды LED1 и LED2, показывая что фреймы посылаются и принимаются. Если загораются другие светодиоды, значит, произошла соответствующая ошибка. Стереть текущие ошибки (погасить светодиоды) можно нажав на кнопку:

  • RIGHT (KEY3 для 1986ВЕ8Т)
  • Кнопки LEFT и UP (KEY1, KEY2) в тесте не участвуют, они нужны только при запуске.

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

Результат в 1986ВЕ1Т

В 6-й ревизии тест отрабатывает успешно для всех длин фреймов и режимов - линейный, автоматически и FIFO.

В 4-й ревизии тест отрабатывает успешно для всех длин фреймов только в линейном режиме работы буферов. Приведу пример, как выглядят данные в буферах при передаче и приеме одного фрейма.

По картинке видно, что при успешной передаче регистры X_Head/X_Tail и R_Head/R_Tail имеют согласованные (равные) значения. Это говорит о правильной работе передатчика и приемника.

В остальных режимах - автоматическом и FIFO, сказалась ошибка из errata:

"0021 При работе буферов Ethernet контроллера в автоматическом режиме и режиме FIFO ядро не успевает записывать данные в буферы при работе на частоте менее 144МГц. …"

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

В автоматическом и FIFO режиме, при записи данных в буфер, указатель X_Tail инкрементируется автоматически при записи каждого слова. Соответственно, при первой же записи слова в буфер Ethernet, регистр X_Tail обгоняет X_Head - передатчик обнаруживает запрос на передачу и начинает выдавать данные. И тут борются как бы два потока - наша функция записывает данные в буфер, а передатчик считывает данные и передает. Вот здесь и сказывается ошибка из errata. Получается, что для 1986ВЕ1Т при частоте ядра меньше 144МГц, передатчик считает данные быстрее, чем мы успеем их все записать.

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

Предполагаю, что буферы памяти находятся в самом периферийном устройстве, поэтому ядру до них "дальше", чем самому блоку МАС, поэтому МАС с буферами работает быстрее.

Регистры X_Head и R_Tail доступны только для чтения и сбрасываются автоматически при присвоении регистра ETH_Delimeter в функции ETH_DeInit(). Регистры X_Tail и R_Head доступны на запись и чтение в линейном режиме.

Поскольку на отладочной плате стоит кварц на 8МГц, то максимальным умножением PLL на x16 удается поднять частоту ядра только до 128МГц. На такой частоте тест выполнить не удалось совсем. Перепаять резонатор возможности пока нет. Если возможность появится статья будет обновлена.

Автоматический режим

Обмен ломается на первом же фрейме.

На картинке память буферов передатчика и приемника. Видно, что передатчик догнал X_Tail и послал первую часть фрейма - в приемнике вертикальная черная линия с цифрой 1. Передатчик дописал поле CRC, его я выделил жирной зеленой линией.

Потом в буфер передатчика были дописаны ядром оставшиеся данные фрейма и передатчик выслал оставшиеся данные - черная линия с цифрой 2. Эти данные затерли начало данных предыдущего фрейма в приемнике, поскольку регистр R_Tail так и остался указывать на начало буфера.

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

Режим FIFO

В этом режиме успевает передаться и приняться успешно несколько фреймов. Возможно, это объясняется тем, что передача данных производится с использованием DMA. Запись данных исполняется быстрее, чем это делалось ядром в автоматическом режиме, но в итоге обмен все равно ломается.

Наблюдается рассогласование регистров X_Head/X_Tail и R_Head/R_Tail. Видимо причина та же - блок MAC не успевает работать с буферами при отправке / приеме.

Разница ревизий 4 и 6

Обнаружилось, что в 6-й ревизии 1986ВЕ1Т нет аппаратной защиты регистров R_Head и X_Tail от записи неправильных значений в линейном режиме.

Так, например, если в 6-й ревизии вызвать X_Tail = 0, то регистр действительно станет равен 0. В 4-й же ревизии при записи X_Tail = 0, X_Tail станет равен Delimeter, как и должно быть.

К сожалению, текущий код SPL работает с этими указателями некорректно - возникает ситуация, когда вызывается X_Tail = 0 и R_Head = 0х1000, при Delimeter = 0х1000. Чего делать нельзя. В 4-й ревизии эта некорректная работа нивелировалась аппаратной защитой регистров, и значения получались правильными, поэтому все работало.

Если при переходе на 6-ю ревизию 1986ВЕ1Т Ваш рабочий проект перестал работать - проверьте работу с указателями R_Head и X_Tail.

Необходимые исправления внесены в наш репозиторий на gitHUB, функции ETH_SendFrame() и ETH_ReceivedFrame() - линейный режим.

Результат в 1986ВЕ3Т

Проблема блока Ethernet в 1986ВЕ3Т проявилась в том, что указатели передатчика иногда неправильно обрабатывают конец буфера. Такая ситуация возникает эпизодически, вот картинка, показывающая состояние регистров и памяти:

Сложилось состояние, передатчик должен был записать статус передачи в последнюю ячейку буфера Ethernet, но по каким-то причинам не смог это сделать. Кроме этого, отсылаемые данные он должен был закончить посылкой CRC, но CRC тоже не послал. Такой затык происходит время от времени, при отладке это состояние отрабатывалось правильно через раз. Первый раз статус записывался в последнюю ячейку и пакет принимался верно, а на следующем проходе - статус не записывался и пакет ломался. Если перед сбойной отправкой пакета намеренно в отладчике передвинуть регистр X_Tail на одну позицию (X_Tail = 0х1004), то статус запишется в ячейку 0х1000, и CRC придет верно. Это говорит о том, что проблема именно с записью статуса отправки в последнюю ячейку буфера Ethernet, если X_Tail находится в следующей (начальной) ячейке буфера. Если следом лежит еще один фрейм (X_Tail не указывает на начало буфера), то проблем не будет!

Обработать проблему программным сдвигом X_Tail на +4 не удалось, потому что застревание на краю буфера возникает не всегда и, видимо, не через раз, как показалось при отладке нескольких циклов. При посылке следующего фрейма указатели что передатчика, что приемника пойдут в разнобой, и тест зажигает все светодиоды.

Помогло выравнивать регистры R_Head и R_Tail, после вторичной посылки фрейма.

uint32_t CheckBuffPTR(void)
{
  uint32_t ErrCnt = 0;
  
  if (ETHERNET_X->ETH_R_Head != ETHERNET_X->ETH_R_Tail)
  {
#ifdef USE_VE3_BUG_PTR_FIX
    ETHERNET_X->ETH_R_Head = ETHERNET_X->ETH_R_Tail;
#endif    
    ErrCnt++;
  }
  if (ETHERNET_X->ETH_X_Head != ETHERNET_X->ETH_X_Tail)
  {
    //    ETHERNET_X->ETH_X_Tail = ETHERNET_X->ETH_X_Head;  // Перекрывается обработкой ETH_R_Head 
    ErrCnt++;
  }
  
  return !ErrCnt;
}

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

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

Без выравнивания указателей тест ломается очень быстро, и дальнейший обмен не происходит - тест "зависает" в ожидании приема пакета. То есть передатчик фрейм отправил, но приемник данных не видит - указатели R_Head и R_Tail равны. По картинке видно, что до первого сбоя было передано 0х0386 фреймов (902 в десятеричной системе).

Линейный режим

В линейном режиме с выравниванием указателей блок работает успешно со всеми длинами фреймов. Периодически, из-за описанной выше проблемы, фрейм приходит битый, но ошибка стирается кнопкой, и видно, что обмен в целом продолжается.

  #define FRAME_LEN_MAX   1514

  //  Выравнивание указателей позволяет правильно принимать следующий пакет! 
  //  Для линейного и FIFO, мешает в Auto 
  #define USE_VE3_BUG_PTR_FIX

Режим FIFO

В режиме FIFO с выравниванием указателей передаются фреймы длиной до порядка 850 байт. При передаче фреймов большей длины обмен ломается - тест "зависает" в ожидании приема пакета.

  #define FRAME_LEN_MAX   850 //1514

  //  Выравнивание указателей позволяет правильно принимать следующий пакет! 
  //  Для линейного и FIFO, мешает в Auto 
  #define USE_VE3_BUG_PTR_FIX

Автоматический режим

В автоматическом режиме выравнивание указателей USE_VE3_BUG_PTR_FIX мешает, обмен "зависает" в ожидании приема пакета.

В режиме без выравнивания обмен данными происходит, но высвечиваются все ошибки. До первой ошибки передается 180 фреймов (0хB4). От длины фрейма зависимость не выявлена. Состояние первого сбоя показано на картинке:

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

Результат в 1986ВЕ8Т

Тест проходит успешно во всех режимах - линейный, автоматический и FIFO. Но для смены режима буферов следует перезапускать МК в режиме отладки, поскольку Reset в данном случае запускает программу с 0-го адреса.

1986ВЕ8Т ошибка с BigEndian

Важно, чтобы блок настраивался в LittleEndian в передатчике и приемнике.

  // Блок Работает
  ETH_InitStruct->ETH_Receiver_BE    = ETH_RECEIVER_BE_LITTLE_ENDIAN;
  ETH_InitStruct->ETH_Transmitter_BE = ETH_TRANSMITTER_BE_LITTLE_ENDIAN;
  
  // Блок НЕ Работает!
  //ETH_InitStruct->ETH_Receiver_BE    = ETH_RECEIVER_BE_BIG_ENDIAN;
  //ETH_InitStruct->ETH_Transmitter_BE = ETH_TRANSMITTER_BE_BIG_ENDIAN;  

При использовании BigEndian поле CRC в памяти приемника начинает затирать данные Payload весьма необычным способом, в зависимости от четности длины фрейма:

  • кратный 4-м фрейм передается успешно
  • кратный + 1 - CRC затирает последний байт, поле CRC разрывается 4-мы нулевыми байтами.
  • кратный + 2 - CRC затирает последние 2 байта, поле CRC разрывается 4-мы нулевыми байтами.
  • кратный + 3 - CRC затирает 3-й байт с конца, 2 последних байта верные.

Это проще показать, чем объяснить. На картинке сверху память передатчика, снизу память приемника. Последние два байта помечены серой рамкой, зеленой помечено поле CRC. Видно как поле CRC затирает данные.

Пробовал управляющее слово передатчика писать в BigEndian, но в такой вариации поведение еще хуже. X_Head передатчика не изменяется, и фрейм всегда передается с начального адреса (текущего X_Head). С каждым разом будет передаваться фрейм все большего размера (при записи новых фреймов на передачу, X_Tail увеличивается). Это говорит о том, что контрольное слово передатчика (количество данных на отправку) должно всегда писаться в LittleEndian.

Для сравнения, вот как выглядит правильная передача, режим LittleEndian.

Смена режима буферов в ходе программы

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

Но в 1986ВЕ3Т и 1986ВЕ8Т такой режим реализовать не удалось:

  • В 1986ВЕ8Т указатели R_Tail и X_Head не сбрасываются ни при сбросе блока, ни при присвоении регистра Dilimiter. Зато почему-то сбрасываются X_Tail и R_Head при записи в регистр G_CfgL. Выровнять после этого R_Tail и X_Head я не могу, потому что они Read-only, а при возврате значений X_Tail и R_Head в согласованное состояние в регистре статуса выставляются флаги, что буферы полны и полуполны.
  • в 1986ВЕ3Т не получилось, потому что режимы, в принципе, не работают корректно.

Резюме по режиму КЗ

Возможно руки кривые и в коде есть ошибки, но на текущий момент по выполненному тесту заключение такое:

  • 1986ВЕ1
    • Ревизия 6 - Работать можно в любом режиме с фреймами любого размера.
    • Ревизия 4 - Без частоты 144МГц, работать можно только в линейном режиме. При 144МГц требуется проверка.
  • 1986ВЕ3 (ревизия 2)
    • Есть аппаратная проблема работы с указателями передатчика на конце буфера данных.
    • В линейном режиме требуется выравнивание указателей приемника при рассогласовании. Пакеты периодически посылаются битые.
    • В автоматическом режиме добиться работоспособности не удалось. Причина не установлена.
    • В режиме FIFO требуется выравнивание указателей приемника при рассогласовании. Длина фреймов не должна превышать 850 байт. Пакеты периодически посылаются битые.
  • 1986ВЕ8Т (ревизия 4)
    • Работать можно в любом режиме с фреймами любого размера. Не использовать режим BigEndian!

В следующем тесте мы подключим микроконтроллеры попарно и проверим, как работают блоки Ethernet в живую.

prog/ethernet/test_cl.txt · Последние изменения: 2018/03/23 18:49 — katya