AVR Урок 40. LAN. ENC28J60. Часть 3

 

 

 

 

Урок 40

 

Часть 3

 

LAN. ENC28J60

 

 

В предыдущей части нашего урока мы написали ещё несколько макросов и функций для работы с микросхемой.

 

При операции чтения мы читаем регистр ESTAT на предмет установки бита CLKRDY.

Напишем функцию чтения буфера (см. таблицу 4.1 выше)

 

//—————————————-

static void enc28j60_readBuf(uint16_t len, uint8_t* data)

{

  SS_SELECT();

  SPI_SendByte(ENC28J60_READ_BUF_MEM);

  while (len—) {

    SPI_SendByte(0x00);

    *data++ = SPDR;

  }

  SS_DESELECT();

}

//—————————————-

 

Создадим переменную для хранения номера текущего банка

 

#include "enc28j60.h"

//———————————————-

static uint8_t Enc28j60Bank;

 

Ну и, соответственно, напишем функцию установки текущего банка

 

//—————————————-

static void enc28j60_SetBank (uint8_t address)

{

  if ((address & BANK_MASK) != Enc28j60Bank)

  {

    enc28j60_writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_BSEL1|ECON1_BSEL0);

    Enc28j60Bank = address & BANK_MASK;

    enc28j60_writeOp(ENC28J60_BIT_FIELD_SET, ECON1, Enc28j60Bank>>5);

  }

}

//—————————————-

 

Попробуем разобраться в том, что здесь происходит.

Ну, во первых, если у нас уже текущий банк равен тому, который мы хотим установить, то мы ничего не делаем и уходим

А затем мы в регистре ECON1 очищаем биты BSEL1 и BSEL0, отвечающие за банк, затем заносим в переменную наш банк из адреса, сдвигаем полученное значение вправо на 5 пунктов для того, чтобы нужные биты оказались в младших, и устанавливаем соответствующие биты в том же регистре

 

image08

 

Затем напишем универсальные функции для чтения и записи обычных регистров управления

 

//—————————————-

static void enc28j60_writeRegByte (uint8_t address, uint8_t data)

{

  enc28j60_SetBank(address);

  enc28j60_writeOp(ENC28J60_WRITE_CTRL_REG, address, data);

}

//—————————————-

static uint8_t enc28j60_readRegByte (uint8_t address)

{

  enc28j60_SetBank(address);

  return enc28j60_readOp(ENC28J60_READ_CTRL_REG, address);

}

//—————————————-

 

Буфер, работающий и на чтение и на запись, необходимо настроить также с помощью регистров

 

image09

 

 

Так как все указатели у нас двухбайтовые, то создадим ещё функцию для записи данных в такие регистры

 

//—————————————-

static void enc28j60_writeReg(uint8_t address, uint16_t data)

{

  enc28j60_writeRegByte(address, data);

  enc28j60_writeRegByte(address + 1, data >> 8);

}

//—————————————-

 

Настроим буферы в функции инициализации

 

;

//настроим буферы

enc28j60_writeReg(ERXST, RXSTART_INIT);

enc28j60_writeReg(ERXRDPT, RXSTART_INIT);

enc28j60_writeReg(ERXND, RXSTOP_INIT);

enc28j60_writeReg(ETXST, TXSTART_INIT);

enc28j60_writeReg(ETXND, TXSTOP_INIT);

 

Включим broadcast, вдруг пригодится

 

enc28j60_writeReg(ETXND, TXSTOP_INIT);

//Enable Broadcast

enc28j60_writeRegByte(ERXFCON, enc28j60_readRegByte(ERXFCON) | ERXFCON_BCEN);

 

Также можно включить фильтрацию пакетов с проверкой контрольной суммы с помощью определённых регистров EPMM0-EPMM7 и EPMMCS, но пока мы этого делать не будем, мы хотим видеть все пакеты. Если будет впоследствии это нужно, то мы всегда успеем отфильтровать. Просто я хочу отметить, что наша микросхема очень хорошо умеет фильтровать пакеты по маске и контрольной сумме.

Добавим в наш файл глобальную переменную нашего физического адреса

 

static uint8_t Enc28j60Bank;

uint8_t macaddr[6] = MAC_ADDR;

 

Ну и, соответственно, настроим канальный уровень в инициализации

 

enc28j60_writeRegByte(ERXFCON, enc28j60_readRegByte(ERXFCON) | ERXFCON_BCEN);

//настраиваем канальный уровень

enc28j60_writeRegByte(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);

enc28j60_writeRegByte(MACON2, 0x00);

enc28j60_writeOp(ENC28J60_BIT_FIELD_SET, MACON3,

MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);

enc28j60_writeReg(MAIPG, 0x0C12);//

enc28j60_writeRegByte(MABBIPG, 0x12);//промежуток между фреймами

enc28j60_writeReg(MAMXFL, MAX_FRAMELEN);//максимальный размер фрейма

enc28j60_writeRegByte(MAADR5, macaddr[0]);// Set MAC address

enc28j60_writeRegByte(MAADR4, macaddr[1]);

enc28j60_writeRegByte(MAADR3, macaddr[2]);

enc28j60_writeRegByte(MAADR2, macaddr[3]);

enc28j60_writeRegByte(MAADR1, macaddr[4]);

enc28j60_writeRegByte(MAADR0, macaddr[5]);

 

Кратко о том, что здесь происходит.

У нас есть четыре регистра для настройки данного уровня MACON1-MACON4, хотя в документации только 3, второго нет

 

image10

Поэтому во второй мы отправим все нули.

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

В третьем регистре включим паддинг, или выравнивание. Для этого есть три бита PADCFG, в них мы включим 001 для выравнивание пакета нулями до 60 байт и добавления контрольной суммы 4 байта. Также здесь мы включаем биты FRMLNEN, который автоматически проверяет длину пакетов и TXCRCEN, который автоматически добавляет к пакету контрольную сумму.

Дальше идут стандартные значения регистров MAIPG и MABBIPG, устанавливающих для полнодуплекстного режима определённые задержки.

Затем MAMXFL, который устанавливает значения максимального размера фрейма (кадра).

Ну а дальше, я думаю, всем понятно, что мы обязаны занести в регистры наш MAC-адрес.

Дальше работаем с физическим уровнем.

Здесь не так всё просто.

Оказывается, чтобы занести значение в один из регистров, управляющих физическим уровнем (PHY), нужно это делать не напрямик, так как нет такой возможности, а через регистры MII.

У нас есть такой регистр MIREGADR, в который мы сначала обязаны занести значение адреса того или иного регистра PHY. А затем данные, предназначенные для этого регистра, мы заносим в регистры MIWRL (младший байт) и MIWRH (старший байт), причём именно в такой последовательности. Затем читаем регистр MISTAT на предмет сброса бита BUSY. Вот так вот.

Поэтому напишем отдельную функцию для записи регистра PHY

 

//—————————————-

static void enc28j60_writePhy (uint8_t address, uint16_t data) {

  enc28j60_writeRegByte(MIREGADR, address);

  enc28j60_writeReg(MIWR, data);

  while (enc28j60_readRegByte(MISTAT) & MISTAT_BUSY)

  ;

}

//—————————————-

 

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

 

В следующей части нашего урока мы закончим инициализацию микросхемы, а также напишем ещё некоторые нужные функции.

 

Предыдущая часть Программирование МК AVR Следующая часть

 

 

Техническая документация:

Документация на микросхему ENC28J60

Перечень ошибок ENC28J60 (Errata)

 

 

Приобрести плату Atmega 328p Pro Mini можно здесь.

Программатор (продавец надёжный) USBASP USBISP 2.0

Ethernet LAN Сетевой Модуль можно купить здесь (модуль SD SPI в подарок) ENC28J60 Ethernet LAN Сетевой Модуль.

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR LAN. ENC28J60

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*