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

 

 

 

 

Урок 40

 

Часть 7

 

LAN. ENC28J60

 

 

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

 

Теперь в функции arp_read  добавим в тело условия отображение типа запроса, адресов источника и адресов приёмника, и установим результат

 

if( (msg->op == ARP_REQUEST) && (msg->ipaddr_dst == IP_ADDR) )

{

  sprintf(str1,"requestrnmac_src %02X:%02X:%02X:%02X:%02X:%02Xrn",

  msg->macaddr_src[0], msg->macaddr_src[1], msg->macaddr_src[2], msg->macaddr_src[3], msg->macaddr_src[4], msg->macaddr_src[5]);

  USART_TX((uint8_t*)str1,strlen(str1));

  sprintf(str1,"ip_src %ld.%ld.%ld.%ldrn",

  msg->ipaddr_src & 0x000000FF, (msg->ipaddr_src>>8) & 0x000000FF, (msg->ipaddr_src>>16) & 0x000000FF, msg->ipaddr_src>>24);

  USART_TX((uint8_t*)str1,strlen(str1));

  sprintf(str1,"mac_dst %02X:%02X:%02X:%02X:%02X:%02Xrn",

  msg->macaddr_dst[0], msg->macaddr_dst[1], msg->macaddr_dst[2], msg->macaddr_dst[3], msg->macaddr_dst[4], msg->macaddr_dst[5]);

  USART_TX((uint8_t*)str1,strlen(str1));

  sprintf(str1,"ip_src %ld.%ld.%ld.%ld",

  msg->ipaddr_dst & 0x000000FF, (msg->ipaddr_dst>>8) & 0x000000FF, (msg->ipaddr_dst>>16) & 0x000000FF, msg->ipaddr_dst>>24);

  USART_TX((uint8_t*)str1,strlen(str1));

  res=1;

}

 

Ну тут всё просто. Только есть один вопрос. С какой стати какое-то устройство будет нам посыть ARP-запрос, мы же ведь никому не говорили о нашем IP-адресе.

А мы ему поможем. Мы воспользуемся утилитой ping, встроенной в любую операционную систему. Хотя ping посылает ICMP-запрос, но если он видит, что в таблице соответствия адресов ARP нет нашего IP-адреса, то сначала он посылает ARP-запрос.

Поэтому мы и пошлём ping на назначенный нами IP-адрес из командной строки, понятное дело, собрав перед этим код и прошив контроллер.

 

image03

 

Мы видим, что наша плата на ping не откликнулась, но это ничего страшного, мы же ведь не писали ответ не только на ICMP-запросы, но и на ARP, но зато мы вот что видим в нашей терминальной программе

 

image04

 

Мы видим и физический и сетевой адреса устройства, пославшего нам запрос (это наш основной ПК с адресом 192.168.1.89), а также сетевой адрес приёмника. Так как физический адрес приёмника пока неизвестен, то мы получаем нулевой адрес.

Очередная задача, стоящая перед нами — ответить на ARP-запрос.

Но мы помним, что мы написали только функцию приёма пакетов Ethernet (или кадров). А чтобы на что-то ответить, мы должны уметь также такие пакеты отправлять. Поэтому нам прийдётся вернуться в файл enc28j60.c и добавить функцию для передачи пакетов

 

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

void enc28j60_packetSend(uint8_t *buf, uint16_t buflen)

{

}

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

 

 

Подождём, пока установится бит TXRTS в регистре ECON1, что означает готовность нашего передатчика передавать информацию

 

void enc28j60_packetSend(uint8_t *buf, uint16_t buflen)

{

  while (enc28j60_readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)

  {

  }

}

 

Дальше борьба с ошибкой микросхемы, согласно которой бит TXRTS сам не сбрасывается. Мы сначала проверяем регистр EIR на установку бита TXERIF, а затем сбрасываем бит

 

while (enc28j60_readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)

{

  if (enc28j60_readRegByte(EIR) & EIR_TXERIF)

  {

    enc28j60_writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);

    enc28j60_writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);

  }

}

 

Добавим функцию записи в буфер

 

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

static void enc28j60_writeBuf(uint16_t len, const uint8_t* data) {

  SS_SELECT();

  SPI_SendByte(ENC28J60_WRITE_BUF_MEM);

  while (len—)

  SPI_SendByte(*data++);

  SS_DESELECT();

}

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

 

Продолжаем функцию отправки пакета. Затем записываем и отправляем пакет

 

      enc28j60_writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);

    }

  }

  enc28j60_writeReg(EWRPT, TXSTART_INIT);

  enc28j60_writeReg(ETXND, TXSTART_INIT+buflen);

  enc28j60_writeBuf(1,(uint8_t*)"\x00");

  enc28j60_writeBuf(buflen, buf);

  enc28j60_writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);

}

 

Добавим прототип данной функции в заголовочный файл и вернёмся в net.c. В фунцкии eth_read немного исправим код, чтобы отправлять ответ ARP только в случае, если модуль узнает свой адрес

 

USART_TX((uint8_t*)"; arp",5);

if(arp_read(frame, len sizeof(enc28j60_frame_ptr)))

{

}

 

Добавим физический адрес нашего устройства, унаследовав его из другого модуля

 

uint8_t net_buf[ENC28J60_MAXFRAME];

extern uint8_t macaddr[6];

 

Добавим функцию для отправки кадра по протоколу Ethernet куда-нибудь повыше, в которой мы установим физические адреса источника и приёмника, а затем отправим пакет

 

//———————————————————

void eth_send(enc28j60_frame_ptr *frame, uint16_t len)

{

  memcpy(frame->addr_dest, frame->addr_src, 6);

  memcpy(frame->addr_src, macaddr, 6);

  enc28j60_packetSend((void*)frame, len + sizeof(enc28j60_frame_ptr));

}

//———————————————————

 

Добавим также функцию отправки ответного пакета ARP сразу после функции eth_send

 

//———————————————————

void arp_send(enc28j60_frame_ptr *frame)

{

}

//———————————————————

 

В следующей части нашего урока мы наконец-то ответим на запрос ARP, а также изучим заголовок протокола IP.

 

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

 

 

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

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

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

 

 

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

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

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

 

 

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

 

AVR LAN. ENC28J60

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

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

*