AVR Урок 41. LAN. ENC28J60. ARP. Часть 1



 

Урок 41

 

Часть 1

 

LAN. ENC28J60. ARP

 

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

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

Напрашивается при этом вполне логичный вопрос: «А зачем нам это, мы же это уже проделали на пршлом занятии?». А на вопрос есть ответ. Мы это делали в одном направлении. То есть мы обеспечивали выполнение этой задачи только в том случае, если внешнему устройству нужно было узнать физический адрес нашего устройства. То есть мы создали своего рода ARP-сервер. Но нужен нам также и ARP-клиент, с помощью которого уже наш модуль будет пытаться узнать сетевой адрес какого-то внешнего устройства. Причём клиент на практике возможно будет даже нужен чаще, так как без этого мы не сможем ничего запросить у других устройств, так как ни один физический адрес внешних устройств мы не знаем. То есть мы даже передать ничего не сможем, так как, учитывая вышенаписанное, нам и передать-то некуда. Так что вот такой ответ. Поэтому продолжаем.

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

Но сначала недочёты.

Во-первых, чтобы у нас сохранился проект предыдущего занятия, давайте теперь дадим проекту, который мы будем продолжать на сегодняшнем занятии, новое имя. Создадим новый проект и назовём его ENC28J60_ARP. Все файлы с исходными кодами, кроме main.c, мы скопируем из предыдущего проекта ENC28J60 и подключим их проект, а код из файла main.c прошлого проекта мы скопируем в одноимённый файл нового проекта, перед этим полностью очистив его от нового текста.

Попробуем собрать код. Если всё нормально и без ошибок собралось, то как и договорились, начнём исправлять недочёты, для чего перейдём в файл enc28j60.c, найдём в нём функцию enc28j60_readOp и увидим в ней, что ложный байт мы вовсе и не пропустили. Мы сначала использовали соответствующую функцию SPI_SendByte, которая отправила 0 в модуль, и если пройти по коду данной функции, то она в регистр SPDR записала значение из модуля, то есть всё равно обмен произошел, а дальше мы просто считали значение из регистра, тем самым мы ничего не пропустили, никаких ложных байтов. Поэтому изменим код на следующий.

Сначала заранее объявим локальную переменную

 

static uint8_t enc28j60_readOp(uint8_t op,uint8_t addres)

{

  uint8_t result;

 

А затем уже исправим код

 

//пропускаем ложный байт

if(addres & 0x80) SPI_ReceiveByte();

result=SPI_ReceiveByte();

SS_DESELECT();

 

Вот теперь в случае присутствия логической 1 в байте 7 мы уже проделаем обмен дважды, а в обычном случае — только единожды.

 

 

Теперь перейдём в хедер-файл enc28j60.h и добавим там ещё один регистр в 3 банк

 

#define MISTAT (0x0A|0x60|0x80)

#define ECOCON (0x15|0x60)

//--------------------------------------------------

 

вернёмся в enc28j60.c и в функции инициализации в самом конце мы уменьшим вдвое частоту генератора и после этого немного подождём

 

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

  //Включим делитель частоты генератора 2, то есть частота будет 12,5 MHz

  enc28j60_writeRegByte(ECOCON,0x02);

  _delay_us(15);

}

 

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

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

 

  enc28j60_writeOp(ENC28J60_BIT_FIELD_SET,ECON1,ECON1_TXRTS);

  //небольшая задержка, почему-то без неё не работает в загруженных сетях

  _delay_ms(1);

}

 

Пока с поправками всё.

 

 

Давайте теперь как-то весь функционал ARP вынесем в отдельный модуль, для чего создадим файлы arp.c и arp.h и подключим их к проекту.

Первоначальное содержание данных файлов стандартное:

 

arp.c

 

#include "arp.h"

//--------------------------------------------------

 

arp.h

 

#ifndef ARP_H_

#define ARP_H_

//--------------------------------------------------

#include <string.h>

#include "enc28j60.h"

#include "net.h"

#include "usart.h"

//--------------------------------------------------

//--------------------------------------------------

#endif /* ARP_H_ */

 

Теперь нам эту новую библиотеку нам надо как-то подключить. А почему как-то, потому что необычно, иначе будут ошибки.

Перейдём в заголовочный файл net.h и и подключим наш новый модуль в самом низу файла (это очень важно)

 

//--------------------------------------------------

#include "arp.h"

//--------------------------------------------------

#endif /* NET_H_ */

 

Теперь из файла net.c в файл arp.c перенесём сначала весь код функции arp_read, конечно удалив затем этот код из файла-источника, также в заголовочном файле arp.h создадим на данную функцию прототип. Теперь, чтобы данная функция работала, мы также в файл arp.c добавим глобальную переменную, вернее мы подключим готовую, чтобы не занимать много памяти

 

#include "arp.h"

//--------------------------------------------------

extern char str1[60];

//--------------------------------------------------

 

То же самое проделаем и с функцией arp_send и также добавляем на неё прототип. Но так как данная функция использует вызов функции eth_send, которая осталась в другом файле, то на неё мы также сделаем прототип в файле net.h причём внизу файла перед подключением файла arp.h

 

//--------------------------------------------------

void eth_send(enc28j60_frame_ptr *frame, uint16_t len);

//--------------------------------------------------

#include "arp.h"

 

Также давайте подключим переменную с MAC-адресом в этот же файл arp.c

 

extern char str1[60];
extern uint8_t macaddr[6];
//--------------------------------------------------

 

В следующей части нашего занятия мы обработаем приём строки с IP-адресом из шины USART и произведём её преобразование в числовую величину.

 

 

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

 

 

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

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

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

 

 

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

Приобрести программатор USBASP USBISP с адаптером можно здесь USBASP USBISP 3.3 с адаптером

Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN Сетевой Модуль.

 

 

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

AVR LAN. ENC28J60. ARP

 

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

AVR LAN. ENC28J60. ARP

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

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

*