Dp83848 ethernet board подключение к stm32

Обновлено: 05.07.2024

Итак, если Вы заинтересовались, читайте далее…

1. Драйвер RNDIS


На этапе написания решалось две задачи: подписать наше устройство и поддержать стандарт RNDIS.
Подпись устройства сводится к составлению верных USB-дескрипторов. Значение VID выбрано 0x0483 (STMicroelectronics), значение PID — 0x0123 (произвольное). Само собой, в коммерческом применении так делать не следует.
Device Descriptor
Offset Field Size Value Description
0 bLength 1 12h
1 bDescriptorType 1 01h Device
2 bcdUSB 2 0200h USB Spec 2.0
4 bDeviceClass 1 02h CDC Control
5 bDeviceSubClass 1 00h
6 bDeviceProtocol 1 00h
7 bMaxPacketSize0 1 40h 64 bytes
8 idVendor 2 0483h SGS Thomson Microelectronics
10 idProduct 2 0123h
12 bcdDevice 2 0001h 0.01
14 iManufacturer 1 01h «Fetisov Sergey»
15 iProduct 1 02h «STM32F4 RNDIS»
16 iSerialNumber 1 03h «00000000123C»
17 bNumConfigurations 1 01h
Configuration Descriptor 1
Offset Field Size Value Description
0 bLength 1 09h
1 bDescriptorType 1 02h Configuration
2 wTotalLength 2 0043h
4 bNumInterfaces 1 02h
5 bConfigurationValue 1 01h
6 iConfiguration 1 00h
7 bmAttributes 1 40h Self Powered
8 bMaxPower 1 01h 2 mA
Interface Descriptor 0/0 CDC Control, 1 Endpoint
Offset Field Size Value Description
0 bLength 1 09h
1 bDescriptorType 1 04h Interface
2 bInterfaceNumber 1 00h
3 bAlternateSetting 1 00h
4 bNumEndpoints 1 01h
5 bInterfaceClass 1 02h CDC Control
6 bInterfaceSubClass 1 02h Abstract Control Model
7 bInterfaceProtocol 1 FFh Vendor-Specific
8 iInterface 1 00h
Header Functional Descriptor
Offset Field Size Value Description
0 bFunctionLength 1 05h
1 bDescriptorType 1 24h CS Interface
2 bDescriptorSubtype 1 00h Header
3 bcdCDC 2 0110h 1.10
Call Management Functional Descriptor
Offset Field Size Value Description
0 bFunctionLength 1 05h
1 bDescriptorType 1 24h CS Interface
2 bDescriptorSubtype 1 01h Call Management
3 bmCapabilities 1 00h
4 bDataInterface 1 01h
Abstract Control Management Functional Descriptor
Offset Field Size Value Description
0 bFunctionLength 1 04h
1 bDescriptorType 1 24h CS Interface
2 bDescriptorSubtype 1 02h Abstract Control Management
3 bmCapabilities 1 00h Requests/notifications not supported
Union Functional Descriptor
Offset Field Size Value Description
0 bFunctionLength 1 05h
1 bDescriptorType 1 24h CS Interface
2 bDescriptorSubtype 1 06h Union
3 bControlInterface 1 00h
4 bSubordinateInterface0 1 01h CDC Data
Endpoint Descriptor 81 1 In, Interrupt, 80 ms
Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 81h 1 In
3 bmAttributes 1 03h Interrupt
4 wMaxPacketSize 2 0008h 8 bytes
6 bInterval 1 50h 80 ms
Interface Descriptor 1/0 CDC Data, 2 Endpoints
Offset Field Size Value Description
0 bLength 1 09h
1 bDescriptorType 1 04h Interface
2 bInterfaceNumber 1 01h
3 bAlternateSetting 1 00h
4 bNumEndpoints 1 02h
5 bInterfaceClass 1 0Ah CDC Data
6 bInterfaceSubClass 1 00h
7 bInterfaceProtocol 1 00h
8 iInterface 1 00h
Endpoint Descriptor 82 2 In, Bulk, 64 bytes
Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 82h 2 In
3 bmAttributes 1 02h Bulk
4 wMaxPacketSize 2 0040h 64 bytes
6 bInterval 1 00h
Endpoint Descriptor 03 3 Out, Bulk, 64 bytes
Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 03h 3 Out
3 bmAttributes 1 02h Bulk
4 wMaxPacketSize 2 0040h 64 bytes
6 bInterval 1 00h

Поддержка стандарта осуществлена в соответствии с документацией.

Также в сети присутствует множество RNDIS-драйверов для других платформ (1, 2, 3), что существенно упростило разработку.
В части обмена драйвер повторяет особенность CDC-класса за исключением того, что передаваемые пакеты оборачиваются служебной информацией. Также существует специальный интерфейс для передачи запросов от usb-хоста с целью настройки устройства или получения его статуса. Детально код драйвера можно изучить в модуле usbd_rndis_core.c.
Минимальная настройка драйвера при встраивании заключается в изменении определений в файле usbd_rndis_core.h.
— MAC-адрес устройства (PERMANENT_HWADDR, STATION_HWADDR)
— Идентификатор производителя (RNDIS_VENDOR)
— Значение MTU (ETH_MTU):


Также в файле usbd_desc.h следует изменить название продукта (USBD_PRODUCT_STRING) и производителя (USBD_MANUFACTURER_STRING).

Процесс установки драйвера в ОС Windows:


1. Пункт меню «обновить драйвер»;
2. Выполнить поиск драйвера;
3. Выбрать драйвер из списка;
4. В списке классов устройств выбрать «Сетевые адаптеры»;
5. В списке производителе выбрать «Microsoft Corporation»;
6. И продукт «Remote NDIS based Internet Sharing Device».

Более подробно процесс установки стандартного RNDIS устройства описан по ссылке.

2. Прикручиваем LwIP


Драйвер RNDIS обеспечивает лишь транспортную функцию для кадров стандарта 802.3 (Ethernet). Очевидно, что поддержку всего многообразия пакетов и стандартов требуется возложить на сетевой стек. В его роли было принято решение использовать популярный стек для встраиваемых систем lwip последней (на текущий момент) версии 1.4.1. Надо отдать должное авторам стека, тот получился весьма просто интегрируемым. При всём при этом, код стека богат полезными комментариями и инструкциями.

Запуск стека под stm32 ограничился включением в процесс сборки конкретного набора исходных файлов и вводом определений в файле lwipopts.h:


Нужно отметить, работа по портированию стека на STM32F4 производилась и раньше фирмой STMicroelectronics (приложение STSW-STM32070).

Запускаем DHCP-сервер


Добавление DHCP-сервера в состав библиотеки связано с необходимостью инициализировать сетевой интерфейс на стороне host-а. По умолчанию, создаваемый при подключении устройства интерфейс настроен на автоматическое получение ip-адреса. Библиотека также успешно работает и при статической адресации, но это является не совсем удобным.

К сожалению, среди поставляемых lwip средств, DHCP-сервер отсутствует.

Однако, это не является существенной проблемой, т.к. в своей минимальной реализации DHCP-сервер весьма минималистичен.

В сети присутствует, пожалуй, единственный пример DHCP-сервера, работающего со стеком lwip. Данный источник оказался весьма полезным для изучения, хоть и не пригодным для встраивания по принципу «as-is» по причине отсутствия возможности конфигурирования и использования socket-api.

Поэтому было принято решение написать DHCP сервер.

И вот его скромные возможности:
— выдача адресов на произвольное время
— резервирование адресов по MAC адресу
— настройка DNS-сервера

Подключение сервера в тестовом проекте:

Запускаем DNS-сервер


Желаемый нами результат работы — отображение web-страницы при вводе в браузере некоторого имени ресурса. Однако, это возможно только при наличии DNS-сервера, который будет «знать» о нашем хосте. Конечно, этот результат доступен, если в адресной строке напрямую ввести ip-адрес: 192.168.7.1. Такой адрес имеет по умолчанию наше устройство. Однако, будем более искусны и запустим DNS-сервер.

В отличии от DHCP, текущая реализация DNS-сервера ещё «тоньше». На данный момент она позволяет обработать только стандартные DNS-запросы на одну запись.

Запуск сервера в проекте:

Долго и безрезультатно пришлось бороться с запуском известного сервера из пакета lwip «contrib-1.4.1». До сих пор для меня остаётся загадкой таинственный HardFault, возникающий на, казалось бы, ровном месте. Были проверены все настройки, адреса чтения и записи, глубина стека… Но, увы.

На днях стал счастливым(ли?) обладателем китайского клона STM3210C-EVAL под названием Open107V.
Среди прочего в наборе есть плата расширения с микросхемой DP83848C, которая реализует PHY Ethernet. Соединяется через MII/RMII, по схеме абсолютно идентично оному в оригинальной плате. Суть в том, что попытки создать соединение с компьютером при использовании примеров, представленных ST и компанией Waveshare(чуть переработанные), не увенчались успехом. Симптомы заключаются в отсутствии исходящих пакетов с платы.
Вопрос: кто-нибудь разбирался со встроенным ethernet в stm, в частоности в связке с указанной микросхемой? В чем может быть загвоздка?

Комментарии ( 57 )

Попробуй еще раз поверь клоки и притяни все свободные ноги.

Тут не надо гадать, тут надо отлаживать. Для начала повесить анализатор на clock, MDC и MDIO и посмотреть, если ли такт в 50 МГц и команды инициализации. JP3 и JP4 проверь.

JP3-4 не проверить ввиду их отсутсвия, но все линии RMII на месте. Сигнал 50МГц присутствует. Выяснил, что пакеты успешно доходят до контроллера, MAC-адрес компа записывается, но по некотоырм причинам не формируются ответные пакеты на ARP-запросы. Я, к сожалению, не имею возможности постоянно заниматсья этим вопросом, так что ковыряю достаточно медленно. Планирую сегодня-завтра доковырять.
В некоторых демопроектах программа затыкается в месте, где производится сброс ethernet-контрллера — не сбрасывается флаг SR в регистре DMABSR.

А зачем Вам U-Link? Rbnfqcrbq j-Link — дешевле, и поддерживается всюду. Как вариант — ST-Link/v2 (ориганальный) у тех же китайцев порядка 20-24$, например, тут.

А какой отладчик используешь? Собираюсь похожую китайскую платку купить, вот не знаю, купить ли китайский U-Link или оригинальный от ST.

Я ST-Link пользую. Говорят, что с U-link в кейле есть некоторые преимущества, хотя я конекретно в этом не разбирался. Но надо обратить внимание, что U-link, если память не изменяет, не поддерживается в IAR. Впрочем, большинство демопроектов как есть исключительно под кейл.


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

Подключение ENC28J60.

Отладочная плата Blue Pill.

Для ENC28J60 у меня среди прочих есть такой модуль, пусть будет он:

Мы будем писать код исходя из соображений возможности его использования и с любым другим железом, так что выбор в данном случае не критичен.

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

Сетевая модель OSI.

Подключение ENC28J60 к STM32.

Настройка периферии в STM32CubeMx.

У меня внешний кварцевый резонатор на 8 МГц, поэтому в окне тактирования:

Тактирование в STM32CubeMx.

Настройка SPI.

После этого можно переходить к генерации проекта, больше в CubeMx ничего менять не будем.

Сразу же зададим адекватную структуризацию в проекте, которой и будем придерживаться по мере его, проекта, развития. Создадим папку Modules, в которую будем помещать наши файлы для работы с тем или иным протоколом или устройством. И сразу добавляем подпапку, а также заголовочный и файл с исходным кодом для драйвера ENC28J60, который и будем реализовывать:

Структура проекта.

Инициализация и работа с ENC28J60.

Начнем с базовых функций для отправки и приема данных по SPI, которые сопровождаются установкой и сбросом сигнала Chip Select:

Далее последовательно функции для записи/отправки байта, записи нескольких байт, чтения байта:

  • управляющие регистры
  • регистры для работы с буфером Ethernet
  • и регистры PHY

Сегодня наш акцент будет смещен на работу с первой из этих групп. Управляющие регистры распределены по 4-м банкам:


Первые буквы регистров указывают на принадлежность регистров:

Это может показаться очень запутанным, непрозрачным и непонятным, но все встанет на свои места по мере того, как мы будем решать практические задачи. Так что не стоит на этом сильно зацикливаться.

Описание всех регистров и их битов я приводить не буду, поскольку это будет банальным переводом даташита, в этом толку, кроме увеличения объема статьи, никакого нет.


Соответственно, как тут указано, байт команды состоит из кода OpCode (3 бита) и 5 битов, которые либо отвечают за адрес регистра из таблицы выше, либо имеют фиксированное значение для некоторых команд. Разберем, к примеру, команду чтения управляющего регистра (Read Control Register):



В общем, несложная модель, реализуем практически. Для начала определим все существующие регистры. Нюанс тут заключается в том, что помимо адреса каждый регистр имеет еще и свой собственный тип (Ethernet, MAC, MII), а также относится к какому-либо банку. Поэтому для описания каждого из регистров будем использовать 8 битов таким вот образом:


Итак, в заголовочном файле определены enum для банков и типов регистров:

И набор дефайнов:

Все эти определения подчиняются схеме описания регистров, которую мы разобрали. Для номера банка у нас 5-ый и 6-ой из 8 битов, соответственно, ENC28J60_REG_BANK_OFFSET = 5 и ENC28J60_REG_BANK_MASK = 0x60 (0b01100000). Аналогично для бита, который отвечает за тип регистра (он у нас 7-ой).

Также для тех 5-ти регистров, которые не относятся к конкретному банку мы будем использовать такое же значение битов, как для нулевого банка (ENC28J60_BANK_COMMON_BITS). Но для их идентификации будем использовать не значения битов, как для других регистров, а непосредственно значение адреса. Поскольку мы знаем, что эти уникальные регистры расположены по адресам старше, чем ENC28J60_COMMON_REGS_ADDR (0x1B).

В итоге имеем изящную систему определения регистров: Register = Address | Type | Bank, где:

Для работы с определенными битами регистров определяем их позиции. Возьмем, к примеру, регистр ECON1:

Перед любыми операциями с регистрами нам нужно будет проверять текущий активный банк в ENC28J60, номер которого хранится в двух младших битах регистра ECON1:

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

Функция проверки банка:

Вспоминаем о тех 7-ми командах, которые предоставляет нам ENC28J60, и определяем их:

Опкоды команд, в свою очередь, в массиве:

Функция отправки байта команды:

И на базе этой функции мы создадим все команды. Рассмотрим пару из них, чтение регистра:

Вот итоговый список тех 7-ми функций-команд для взаимодействия с ENC28J60:

И, во-вторых, есть отдельная группа PHY регистров, не относящихся к банкам, которые мы обсудили, имеющих свое собственное адресное пространство.

Их мы просто определяем адресами:

Особенность этих регистров в том, что с ними нельзя работать напрямую, а только через MIREGADR и MIRDL/MIRDH:

База для работы с ENC28J60 полностью готова, так что стартовую статью цикла мы сейчас завершим инициализацией модуля, которую будем использовать и в последующих проектах:

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

В состав микроконтроллеров STM32F107xx, STM32F207xx и STM32F217xx входит периферия Ethernet MAC. Основные свойства периферии:
полноценный MAC-уровень с подключением к внешнему физическому уровню;
работа на скоростях 10 и 100 Мбит/с;
полу/полнодуплексные режимы работы;
выделенный DMA-контроллер с очередями приёма и передачи пакетов;
поддержка привязки пакетов во времени;
управление входом/выходом режимов низкого энергопотребления;
интегрированный набор векторов прерываний.
Рассмотрим блок-схему Ethernet MAC в контроллере STM32F107 (см. рис. 1).


Рис. 1. Блок-схема Ethernet MAC в контроллере STM32F107


Рис. 2. Аддитивное дрожание синхроимпульсов традиционных ХО обычно в 3…10 раз больше, чем в DSPLL с ХО

Подключение по RMII требует всего восьми портов контроллера, в то время как для подключения физического уровня по стандарту MII требуется 16 портов контроллера. Если перевести количество свободных портов контроллера в стоимость, можно предположить, что соединение по RMII более выгодно. Скорее всего, так и есть, однако имеется ряд нюансов. Интерфейс RMII работает на частоте 50 МГц, что вдвое выше, чем у MII. Соответственно, эмиссия помех такого решения выше. Более того, для генерации 50 МГц и выдаче этой частоты на микросхему физического уровня задействуется один из множителей частоты — рекомендуемое производителем решение по тактированию внешней микросхемы Ethernet PHY. И, наконец, контроллер STM32 может подключить до 32-х внешних микросхем физического уровня по интерфейсу MII и всего лишь одну — по интерфейсу RMII. В любом случае, у разработчика остаётся право выбора, каким образом подключить внешнюю микросхему физического уровня Ethernet.

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

// сброс настроек в начальное состояние Ethernet
ETH_DeInit();

// сбрасываем Ethernet
ETH_SoftwareReset();

// ждём подтверждения, что Ethernet сбросился
while(ETH_GetSoftwareResetStatus()==SET);

Далее задаем свойства сети:

// конфигурируем Ethernet
ETH_StructInit(&ETH_InitStructure);

// Устанавливаем параметры ETH_InitStructure
ETH_InitStructure.ETH_AutoNegotiation = ETH_AutoNegotiation_Enable ;
ETH_InitStructure.ETH_Speed = ETH_Speed_100M;
ETH_InitStructure.ETH_LoopbackMode = ETH_LoopbackMode_Disable;
ETH_InitStructure.ETH_Mode = ETH_Mode_FullDuplex;
ETH_InitStructure.ETH_RetryTransmission = ETH_RetryTransmission_Disable;
ETH_InitStructure.ETH_AutomaticPadCRCStrip = ETH_AutomaticPadCRCStrip_Disable;

// Принимать всё подряд
// ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Enable;

ETH_InitStructure.ETH_BroadcastFramesReception = ETH_BroadcastFramesReception_Enable;
ETH_InitStructure.ETH_PromiscuousMode = ETH_PromiscuousMode_Disable;
ETH_InitStructure.ETH_MulticastFramesFilter = ETH_MulticastFramesFilter_Perfect;
ETH_InitStructure.ETH_UnicastFramesFilter = ETH_UnicastFramesFilter_Perfect;
// производим инициализацию параметров
Value = ETH_Init(&ETH_InitStructure, PHY_ADDRESS);

Процедура ETH_Init настраивает не только внутренние регистры контроллера, но и внешнюю микросхему PHY-уровня. Далее должно быть выделено пространство буферов приёма, буферов передачи и для описывающих их дескрипторов.

// Будем использовать стандартные библиотеки, поэтому создаём соответствующие структуры
ETH_InitTypeDef ETH_InitStructure;

// Ethernet DMA работает с дескрипторами — указатели массивов данных, которые следует транслировать (+ дополнительная служебная информация)
// Дескрипторы
ETH_DMADESCTypeDef DMARxDscrTab[ETH_RXBUFNB], DMATxDscrTab[ETH_TXBUFNB];
// массив буферов приёма и отправки данных
// на которые будут ссылаться дескрипторы
u8 Rx_Buff[ETH_RXBUFNB][ETH_MAX_PACKET_SIZE], Tx_Buff[ETH_TXBUFNB][ETH_MAX_PACKET_SIZE];

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

// Записываем часть параметров дескрипторов (указатели на буфер + на следующий дескриптор)
ETH_DMATxDescChainInit(DMATxDscrTab, &Tx_Buff[0][0], ETH_TXBUFNB);
// Записываем длину буфера в дескриптор
DMATxDscrTab->ControlBufferSize = 100;

// Устанавливаем дескрипторы для приёма
ETH_DMARxDescChainInit(DMARxDscrTab, &Rx_Buff[0][0], ETH_RXBUFNB);
DMARxDscrTab->ControlBufferSize = ETH_MAX_PACKET_SIZE | (1<<14);

Функции в качестве аргументов имеют начальные адреса дескрипторов, начальные адреса буферов данных и длину одного буфера. Аналогичные библиотечные функции имеются для организации кольцевой структуры дескрипторов.
Итак, дескрипторы описаны, свойства сети заданы, запускаем Ethernet:

// Разрешаем приём
DMARxDscrTab->Status = ETH_DMARxDesc_OWN;

// Запускаем Ethernet
ETH_Start();

// а прошлая посылка отправлена?Если отправлена, то
if ((DMATxDscrTab->Status&ETH_DMARxDesc_OWN) == 0)
// Чтобы успешно отправлять, следует сначала отключить передачу (либо успевать обрабатывать все буферы, чтобы DMA не подвешивался).
ETH_DMATransmissionCmd(DISABLE);
//помещаем данные по яркости в 20 и 21-й байт посылки
Tx_Buff[0][20] = Bright_Tx&0xFF;
Tx_Buff[0][21] = Bright_Tx>>8;
// отдаём дескриптор в DMA Ethernet
DMATxDscrTab->Status = ETH_DMARxDesc_OWN | ETH_DMATxDesc_TCH | ETH_DMATxDesc_TTSE | ETH_DMATxDesc_LS | ETH_DMATxDesc_FS;
// разрешаем передачу
ETH_DMATransmissionCmd(ENABLE);
>
В отправляемый пакет помещаем данные. В нашем случае это два байта со смещением 20 и 21 от начала пакета и передаём дескриптор в распоряжение DMA.

// адрес назначения МАССОВАЯ РАССЫЛКА
Tx_Buff[0][0]=0xff;
Tx_Buff[0][1]=0xff;
Tx_Buff[0][2]=0xff;
Tx_Buff[0][3]=0xff;
Tx_Buff[0][4]=0xff;
Tx_Buff[0][5]=0xff;
// адрес источника
Tx_Buff[0][6]=0x17;
Tx_Buff[0][7]=0x11;
Tx_Buff[0][8]=0x12;
Tx_Buff[0][9]=0x13;
Tx_Buff[0][10]=0x14;
Tx_Buff[0][11]=0x15;
// длина пакета
Tx_Buff[0][6]=0x0;
Tx_Buff[0][7]=0x55;

Мы самостоятельно заполняем преамбулу пакета аналогично структуре, описанной в разделе «Ethernet в STM32». При этом мы не заполняем синхронизирующий пакет с командой начала данных — первые восемь байт, а так же контрольную сумму CRC32, которая будет добавлена автоматически.
Если мы собираемся принимать пакеты определённой структуры, то мы можем ввести фильтрацию. Далее показан вариант настройки Ethernet периферии с организацией фильтрации по адресу источника.

// Настройка фильтра приёма
ETH_InitStructure.ETH_ReceiveAll = ETH_ReceiveAll_Disable;
ETH_InitStructure.ETH_SourceAddrFilter = ETH_SourceAddrFilter_Normal_Enable;
ETH_InitStructure.ETH_DestinationAddrFilter = ETH_DestinationAddrFilter_Normal;
Далее необходимо настроить фильтр. В качестве фильтра воспользуемся MACAddress1:
//настраиваем MAC-адрес устройства
Mac_addr0[0]=0x0;
Mac_addr0[1]=0x55;
Mac_addr0[2]=0x12;
Mac_addr0[3]=0x13;
Mac_addr0[4]=0x14;
Mac_addr0[5]=0x17;

ETH_MACAddressConfig(ETH_MAC_Address1, Mac_addr0);
ETH_MACAddressFilterConfig(ETH_MAC_Address1,ETH_MAC_AddressFilter_SA);
ETH_MACAddressPerfectFilterCmd(ETH_MAC_Address1, ENABLE);

Читайте также: