Подключение микроконтроллера к локальной сети: работаем с ENC28J60

Эта часть полностью посвящена работе с ENC28J60.

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

Но даташит всё равно может пригодится. А так же еррата.

Краткое содержание:

  • Включение ENC28J60
  • Архитектура ENC28J60
  • Обмен данными по SPI
  • Инициализация
  • Отправка пакетов
  • Приём пакетов
  • Заключение

Примеры кода написаны под AVR. Впрочем из платформенно-зависимых вещей тут только работа со SPI.

ENC28J60 — Ethernet-адаптер (проще говоря, «сетевая карточка») на одном чипе, разработанный вражеской компанией Microchip. Микросхемка не требует для работы много обвязки из внешних компонентов, к МК подключается с помощью SPI. Полностью соответствует спецификации IEEE 802.3 и, кроме того, поддерживает много дополнительных прикольных фич (например, аппаратную фильтрацию пакетов).

А теперь, немного о грустном. Количество багов в ENC28J60 трудно описать печатными словами. Из-за них половина фич либо работает нестабильно, либо может нарушать работу других важных модулей. Хотя, главное, что принимать и отправлять пакеты девайс всё-таки умеет. :)

Подключаемся


Микросхемка выпускается в 28-ножечных DIP, SOIC и QFN корпусах. Попадаются и готовые модули со всей обвязкой и разъёмом для сетевого кабеля.

Вот стандартная схема включения ENC28J60 (распиновка для DIP корпуса):

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

Увеличить схему

Питание — 3.3 В. Но входы микросхемы совместимы с 5-вольтовыми TTL уровнями.

Потребляет микросхемка прилично — 250 мА. Нужно столько для питания драйверов передатчика. Есть режим «пониженного энергопотребления», когда вся «силовая» часть отключается.

VCAP — выход встроенного преобразователя на 2,5 В (именно такое напряжение используется при передачи данных по сетевому кабелю). К этому выводу нужно подключить конденсатор на 10 мкф. Даташит не рекомендует питать от этого вывода что-то ещё.

R7 (RBIAS) — резистор для какой-то балансировки. В даташите указан номинал 2 кОм с допуском 1%. Однако в ENC28J60 есть баг, из-за которого в ревизиях микросхемы 1 и 4 нужно использовать резистор на 2,7 кОм. А в ревизиях 5 и 7 — на 2,32 кОм. Иначе выходной сигнал не будет соответствовать спецификации IEEE. Западло, однако. Ревизию можно определить только чтением соответствующего регистра. Мне попалась ревизия 7 — судя по всему, последняя. Так что, стоит запаять резистор на 2,32 кОм, прочитать ревизию, и, если вдруг попадётся другая ревизия, резистор заменить. Где взять резистор на такой необычный номинал? Можно бегать по магазинам и искать, или просто взять горсточку обычных неточных резисторов на 2,2 кОм и методом тыка выбрать наиболее близкий к требуемому номиналу. Впрочем, когда я только начинал экспериментировать с ENC28J60, об этом баге не знал и ставил резистор на 2 кОм. Проблем не было. :)

TR1 и TR2 — не абы какие трансформаторы, а специальные Ethernet-фильтры (Ethernet magnetics). Представляют собой систему из нескольких катушек на ферритовых колечках. Обычно выпускаются в виде готовых сборок (оба фильтра в одном корпусе, совместимом с DIP-16). Нужны они, судя по всему, для развязки, защиты от статики, etc. (сетевой кабель может иметь длину до 100, а то и 300 м — представь какой статический потенциал может быть между девайсами на таком расстоянии). Где их взять? Вариант номер раз — взять мёртвую/ненужную (или хотя-бы дешёвую) сетевую карточку, и выпаять из неё. Кстати, в ней же найдутся точные резисторы на 50 Ом, розеточка для сетевого кабеля и, если повезёт, кварц на 25 МГц. Вариант номер два — использовать сетевой разъём с уже встроенными фильтрами («MagJack»). Деталька редкая и дорогая. Впрочем, достать её можно из трупика материнской платы — обычно там используются именно они. Правда, чтобы выпаять такую массивную деталь из толстенной платы с кучей слоёв меди, понадобится паяльная лампа или что-то в этом роде. К тому же часто деталька идёт в виде неразделимого блока с USB-A розеточками, которые будут вносить неприятную энтропию в конструкцию (если, конечно, в ней не будет USB-хоста, хе-хе).

Катушка L1 — ферритовое колечко диаметром 5мм с несколькими витками проволоки. Если колечка под рукой нет, можно поставить дроссель, например, на 100 мкГн.

ENC28J60 автоматически определяет полярность подключенных светодиодов. Причём полярность светодиода, подключенного к выводу LEDB влияет на дуплексный режим работы микросхемы. Если светодиод подключен как показано на схеме, катодом к микрухе — ENC28J60 инициализируется в полнодуплексном режиме. Соответственно, если подключен анодом — то в полудуплексном. Если светодиод не подключен — состояние не определено. Впрочем, дуплексный режим можно изменить при инициализации.

Конденсатор C2 на 2 кВ служит для разрядки статики при подключении кабеля. Естественно, можно поставить конденсатор и на меньшее напряжение. Ни на что это не повлияет, разве что твой девайс не будет формально соответствовать стандарту.

Вот так я запаял

Вход RESET уже подтянут к питанию внутри микрухи, так что его можно оставить болтаться — ENC28J60 поддерживает и «мягкий» сброс.

Как выяснилось, вход RESET у ENC28J60, несмотря на то, что сказано в даташите, не подтянут! Его обязательно нужно соединить с питанием, иначе микруха может сброситься в самый неудачный момент из-за любой наводки.

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

С выхода CLKOUT можно снимать тактовый сигнал (с настраиваемым делителем). Правда, из-за бага, при входе в спящий режим сигнал пропадает (хотя главные часики продолжают тикать). Блин, инженеры из Microchip совсем забивают на тестирование?!

Таким образом, для связи с микроконтроллером можно использовать только 4 провода — стандартную шину SPI.

Архитектура ENC28J60


На этой картинке я нарисовал основные блоки ENC28J60:

Архитектура ENC28J60

  • PHY — физический уровень. Приёмник, передатчик, драйверы, etc. В общем, всё, что необходимо для работы с определённой средой передачи данных (medium). В данном случае — с витой парой, по стандарту 10BASE-T. Доступ к PHY происходит исключительно через MII — Medium Independent Interface. MII задуман так, чтобы следующий (канальный) уровень мог абстрагироваться от типа среды передачи данных. PHY имеет свой набор 16-битных регистров (специфичных для среды передачи данных), доступ к которым осуществляется через MII. Не нужно пугаться аббревиатуры MII — это всего лишь набор регистров, через которые управляется PHY.
  • MAC (Medium Access Controller) — канальный уровень. В него входит вся логика, необходимая для отправки и приёма пакетов в сети Ethernet. MAC занимается адресацией, рассчётом контрольной суммы, фильтрацией принимаемых пакетов, разрешением коллизий (в полудуплескном режиме), etc. Обменивается со следующим, сетевым уровнем готовыми пакетами, а с физическим — отправляемыми и принимаемыми «сырыми» байтами.
  • Управляющая логика занимается всем остальным. В том числе, обслуживает буфер, из которого MAC берёт отправляемые данные и складывает принятые. Управляет режимами энергопотребления, etc.

Вся память в ENC28J60 делится на буфер для данных, управляющие регистры и регистры PHY.

Буфер для данных

В ENC28J60 есть буфер размером 8 КБ. Часть этого буфера обычно выделяется для приёма пакетов, остальное можно использовать как угодно. Например, для отправляемых данных.

Управляющие регистры

Управляющие регистры делятся на 4 банка (ну нравится Microchip'овским инженерам сегментированное адресное пространство). Каждый банк имеет размер в 32 регистра, причём последние 5 ячеек (0x1b..0x1f) всегда мапятся на одни и те же регистры, вне зависимости от того, какой банк выбран.

Страшно?

Карта регистров

Пугаться количества не нужно. Сейчас всё структурируем, и станет просто.

Основная часть регистров имеет префикс E (Ethernet). Регистры MAC — с префиксом MA, регистры MII — с префиксом MI.

Регистры можно разделить на функциональные группы.

Карта регистров

Основное

Назначение отдельных бит, как правило, понятно из их названий. :)
Здесь я опишу лишь то, что нам реально понадобится. Остальные биты описаны в даташите. Однако перед использованием той или иной фичи, нужно заглянуть в еррату и проверить нет ли с данной фичей проблем. Например, DMA (биты DMAST и CSUMEN) еррата использовать не рекомендует вообще. Так-то!

ECON1

  • BSEL1:BSEL0 — выбор банка регистров.
  • RXEN — разрешает приём данных.
  • TXRTS — разрешает отправку пакета (автоматически сбрасывается после того, как отправка пакета будет завершена).

ECON2

  • VRPS — разрешает перевод стабилизатора питания в экономичный режим при включении режима пониженного энергопотребления (бит PWRSV). Данный бит можно установить при инициализации и забыть про него.
  • PWRSV — включает режим пониженного энергопотребления. Прежде чем устанавливать этот бит, следует запретить приём новых пакетов и убедиться что приём данных завершён. После выхода из режима пониженного энергопотребления, нужно подождать 1 мс, чтобы PHY вошёл в рабочий режим.
  • PKTDEC — при установке этого бита значение счётчика пакетов уменьшается на 1.
  • AUTOINC — включает автоматическое инкрементирование указателей чтения и записи буфера (для удобства последовательного чтения и записи данных). Этот бит установлен после сброса, и трогать его ни к чему.

ESTAT

  • TXABRT — флаг завершения передачи с ошибкой.
  • RXBUSY — признак работы приёмника (установлен, если принимаются данные).

Регистр EPKTCNT — счётчик принятых пакетов. Автоматически инкрементируется при успешно принятом пакете. Уменьшается вручную, установкой бита PKTDEC в регистре ECON2. Вручную записывать в этот регистр ничего нельзя, т.к. все операции с ним должны выполняться атомарно.

Указатели буфера

Регистры, указывающие куда приёмник будет складывать данные, откуда данные будет брать передатчик, etc. Каждый указатель занимает два регистра. Например, младший байт ERDPT хранится в регистре ERDPTL, а старший — в ERDPTH.

ERDPT и EWRPT — указатели чтения и записи буфера. Указывают по какому адресу данные будут считываться из буфера или записываться в буфер микроконтроллером.

Если ECON2.AUTOINC установлен, данные будут считываться и записываться последовательно (соответствующий указатель будет инкрементироваться после каждого байта).

Раскладка буфера

ETXST и ETXND — начало и конец отправляемого пакета. Например, если мы хотим отравить пакет размером 256 байт, лежащий в буфере по адресу 0x1800, устанавливаем ETXST в 0x1800 и ETXND в 0x18ff.

ERXST и ERXND — начло и конец кольцевого буфера, в который будут приниматься пакеты. Из-за бага в ENC28J60, в ERXST можно записывать только 0. Например, если мы хотим выделить 4096 байт под приём пакетов, пишем в ERXST 0, а в ERXND 0x0fff. Когда приём пакетов разрешён, трогать эти регистры нельзя.

ERXRDPT и ERXWRPT — указатели кольцевого буфера. Доходя до конца буфера (ERXND), указатель затем перемещается на начало (ERXST).

ERXWRPT — указывает на место, куда приёмник положит следующий принятый пакет. Этот указатель доступен только для чтения. Он автоматически инициализируется вместе с ERXST и автоматически обновляется после приёма пакета.

ERXRDPT — указывает на то место, откуда микроконтроллер будет забирать принятые пакеты.

Если микроконтроллер долго не будет забирать пакеты из буфера, ERXWRPT может «догнать» ERXRDPT. В таком случае приёмнику некуда будет складывать данные и приходящие данные начнут выбрасываться. Чтобы освобождать место в буфере, микроконтроллер, после того, как заберёт пакет из буфера, должен перемещать ERXRDPT к следующему пакету.

DMA

В ENC28J60 есть модуль DMA, позволяющий выполнять операции над блоками. А именно, копирование блока внутри буфера и аппаратное вычисление контрольной суммы для IP и других протоколов. Второе даже могло бы пригодиться. Но из-за имеющегося бага, использование этой фичи может привести к потере входящих пакетов. Обидно.

Фильтрация пакетов

ENC28J60 отлично умеет фильтровать пакеты. Это важно, особенно, если сеть на хабах. :)

Правила фильтрации пакетов устанавливает регистр ERXFCON.

ERXFCON

  • UCEN включает фильтр Unicast-пакетов. Пакет проходит фильтр, если адрес получателя в нём равен нашему MAC-адресу.
  • MCEN включает фильтр Multicast-пакетов. Пакет проходит фильтр, если является Multicast-пакетом.
  • BCEN включает фильтр Broadcast-пакетов. Пакет проходит фильтр, если является широковещательным.
  • MPEN включает фильтр волшебных пакетов. Пакет проходит фильтр, если является волшебным и направлен на наш MAC-адрес.
  • PMEN включает фильтрацию по шаблону.
  • HTEN включает фильтрацию по хэш-таблице.
  • ANDOR — группировка фильтров. Если бит установлен — пакет принимается только при прохождении всех выбраных фильтров. Если сброшен — прохождения одного фильтра достаточно.
  • CRCEN разрешает проверку контрольной суммы. Если установлен, принимаются пакеты только с корректной контрольной суммой.

Фильтрация по шаблону заключается в следующем. Из принятого пакета, по смещению, записанному в регистрах EPMO, берётся окно размером 64 байта. Из этого окна выбираются байты по маске, записанной в регистрах EPMM (например, если бит 0 в регистре EPMM0 установлен, выбирается байт 0 из окна, etc.). От выбранных байт рассчитывается контрольная сумма. Если она совпадает со значением в регистрах EPMCS, фильтр пройден.

При фильтрации по хэш-таблице, рассчитывается хэш от адреса получателя, указанного в заголовке пакета. Берётся соответствующий бит из регистров EHT. Например, если хэш равен 0x5, берётся бит 5 из регистра EHT0. Если бит установлен, фильтр пройден.

MAC-адрес

Те самые 6 байт, которые будут идентифицировать наш девайс в локальной сети. Нужны ENC28J60 для фильтрации входящих пакетов. Хранятся в обратном порядке, т.е. для адреса 01:23:45:67:89:ab в MAADR0 пишем 0xab, в MAADR1 — 0x89, etc.

Регистры MAC

MACON1

  • MARXEN — разрешить MAC принимать пакеты.
  • TXPAUS, RXPAUS — включают аппаратное управление потоком.

MACON3

  • FULLDPX — включить полнодуплексный режим. Дуплексный режим PHY (PHCON1.PDPXMD) должен быть таким же. Значение после сброса зависит от полярности подключения светодиода к ножке LEDB.
  • FRMLNEN — включить автоматическую проверку длины принимаемых и отправляемых фреймов.
  • TXCRCEN — включить автоматическое добавление контрольной суммы к фрейму.
  • PADCFG2:PADCFG0 — настройка паддинга фреймов:

    • 001 — выравнять пакет нулями до 60 байт, затем добавить контрольную сумму (4 байта). Бит TXCRCEN также должен быть установлен.
    • 000 — не выравнивать пакеты.

Регистры MAMXF — максимальная длина принимаемого и отправляемого пакета. Обычно 1518 байт или меньше. Ставим столько, сколько сможет утащить наш МК. Пакеты большего размера будут отбрасываться.

MABBIPG, MAIPGL и MAIPGH — задержка (gap) между отправляемыми пакетами. Стандартные значения:

  • MABBIPG — 0x15 (в полнодуплексном режиме) или 0x12 (в полудуплексном).
  • MAIPGL — 0x12.
  • MAIPGH — 0x0c.

MACLCON1 и MACLCON2 — настройка задержки и ретрансмиссий при возникновении коллизии. Оставляем по умолчанию.

Регистры MII

Регистры MII служат для доступа к регистрам PHY. Во как!

Регистры MII

Для чтения регистра PHY:

  1. Выставляем его адрес в регистре MIREGADR.
  2. Устанавливаем бит MICMD.MIIRD.
  3. Ждём, пока MISTAT.BUSY очистится.
  4. Вручную очищаем MICMD.MIIRD.
  5. Забираем данные из регистров MIRD.

Для записи в регистр PHY:

  1. Выставляем его адрес в регистре MIREGADR.
  2. Записываем данные в регистры MIWR. Сначала MIWRL, затем MIWRH.
  3. Ждём, пока MISTAT.BUSY очистится.

Управление ножкой CLKOUT

В ENC28J60 можно брать тактовый сигнал (с делителем) с ножки CLKOUT. Из-за бага, сигнал может пропадать при входе в режим пониженного энергопотребления.

ECOCON

Биты ECOCON2:0 устанавливают делитель:

  • 000 — ножка CLKOUT подтянута к земле.
  • 001 — делитель на 1 (25 МГц).
  • 010 — делитель на 2 (12,5 МГц).
  • 011 — делитель на 3 (8,333333 МГц).
  • 100 — делитель на 4 (6,25 МГц).
  • 101 — делитель на 8 (3,125 МГц).

Регистры PHY

Регистры PHY раположены в отдельном адресном пространстве. Получить к ним доступ можно через регистры MII. Размер адресного пространства — 32 регистра, всего заюзано 9 адресов.

Регистры PHY

Регистры PHY 16-битные. Используются для различных настроек PHY. Целый регистр выделен под настройки светодиодов. Эстетика!

PHCON1

  • PDPXMD — дуплексный режим PHY. Должен соответствовать дуплексному режиму MAC (MACON3.FULLDPX). Начальное значение зависит от полярности светодиода, подключенного к ножке LEDB.

PHCON2

  • HDLDIS — запрещает «заворот назад» (loopback) отправляемых данных в полудуплексном режиме.

PHSTAT1

  • LLSTAT — «асинхронный» бит сосотяния линка. Читается как 1 если линк есть и не пропадал с момента предыдущего чтения этого бита.

PHSTAT2

  • LSTAT — состояние линка. Бит установлен, если линк есть.

PHLCON

Управление светодиодиками.

  • STRCH — разрешает «растягивание» событий. Если бит включен, события будут отмечаться вспышкой светодиода определённой длительности. Если выключен — светодиод будет зажигаться только во время события (передача/приём данных, etc.).
  • LFRQ — длительность вспышки светодиода:

    • 00 — 40 мс.
    • 01 — 73 мс.

    • 10 — 139 мс.
  • LACFG и LBCFG — выбираем, что именно будут показывать светодиоды, подключенные к ножкам LEDA и LEDB:

    • 0001 — передача.
    • 0010 — приём.

    • 0100 — состояние линка.
    • 0101 — дуплексный режим.
    • 0111 — приём и передача.
    • 1000 — включен.
    • 1001 — выключен.
    • 1100 — приём и состояние линка.
    • 1101 — приём, передача и состояние линка.

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

SPI


Обмен по SPI ведётся в режиме 0 (CPOL=0, CPHA=0). ENC28J60 поддерживает скорость передачи данных по SPI до 10 мбит/с.

// Указываем как у нас подключено
#define ENC28J60_SPI_DDR    DDRB
#define ENC28J60_SPI_PORT    PORTB
#define ENC28J60_SPI_CS        (1<<PB4)
#define ENC28J60_SPI_MOSI    (1<<PB5)
#define ENC28J60_SPI_MISO    (1<<PB6)
#define ENC28J60_SPI_SCK    (1<<PB7)

#define enc28j60_select() ENC28J60_SPI_PORT &= ~ENC28J60_SPI_CS
#define enc28j60_release() ENC28J60_SPI_PORT |= ENC28J60_SPI_CS

// Инициализация ENC28J60
void enc28j60_init()
{
    // Настроим ножки
    ENC28J60_SPI_DDR |= ENC28J60_SPI_CS|ENC28J60_SPI_MOSI|ENC28J60_SPI_SCK;
    ENC28J60_SPI_DDR &= ~ENC28J60_SPI_MISO;
    enc28j60_release();
    
    // Максимальная скорость SPI (CLK/2)
    SPCR = (1<<SPE)|(1<<MSTR);
    SPSR |= (1<<SPI2X);

    // Остальная инициализация
    // ...
}

// Передача данных через SPI
uint8_t enc28j60_rxtx(uint8_t data)
{
    SPDR = data;
    while(!(SPSR & (1<<SPIF)))
        ;
    return SPDR;
}


Обмен данными с ENC28J60 выполняется транзакциями. Транзакция начинается с отправки микроконтроллером команды. Затем идут опциональные данные (приём или передача). Завершается транзакция «поднятием» ножки CS.

Чтение:

Чтение

При чтении данных уровень на линии MOSI не имеет значения.

Запись:

Запись

При записи линия MISO находится в Z-состоянии (т.е. не подключена ни к чему).

#define enc28j60_rx() enc28j60_rxtx(0xff)
#define enc28j60_tx(data) enc28j60_rxtx(data)


Команда состоит из опкода и аргумента. При чтении или записи регистра, аргумент содержит адрес регистра.

Таблица команд

Операции с регистрами

Для чтения регистра контроллер отправляет ENC28J60 команду чтения регистра и забирает значение. При чтении регистров MAC или MII, контроллер должен пропустить 1 «ложный» байт, затем прочитать значение.

// Операция чтения
uint8_t enc28j60_read_op(uint8_t cmd, uint8_t adr)
{
    uint8_t data;

    // Низкий уровень на CS
    enc28j60_select();
    
    // Отправляем команду
    enc28j60_tx(cmd | (adr & 0x1f));
    
    // При необходимости, пропускаем "ложный" байт
    if(adr & 0x80)
        enc28j60_rx();
        
    // Читаем данные
    data = enc28j60_rx();
    
    // Высокий уровень на ножке CS
    enc28j60_release();
    return data;
}

// Операция записи
void enc28j60_write_op(uint8_t cmd, uint8_t adr, uint8_t data)
{
    enc28j60_select();
    
    // Отправляем команду
    enc28j60_tx(cmd | (adr & 0x1f));
    
    // Отправляем значение
    enc28j60_tx(data);
    
    enc28j60_release();
}


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

Также, нам понадобится заголовочный файл с определениями регистров. Для удобства, в определение регистра можно включить также адрес банка и признак регистра MII/MAC.

// С этого адреса начинаются глобальные для всех банков регистры
#define ENC28J60_COMMON_CR    0x1B

// Банк 0
#define ERDPTL                 0x00
#define ERDPTH                 0x01
#define ERDPT                ERDPTL
//...


// Банк 1
#define EHT0                 (0x00 | 0x20)
#define EHT1                 (0x01 | 0x20)
//...

// Банк 2, регистры MAC/MII
#define MACON1                 (0x00 | 0x40 | 0x80)
//...

// Банк 3
#define EREVID                 (0x12 | 0x60)
//...


Кстати, быстро превратить таблицы из даташита в заголовочный файл поможет любой офисный пакет с редактором электронных таблиц. :)

#define ENC28J60_SPI_RCR    0x00
#define ENC28J60_SPI_WCR    0x40
#define ENC28J60_SPI_BFS    0x80
#define ENC28J60_SPI_BFC    0xA0

uint8_t enc28j60_current_bank = 0;

// Выбор банка регистров
void enc28j60_set_bank(uint8_t adr)
{
    uint8_t bank;

    // Регистр относится к определённому банку?
    if( (adr & ENC28J60_ADDR_MASK) < ENC28J60_COMMON_CR )
    {
        // Получаем номер банка
        bank = (adr >> 5) & 0x03; //BSEL1|BSEL0=0x03
        
        // Если выбран "не тот" банк
        if(bank != enc28j60_current_bank)
        {
            // Выбираем банк
            enc28j60_write_op(ENC28J60_SPI_BFC, ECON1, 0x03);
            enc28j60_write_op(ENC28J60_SPI_BFS, ECON1, bank);
            enc28j60_current_bank = bank;
        }
    }
}

// Чтение регистра
uint8_t enc28j60_rcr(uint8_t adr)
{
    enc28j60_set_bank(adr);
    return enc28j60_read_op(ENC28J60_SPI_RCR, adr);
}

// Чтение пары регистров (L и H)
uint16_t enc28j60_rcr16(uint8_t adr)
{
    enc28j60_set_bank(adr);
    return enc28j60_read_op(ENC28J60_SPI_RCR, adr) |
        (enc28j60_read_op(ENC28J60_SPI_RCR, adr+1) << 8);
}

// Запись регистра
void enc28j60_wcr(uint8_t adr, uint8_t arg)
{
    enc28j60_set_bank(adr);
    enc28j60_write_op(ENC28J60_SPI_WCR, adr, arg);
}

// Запись пары регистров (L и H)
void enc28j60_wcr16(uint8_t adr, uint16_t arg)
{
    enc28j60_set_bank(adr);
    enc28j60_write_op(ENC28J60_SPI_WCR, adr, arg);
    enc28j60_write_op(ENC28J60_SPI_WCR, adr+1, arg>>8);
}

// Очистка битов в регистре (reg[adr] &= ~mask)
void enc28j60_bfc(uint8_t adr, uint8_t mask)
{
    enc28j60_set_bank(adr);
    enc28j60_write_op(ENC28J60_SPI_BFC, adr, mask);
}

// Установка битов в регистре (reg[adr] |= mask)
void enc28j60_bfs(uint8_t adr, uint8_t mask)
{
    enc28j60_set_bank(adr);
    enc28j60_write_op(ENC28J60_SPI_BFS, adr, mask);
}


Чтение и запись буфера

Для чтения буфера отправляем команду чтения, затем читаем столько байт, сколько нам нужно. Завершается операция поднятием линии CS.

#define ENC28J60_SPI_RBM    0x3A

// Чтение данных из буфера (по адресу в регистрах ERDPT)
void enc28j60_read_buffer(uint8_t *buf, uint16_t len)
{
    enc28j60_select();
    enc28j60_tx(ENC28J60_SPI_RBM);
    while(len--)
        *(buf++) = enc28j60_rx();
    enc28j60_release();
}


Запись происходит аналогично. Команда, передача данных, поднятие CS.

#define ENC28J60_SPI_WBM    0x7A

// Запись данных в буфер (по адресу в регистрах EWRPT)
void enc28j60_write_buffer(uint8_t *buf, uint16_t len)
{
    enc28j60_select();
    enc28j60_tx(ENC28J60_SPI_WBM);
    while(len--)
        enc28j60_tx(*(buf++));
    enc28j60_release();
}


Мягкий сброс

Сброс выполняется отправкой команды 0xff. После сброса ждём 1 мс, чтобы ENC28J60 мог выполнить внутреннюю инициализацию.

#define ENC28J60_SPI_SC        0xFF

void enc28j60_soft_reset()
{
    // Отправляем команду
    enc28j60_select();
    enc28j60_tx(ENC28J60_SPI_SC);
    enc28j60_release();

    // Ждём, пока ENC28J60 инициализируется
    _delay_ms(1);

    // Не забываем про банк
    enc28j60_current_bank = 0;
}


Инициализация


Типичная последовательность инициализации ENC28J60 выглядит примерно так:

  • Настраиваем размер FIFO для приёма данных (ERXST, ERXND), инициализируем указатель для чтения данных из FIFO (ERXRDPT).
  • Настраиваем фильтрацию входящих пакетов. По умолчанию, ENC28J60 пропускает пакеты, приходящие на наш MAC-адрес и широковещательные пакеты. В принципе, можно так и оставить.
  • Настраиваем MAC:

    • Очищаем MACON2.MARST чтобы снять сброс MAC.
    • Устанавливаем MACON1.MARXEN чтобы разрешить приём данных MAC.

    • Устанавливаем MACON1.RXPAUS и MACON1.TXPAUS для включения аппаратного упралвения потоком.
    • Настраиваем биты PADCFG, TXCRCEN в MACON3. Для большинства приложений подойдёт выравнивание пакета до 60 байт и автоматическое добавление контрольной суммы.
    • Устанавливаем максимальный размер фрейма в регистрах MAMXF.
    • Устанавливаем размер промежутка между фреймами в регистрах MABBIPG, MAIPGL и MAIPGH.
    • Устанавливаем MAC-адрес в регистрах MAADR.
  • Настраиваем PHY:

    • Включаем бит PHCON2.HDLDIS, если не хотим получать свои пакеты обратно в полудуплексном режиме.
    • Выбираем как на различные события будут реагировать светодиоды LEDA и LEDB в регистре PHLCON.

  • Настраиваем дуплексный режим, если хотим переопределить значение, определяемое полярностью светодиода LEDB. Для включения полного дуплекса устанавливаем биты PHCON1.PDPXMD и MACON3.FULDPX.
  • Разрешаем приём пакетов



#define ENC28J60_SPI_DDR    DDRB
#define ENC28J60_SPI_PORT    PORTB
#define ENC28J60_SPI_CS        (1<<PB4)
#define ENC28J60_SPI_MOSI    (1<<PB5)
#define ENC28J60_SPI_MISO    (1<<PB6)
#define ENC28J60_SPI_SCK    (1<<PB7)

#define ENC28J60_BUFSIZE    0x2000
#define ENC28J60_RXSIZE        0x1A00
#define ENC28J60_MAXFRAME    1500

#define ENC28J60_RXSTART    0
#define ENC28J60_RXEND        (ENC28J60_RXSIZE-1)
#define ENC28J60_TXSTART    ENC28J60_RXSIZE
#define ENC28J60_BUFEND        (ENC28J60_BUFSIZE-1)

uint16_t enc28j60_rxrdpt = 0;

void enc28j60_init(uint8_t *macadr)
{
    // Настраиваем SPI
    ENC28J60_SPI_DDR |= ENC28J60_SPI_CS|ENC28J60_SPI_MOSI|ENC28J60_SPI_SCK;
    ENC28J60_SPI_DDR &= ~ENC28J60_SPI_MISO;
    enc28j60_release();

    SPCR = (1<<SPE)|(1<<MSTR);
    SPSR |= (1<<SPI2X);

    // Выполняем сброс
    enc28j60_soft_reset();

    // Настраиваем размер буфера для приёма пакетов
    enc28j60_wcr16(ERXST, ENC28J60_RXSTART);
    enc28j60_wcr16(ERXND, ENC28J60_RXEND);

    // Указатель для чтения принятых пакетов
    enc28j60_wcr16(ERXRDPT, ENC28J60_RXSTART);
    enc28j60_rxrdpt = ENC28J60_RXSTART;

    // Настраиваем MAC
    enc28j60_wcr(MACON2, 0); // очищаем сброс
    enc28j60_wcr(MACON1, MACON1_TXPAUS|MACON1_RXPAUS| // включаем управление потоком
        MACON1_MARXEN); // разрешаем приём данных
    enc28j60_wcr(MACON3, MACON3_PADCFG0| // разрешаем паддинг
        MACON3_TXCRCEN| // разрешаем рассчёт контрольной суммы
        MACON3_FRMLNEN| //разрешаем контроль длины фреймов
        MACON3_FULDPX);// включаем полный дуплекс
    enc28j60_wcr16(MAMXFL, ENC28J60_MAXFRAME); // устанавливаем максимальный размер фрейма
    enc28j60_wcr(MABBIPG, 0x15); // устанавливаем промежуток между фреймами
    enc28j60_wcr(MAIPGL, 0x12);
    enc28j60_wcr(MAIPGH, 0x0c);
    enc28j60_wcr(MAADR5, macadr[0]); // устанавливаем MAC-адрес
    enc28j60_wcr(MAADR4, macadr[1]);
    enc28j60_wcr(MAADR3, macadr[2]);
    enc28j60_wcr(MAADR2, macadr[3]);
    enc28j60_wcr(MAADR1, macadr[4]);
    enc28j60_wcr(MAADR0, macadr[5]);

    // Настраиваем PHY
    enc28j60_write_phy(PHCON1, PHCON1_PDPXMD); // включаем полный дуплекс
    enc28j60_write_phy(PHCON2, PHCON2_HDLDIS); // отключаем loopback
    enc28j60_write_phy(PHLCON, PHLCON_LACFG2| // настраиваем светодиодики
        PHLCON_LBCFG2|PHLCON_LBCFG1|PHLCON_LBCFG0|
        PHLCON_LFRQ0|PHLCON_STRCH);

    // разрешаем приём пакетов
    enc28j60_bfs(ECON1, ECON1_RXEN);
}


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


Для отправки пакета, записываем указатели на его начало и конец в регистры ETXST и ETXND. Перед пакетом должен находиться управляющий байт, в котором можно переопределить некоторые настройки MAC для отправки этого пакета. После того, как пакет будет отправлен, после его конца будет записан блок, содержащий статус передачи.

Раскладка отправляемого пакета

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


void enc28j60_send_packet(uint8_t *data, uint16_t len)
{
    // Ждём готовности передатчика
    while(enc28j60_rcr(ECON1) & ECON1_TXRTS)
        ;
        
    // Записываем пакет в буфер
    enc28j60_wcr16(EWRPT, ENC28J60_TXSTART);
    enc28j60_write_buffer((uint8_t*)"\x00", 1);
    enc28j60_write_buffer(data, len);

    // Устанавливаем указатели ETXST и ETXND
    enc28j60_wcr16(ETXST, ENC28J60_TXSTART);
    enc28j60_wcr16(ETXND, ENC28J60_TXSTART + len);

    // Разрешаем отправку
    enc28j60_bfs(ECON1, ECON1_TXRTS);
}


Правда, в ENC28J60 есть баг, из-за которого бит TXRTS может не сбрасываться при серьёной ошибке передачи пакета. Соответственно, готовности передатчика мы не дождёмся. Еррата рекомендует проверять бит EIR.ERIF, и, если он установлен, выполнять сброс передатчика. Для этого изменим код вот так:


    //...
    while(enc28j60_rcr(ECON1) & ECON1_TXRTS)
    {
        // При ошибке, сбрасываем передатчик
        if(enc28j60_rcr(EIR) & EIR_TXERIF)
        {
            enc28j60_bfs(ECON1, ECON1_TXRST);
            enc28j60_bfc(ECON1, ECON1_TXRST);
        }
    }
    //...


Приём пакетов


ENC28J60 записывает пакеты в кольцевой буфер в виде связанного списка:

Раскладка принятого пакета

Адрес первого непрочитанного пакета храниться в регистрах ERXRDPT. Забрав пакет, микроконтроллер записывает в ERXRDPT адрес следующего пакета. После этого место, которое занимал пакет считается свободным и ENC28J60 может использовать его для приёма новых пакетов.

Статус приёма — длина пакета (2 байта) и различные флаги (тоже 2 байта). Из флагов нас интересует только бит 7 — приём успешно завершён.

Все принятые пакеты ENC28J60 записывает в буфер с выравниванием на 2 байта. Таким образом, адрес пакета всегда чётный.

Для того, чтобы забрать принятый пакет, микроконтроллер делает следующее:

  • Смотрит сколько принято пакетов (в регистре EPKTCNT).
  • Читает пакет из буфера (по адресу ERXRDPT).
  • Записывает в ERXRDPT адрес следующего пакета.
  • Уменьшает значение счётчика пакетов установкой бита ECON2.PKTDEC.

Ну и последний на сегодня баг ENC28J60 — при записи чётного значения в регистр ERXRDPT, ENC28J60 может повредить данные в буфере (кстати, адрес пакета всегда чётный из-за выравнивания). Еррата рекомендует записывать в ENC28J60 всегда нечётное значение. Стоп, а как же мы узнаем откуда брать новый пакет? Придётся хранить это значение в памяти микроконтроллера. Но ERXRDPT мы всё равно должны записывать, чтобы ENC28J60 знал сколько памяти доступно для приёма пакетов. Только записывать будем не адрес следующего пакета, а на адрес на 1 байт выше.

// "Правильное" значение ERXRDPT
uint16_t enc28j60_rxrdpt = 0;

uint16_t enc28j60_recv_packet(uint8_t *buf, uint16_t buflen)
{
    uint16_t len = 0, rxlen, status, temp;

    // Есть ли принятые пакеты?
    if(enc28j60_rcr(EPKTCNT))
    {
        // Считываем заголовок
        enc28j60_wcr16(ERDPT, enc28j60_rxrdpt);

        enc28j60_read_buffer((void*)&enc28j60_rxrdpt, sizeof(enc28j60_rxrdpt));
        enc28j60_read_buffer((void*)&rxlen, sizeof(rxlen));
        enc28j60_read_buffer((void*)&status, sizeof(status));

        // Пакет принят успешно?
        if(status & 0x80)
        {
            // Выбрасываем контрольную сумму
            len = rxlen - 4;
            
            // Читаем пакет в буфер (если буфера не хватает, пакет обрезается)
            if(len > buflen) len = buflen;
            enc28j60_read_buffer(buf, len);    
        }

        // Устанавливаем ERXRDPT на адрес следующего пакета - 1
        temp = (enc28j60_rxrdpt - 1) & ENC28J60_BUFEND;
        enc28j60_wcr16(ERXRDPT, temp);

        // Уменьшаем счётчик пакетов
        enc28j60_bfs(ECON2, ECON2_PKTDEC);
    }

    return len;
}


Заключение


Готовую библиотеку можно взять здесь.

Уфф, ну вот вроде и всё про ENC28J60 :)

В следующей части напишем простенькое приложение работающее с компом по UDP.

update: Микрочип время от времени обновляет даташит. Последнюю версию можно найти здесь. Статья написана на основе документа ревизии A.


Все статьи цикла

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

RSS свернуть / развернуть
Афтар жги дальше :-)
+1
отлично. ждем продолжения
0
Спасибо, информативно :)
Почитал Errata, 15 багов 8) Но если взять правильные бубны тогда баги превращаются в новые фичи…
0
по теме ENC28J60+Errata нашел подобные комменты на roboforum-е:
ENC28J60 — жутко глючная штука, не советую с ней даже связываться. Использовали первое время в преобразователе Ethernet — RS485, так эта зараза при непонятном стечении обстоятельств отваливалась сама собой. Даже после выполнения всех безумных рекомендаций из Errata (типа тактирования микроконтроллера только от самой ENC)- лечилась исключительно перезагрузкой.
никто не сталкивался?
0
Хм, ну она у мя «сама» отваливалась когда я резет не подтянул)
Ибо если она сбросится, мк, естественно, не догадается её снова инициализировать.
А так по нескольку дней работало с приличной нагрузкой кстати)))
Алсо нету в еррате рекомендации тактовать мк от самой енки.
0
Количество глюков это объяснимо. Мелкочип всё таки.
Но где ты найдёш такую же дешёвую микруху?
0
скажите кто знает. а контроллеры пик тоже такие глючные?)))
0
Спасибо.
Особо порадовала цветная табличка! Почему таких нету в даташитах?!? :)
Что будет в следующей серии, если не секрет?
0
Он же сказал — UDP. Тут, насколько я вижу (я еще тока чуть дальше цветной таблички дошел) про чтение Ethernet'пакетов из микросхемы. Дальше, видимо — протоколы IP и UDP.
0
Большое спасибо афтару :)
Давно у меня уже валяется в закромах этот таракан, все никак не мог его понять и вдруг статья :)
Ух щас я его! :)
0
А у этого контроллера вообще что-то работает без глюков и кучки условий мелким текстом? =)
Что-то пока читаю статью, везде то то не работает, то резистор подбирается в зависимости от фазы луны =D
0
Хороший вопрос.
В фильтре пакетов вроде бы нету багов (известных).
Действительно, создаётся впечатление, что, как один эмбеддер сказал, микруху эту разрабатывал какой-то индус левой пяткой)
Но главное, что заставить её правильно работать всё-таки можно, пусть и ценой нескольких хаков в коде.
0
А вообще-то баги в микрухах — далеко не редкость. Это встречается повсюду (
0
Нде
молодец конечно что разобрался
а вот лично я после всего вышеописанного
даже смотреть на это… в здравом уме не буду
мозг жалко
0
Что не так? (
0
да не
я о багах
0
Спасибо за статью, она безусловно будет полезна многим.
Сам недавно купил эту микруху, смущает только одно — она работает только с IPv4, а ведь на подходе IPv6 (может даже по оптволокну) и ставить ее в новые устройства вродь как уже не имеет особого смысла. Разве что попрактиковаться в создании интернет-устройств, для этого ее и купил.
0
Ей без разницы с каким протоколом сетевого уровня работать.
IPv6 на подходе, ага. Но и IPv4 ещё очень долго никуда не денется.
0
Эта микросхемка не реализует сетевой уровень, на котором как раз протокол IP работает, только канальный. Да и тот, на сколько я понял из первой части статьи, не весь. За ARP'ом тем же не следит.

Для ЛВС ещё долго будет актуальна.
0
Да, и правда, IP адрес окажется в буфере вместе с остальными данными. Значит ошибался, мне почему-то казалось что она обрабатывает IP адрес аппаратно. Но так даже лучше.
0
Ваще красавчек! СПАСИБО ;)
0
А можно поподробнее про трансформаторы TR1 и TR2? Я так понял, что H16105DF-R — это и есть эти фильтры, так? Просто дохлых/ненужных материнок/сетевых карт у меня нет — и их по-любому придется покупать. Вот из этих любой подойдет? Или лучше сразу magjack искать?
0
Судя по параметрам, они все одинаковые там, отличается только распиновка)

Ну если серийно нужно, конечно можно купить magjack или блок трансформаторов. Но, например, у себя поблизости я не нашёл, так что нужно искать/заказывать/ждать.

А для просто поиграться — проще взять с дохлой платы. Не думаю, что так сложно найти.
0
Можно, кстати, заказать magjack тут. Но придётся подождать. И за те же деньги можно купить 2 дряных dlink'овских сетевушки. Но зато 100% надёжно — точно будет работать и с распиновкой не придётся возиться.
0
разводку той платы из начала статьи, не выложите плиз?

Почитал комменты, интересно было бы услышать сравнение для
похожих чипов (и с какой реализацией внутри) сушествуют.
0
В терре разъем для СМД монтажа с трансами и светодиодами стоит примерно 150 рублей. Есть и не СМД. Так что найти и заказать — не большая проблема. В других магазинах тоже их видел.
0
Окей, все равно скоро собирался в митино съездить — там и посмотрю, что будет в наличии/дешевле; заказывать и ждать совсем не хочется, тем более за 5 евро+доставка. А насчет сетевых карт — у меня никогда ее не было и как-то не думал, что они бывают настолько дешевые))
0
посмотрите не дорогие
www.promelec.ru/vitrina_new/406/1262/1263/page3/
0
Какая модель?
0
мне пришла парочка HR961160C HANRUN
Пытаюсь все найти со встроенными диодными мостами для PoE, но только один даташит нашел…
0
С ними пришла еще парочка W5100. Буду курить на досуге…
0
Эту микруху спасает только паябельный корпус, ибо с таким количеством багов…
Ну и последний на сегодня баг ENC28J60 — при записи чётного значения в регистр ERXRDPT, ENC28J60 может повредить данные в буфере (кстати, адрес пакета всегда чётный из-за выравнивания).
Убило наповал.
0
А почему именно ENC? В чем плюсы по сравнению с другими аналогичными микрухами, дешевыми RTL, например?
0
Что за аналогичная дешёвая микруха от RTL?
0
В заключительной статье было упоминание про RTL8201BL, но при более внимательном рассмотрении, как я понял, этот RTL8201BL реализует только физический уровень, в то время как в ENC есть еще и канальный. Поправьте, если ошибаюсь. И все же интересно чем обоснован выбор именно этого Ethernet-контроллера, ведь он наверно не один в природе? Или этот самый популярный и доступный?
0
Да их как грязи вообщет. Есть от Withnet неплохие контроллеры (у W5100 вообще тспип встроенный аппаратно), от Cypress.

Обычно делают на том что под руку попадется. =)
0
так она в 3 раза дороже
0
Это для вас. У автора может быть совсем другие реалии.
0
Пытаюсь повторить проект в IAR. Все собралось нормально кроме непонятки с функцией sei(). Что это такое? очевидно это относится к AVR Studio. Какова ее роль?
0
Это включает прерывания)
ЕМНИП аналог в иаре — __enable_interrupt(); (хедер intrinsic.h).
Алсо всё-таки юзать avr-gcc. =)
0
Алсо всё-таки юзать avr-gcc. =)
всё-таки советую *
0
Спасибо. Все понял.

Алсо всё-таки юзать avr-gcc. =)

Да я и не против, но на IAR уже столько потрачено времени… Надежная штука. Надеюсь что он не подведет и в этом случае.
Да, дабы не менять все пришлось в файле enc28j60.h сделать так
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned long uint32_t;

Надеюсь это не должно вызвать у компилятора вопросов…
0
Всё равно придётся перейти на avr-gcc)
0
Уговорили. Если сразу пример (имеется ввиду пример UDP из следующего поста) на IAR не покатит попробую запустить его на AVR Studio. Я так понимаю именно на ней выполнен проект? Кстати спасибо за посты. Все очень интересно и профессионально.
Пока подключил эту штуку starterkit.ru/html/index.php?name=shop&op=view&id=57 к ATMega128.
Кварц 14.7MHz Может всеже сменить кварц на 8? Или и так должно пойти…
0
А почему таблица регистров из статьи отличается от таблица регистров из даташита?
narod.ru/disk/28068013001/ENC29J60_%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D1%81%D1%85%D0%B5%D0%BC%D0%B0.pdf.html — смотри page 12
0
Я так понимаю зависит от версии микросхемы. Тогда возникает вопрос как эту версию определить?
0
Непонимаю что тебе не нравится. Где ошибка-то?

Алсо зачем заливать шит на говнообменники, заставляющие вводить капчу, ждать, впаривающие какие-то сраные бары. Если религия не позволяет дать прямую ссылку на шит, залей на нормальный обменник.
0
Этот-то как раз еще ничего. Не заставляет ждать, реклама не настырная, быстрый, предупреждает «файл скоро протухнет». Разве что капча.
Хотя в данном случае стоило дать линк на сайт микрочипа, да.
0
На вскидку: в банке 4 по адресам 0х00...0х05 например, или банк 3 0х01.
Если внимательно посмотреть может еще чего найдется. Может это не принципиально, но всеже.
0
А, да. У тебя просто другая ревизия даташита. Приниципальных различий вроде бы нет. Добавил в конец статьи.
0
Забавно, несколько регистров внезапно переехали в reserved)

Хотя, если у них даже даташит версии С (последняя вроде) помечен как preliminary…
0
А как определить подходит этот даташит к моей микросхеме или нет?
0
Так что, никто не знает как определить версию микросхемы и какой даташит для нее нужен?
0
Самый свежий.
0
Чего самый свежий?
0
Даташит самый свежий.
А ревизию кристалла мона только прочитать из него самого. Регистр EREVID.
0
Подскажите пожалуйста инф. по схеме:
1) в даташите на ENC28J60 светодиоды подключены на GND (здесь они подключены на VNC 3.3В)- на что это влияет?
2) в качестве трансформатора H16105DF-R можно ли использовать какой нить из этих (тоже стоят в сетевых карточках): 16PT8515, LP-164C, FB2022.
3) использование резисторов (R3,R4,R5,R6) с 3-5% (вместо 1%) погрешностью критично?
0
1) МС автоматически определяет полярность диодов. Одновременно полярность определяет режим при запуске — полно- или полудуплексный (но это не очень существенно, т.к. можно потом программно поменять на нужный). Кстати, в этом модуле тоже есть ошибка и полярность может определиться неправильно. Как бороться — в эррате.
2) Скорее всего можно, а вообще-то в даташите указаны параметры требуемого трансформатора. Хотя у меня магджек с заметно отличающимия параметрами (конкретно — коэфф. трансформации RX 2.5:1 вместо 1:1), но работает. Возможно кстати, что резисторы R5 и R6 мне нужно поставить другие, но и с этими работает.
3) Вообще работает даже есть поставить 51 ом 5%. Но при этом форма сигнала не соответствует требованиям стандарта. Возможно снизится помехоустойчивость или максимальная длина кабеля (сопротивление резисторов намекает на то, что они согласующие, а рассогласование увеличивает потери сигнала из-за отражения). То же относится и к R7 — работает даже при больших отклонениях. Ну, по крайней мере на 10-метровом кабеле.
0
А в ST802RT1 только PHY? Т.е его можно использовать в связке с контроллером у которого есть MAC на борту.
Datasheet: www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATA_BRIEF/CD00216985.pdf
0
"… сетевой разъём с уже встроенными фильтрами («MagJack»). Деталька редкая и дорогая..." Позавчера выкупил подобное HY991101C в smd.ru за 109руб./шт. Но у меня другой вопрос: есть функциональный аналог CP220x Ethernet Controller ICs от silabs.com. Errata состоит из трех пунктов, что обнадеживает да и цена сопоставима с ENC28J60. Корпус QFN-28 или LQFP-48, что вполне приемлемо. Никто с подобными не работал? Хочу заложить их в следующий свой проект.
0
  • avatar
  • SMK2
  • 03 декабря 2011, 21:10
А что у них с ценой/доступностью/функционалом?
0
С ценой/доступностью/функционалом все хорошо, например, в Контесте (elecont.ru) CP2200-GQR LQFP-48 163.76р. — 573щт.; CP2201-GM QFN-28 222.55 р. — 35шт.; CP2201-GMR QFN-28 127р. — 691шт. В elitan.ru: CP2201-GMR@SILABS QFN28 1шт — 116р.; от 10шт. — 86,3р.; от 14шт. — 80.6р.; sbros — 73,4р./шт. Ethernet контроллер IEEE802.3MAC and 10BASE-T PHY (Vcc=3,1-3,6V, 8kb Flash, выводы совмест. с 5V I/O, LED-драйвер
Добавить в проект
0
функциональный аналог CP220x
не совсем, у него нет SPI
0
А какой у него интерфейс?
0
параллельный 8-битный
0
Добрый день.
А можете поделится печаткой модуля, который у Вас в этой статье на фото?
0
  • avatar
  • mcsa
  • 06 декабря 2011, 11:09
Доброго!
А кто нить запускал пример на STM32? Пробую iteadstudio.com/produce/enc28j60-ethernet-module-and-demo-codes/ свиду очень похоже. Ничего не работает, Мак не считывается. Может кто подскажет как быть?
0
  • avatar
  • Yeti
  • 17 января 2012, 16:37
Очень хочется печатку из статьи желательно в layout, хотя это не принципиально. Спасибо тем кто может поделиться, если уже сам реализовывал этот проект.
0
Спасибо за статью, сильно жизнь облегчила)). Вопросик есть. Набросал код по аналогии и смотрю, счетчик пакетов=0 и все тут. Пакеты начали поступать после отключения проверки crc в ERXFCON. Соответственно флаги в принятых пакетах тоже нифига не ОК. 90% жалуются на crc и 10% на несоответствие длины пакета. Это нормально? В принципе, заголовки у пакетов адекватные. В еррате вроде по данному вопросу не видать ничего. Проверил на 2х устройствах, одном самопальном и одном китайско-заводском. Результат один. Не встречалась такая ситуация никому?
0
А откуда посылаете пакеты на девайс?
С PC?
Это ненормально. Ревизия чипа какая?
0
С РС пингую несуществующий адрес и ловлю широковещательные пакеты. Девайс к РС через коммутатор коннектится, т.е. не на прямую. Хотя сейчас попробую напрямую посадить. Ревизия, на сколько я понял, 7-ая (EREVID = 0х06)
0
Что-то не вкурю никак… не отправляет пакеты и все тут. Пытаюсь ARP-ответ сделать. Пакет формирую из запроса, отправляю, линк отправки моргает, флаг ошибки отправки не появляется, но Wireshark ответа не видит… Косяк с контрольной суммой так и остался из предыдущего поста. Вот мысль есть, enc28 добавляет контрольную сумму к пакету, так вот если эта сумма будет тоже не верна Wireshark такой пакет покажет?
0
И еще вопрос: При приеме пакета в статусе: длина принятого фрейма 60 байт и в то же время флаг Length Out of Range (Indicates that frame type/length field was larger than 1500 bytes). Как это?
0
Здравствуйте пытаюсь повторить проект на меге128 подправил пины spi, перенастроил таймер, прерывания таймера работают. Фъюз совместимости с мегой103 снял, но проект не стартует, подскажите в чем может быть проблема, и какие регистры мк я забыл перенастроить
0
JTAG там еще включен однако по-умолчанию.
0
Пробывал проект на меге8, меге16, меге32 все работает а с мегой128 беда…
0
Вопрос к конденсаторам для 25МГц кварца — они обязательно должны быть 19пф или можно 22пф? просто 22 у меня есть в наличии
0
Это отдельный вопрос. Но если кратко — да, можно, в данном случае заметно это не повлияет.
0
+2
Здравствуйте. Помогите понять почему код не работает.

#define SPI_PORT PORTB
#define SPI_DDR DDRB
#define SPI_CS 4
#define SPI_MOSI 5
#define SPI_MISO 6
#define SPI_SCK 7

#include <avr/io.h>
#include «enc28j60.h»

int main(void)
{
DDRA = 0xFF;
PORTA = 0x00;
SPI_DDR = (1<<SPI_CS)|(1<<SPI_MOSI)|(0<<SPI_MISO)|(1<<SPI_SCK);
SPI_PORT = (1<<SPI_CS)|(1<<SPI_MOSI)|(1<<SPI_MISO)|(1<<SPI_SCK); — Выстявляем ноги

SPCR = (1<<SPE)|(1<<MSTR)|(0<<CPOL)|(0<<CPHA)|(1<<DORD)|(0<<SPR1)|(0<<SPR0);
SPSR = (0<<SPI2X); -----------РЕЖИМ 0 и двойная корость

SPI_PORT &= ~(1<<SPI_CS); — Начинаем передачу.
SPDR = (0b01000000|ECON1); — Говорим что хочем писать в ECON1 (выбирать банк)
while (!(SPSR & (1<<SPIF)));
SPDR = (0b00000000 | 0х03); — Передаем что банк 3.
while (!(SPSR & (1<<SPIF)));

unsigned char report;
SPDR = (0b00000000|EREVID); — говорим что хочу читать ревизию
while (!(SPSR & (1<<SPIF)));
report = SPDR; — приняли ревизию.
SPI_PORT |= (1<<SPI_CS); — Завершили передачу.

while(1){ — Так как у меня нету JTAG то проверяю принял что-то или нет просто засветив светодиод.
for (unsigned char i=0x00; i<0xFF; i++){
if (dt==i){
PORTA=0xFF;
}
}
}
return 0;
}

Прикол в том, что он не светит. Если написать i <= 0xFF (включительно) в условии цикла — то светодиод горит. Скажите что это может быть? Микроконтроллер работает на 16000000.
0
Скажите что это может быть?
В dt у вас 0xFF.
Что такое dt и зачем она нужна — думайте сами.
0
0
Репост удовлетворяет лицензии, под которой опубликован оригинал. Так что «спёрли» не подходит.
P.S.: Какие-то статьи когда-то были стянуты без разрешения с этого сообщества, сейчас же вроде поутихло.
0
Интересно, а под какой она лицензией? В первый раз слышу.
0
Заглючение, там есть фак, в нем написана лицензия wtf-что-то-там.
0
ТС, отредактируйте ссылку на большую схему подключения ENC28J60, уже давным-давно не работает.
0
Можете мне помочь по этой теме?
У меня есть железка DP83848, как подключить к STM32F4Discovery? Буду очень-очень благодарен за помощь. Если можно, напишите как можно с обширными пояснениями.
Спасибо.
0
если все еще актуально — могу проект скинуть где подключение есть
0
Если использовать сетевой разъём с уже встроенными фильтрами и трансформаторами из материнской платы ПК, имеет ли значение на какой скорности работала та сетевуха? (10/100/1000)
0
  • avatar
  • Miro
  • 25 августа 2013, 10:47
с гигабитом сложней а 10 и/или 100 подходит все
0
Да, выпаивается разъем от материнской платы, мягко сказать, очень не просто. даже со строительным феном получилось только отодрать отверткой от платы.
+1
  • avatar
  • Miro
  • 25 августа 2013, 11:07
У меня, двумя паяльниками и с помощью друга — получилось )
0
а у меня на газовой плите получалось))) ночью, чтоб никто не видел)))
0
Добрый день!
пытаюсь разобраться с микросхемой. не понимаю
#define enc28j60_rx() enc28j60_rxtx(0xff)

Это же по сути мягкий сброс? мы ведь отправляем 11111111. Как же осуществляется чтение? Чую, что я не понимаю))
0
Это мягкий сброс если идет в позиции команды. Скажем если выбрать енку (цс=0) и сразуже вызвать enc28j60_rx, то да, мы получим мягкий сброс.
Но здесь вызов enc28j60_rx предполагается не в позиции команды, а в позиции данных (после команды). С начала передается комманда, а уже затем в ответ на команду енка будет выдавать результат. Но т.к. спи 2-направленный, то что бы что-то считать мы должны что-то записать. Вкачестве «что-то записать» и используется 0xFF.
Если попробывать представить обмен, то будет выглядить так (передача произходит одновременно по 2-м линиям):
MOSI: CMDn 0xFF 0xFF
MISO: xxxx DATA DATA
При этом CMDn != 0xFF, и сами 0xFF в этом случае интерпретируются не как команда а как данные (которые в конкретном случае игнорируются).
0
спасибо большое! то есть заместо 0xff может спокойно быть всякая ересь))
постепенно врубаюсь в происходящее))
0
При подключении к незапитанной платой на сетевухе комповой и в компе появляется линк, я имею ввиду «Подключение по локальной сети» включено. Это нормально? Если запитать плату, то светодиод на плате один из двух горит постоянно, что с вставленным кабелем, что с вытащенным. Тот светодиод настроен на индикацию состояния линка. В конфигурации менял, чтоб дугой индицировал это состояние — индицирует также, горит (второй в это момент не светится). При чтении бита LSTAT показывает, что нет линка (равен 0). Правда трансформатор использовал внешний ML8512 от сетевухи. Даташита именно на него не нашел, нашел только очень похожий на 16РТ8512B. Пинга нет (проект из статьи про UDP-сервер). Вот ищу где ещё собака зарыта…
0
  • avatar
  • Flint
  • 25 августа 2014, 16:51
Исключил трансформатор, соединил напрямую — заработало, пинг пошел
0
никто не замечал, что при чтении MACON1, например, dummy byte тот же что и следующий за ним?
0
при нажатии на Увеличить схему

переходит на какой-то левый сайт
0
Здравствуйте. Статья и в правду интересная. Вот такой вопрос: не нашёл функцию enc28j60_write_phy(); в инициализации она используется, а вот что из себя представляет?

С уважением Алексей.
0
Видимо, эту функцию следует искать в приложенных сырках (ссылка в «заключении»). Как именно она работает кратко описано в разделе «Регистры MII».
0
Спасибо, нашёл. Я работаю в программе Code Vision AVR, поэтому пришлось немного редактировать. Вот такой ещё вопрос: функция инициализации void enc28j60_init(тут должен быть MAC адрес)? Если так, то почему 8-битная переменная объявлена (uint8_t *macadr)? А в сомой функции macadr как массив?
enc28j60_wcr(MAADR5, macadr[0]); // Set MAC address
enc28j60_wcr(MAADR4, macadr[1]);
enc28j60_wcr(MAADR3, macadr[2]);
enc28j60_wcr(MAADR2, macadr[3]);
enc28j60_wcr(MAADR1, macadr[4]);
enc28j60_wcr(MAADR0, macadr[5]);
0
uint8_t * — это указатель на uint8_t. А указатели в си — то же самое, что массивы.
0
Я с Вами согласен, но в Си (по крайней мере в CodeVision) массив указывается с размерностью (нумерацией), то есть macadr[6] это значит что массив состоит из шести значений. В данном случае этого нет, поэтому не ясно массив или переменная, если массив то из скольких значений? В функции указывается нумерация массива macadr[0], macadr[1] и т.д. а в инициализации enc28j60_init(uint8_t *macadr) — указывается просто 8-битная переменная macadr. Возможно это понятно для AVR Studio, но не людям. В любой литературе по Си написано что массив указывается с размерностью, в данном случае этого нет, поэтому такой вопрос и был. Так что это массив или переменная?
0
Это указатель на uint8_t. В данном случае он трактуется как указатель на массив uint8_t (си не делает различий между массивами и указателями).
0
uint8_t
u — unsigned — беззнаковое
int — integer — целое
8 — кол-во битов
_t — обозначение того что эта аббревиатура не макрос и не функция и не процедура а ТиП!

О массиве и слова нет.
Производные типы от стандартных в языке Си для компилятора AVR-GCC
uint8_t — unsigned char, но негде ни слова нет что это массив. Откройте библиотеку AVR-GCC, и посмотрите,
Это указатель на uint8_t. В данном случае он трактуется как указатель на массив uint8_t
— не соглашусь, даже в AVR Studio массив обозначается uint8_t tmp[10]={....}; То есть это простая 8-битная переменная, а в функции указывается массив. Вы мне не ответили на вопрос. Извиняюсь за свою назойлевость, но это факт.
Это указатель на uint8_t. В данном случае он трактуется как указатель на массив uint8_t
— это не ответ, и не подтверждение что относится к разряду массива.
0
uint8_t *macadr — это указатель на конкретный байт в памяти, в этом же месте памяти (с этого же байта) начинается массив (поименованная область памяти) macadr, т.е. это указатель на macadr[0] — 1-й байт массива macadr.
0
Тем, кто писал до этого на java/javascript или Basic — это не понятно, но тому, кто работал с массивами(и вообще, любыми областями памяти) на asm — эта адресная арифметика Си — яснса, как божий день, т.к. все дешевые фокусы Си взяты из ассемблера.
+1
Если я правильно понял дискуссию выше, то вам стоит взять справочник по Си и почитать главы о том как связаны указатели и массивы, и как организуется передача массива в функцию.
+1
Alexl81, вам надо пописать на денек-два на asm — и все с пониманием Си встанет после этого не место. Лучше всего (именно в учебных целях понимания сути) для MSP430 — его asm и методы адресации CPU чем-то похожа на ones в древней машине PDP-11, на которой и писался этот самый Си.
0
В своём описании ты звёздочку забыл "*" после uint8_t — она и указывает что перед тобой указатель
+1
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.