Урок 68
Часть 7
LAN. ENC28J60
В предыдущей части нашего урока мы мы написали структуру для заголовка ARP, а также написав функцию исследования данного протокола, увидели некоторые части заголовка принятого ARP-запроса в терминальной программе.
Очередная задача, стоящая перед нами — ответить на 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)
{
{
}
//--------------------------------------------------
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,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 только в случае, если ARP-запрос вернёт единицу
if(frame->type==ETH_ARP)
{
...
if(arp_read(frame,len-sizeof(enc28j60_frame_ptr)))
{
}
}
Добавим физический адрес нашего устройства в net.c, унаследовав его из другого модуля
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_send занесём в ARP-заголовок код ответа ARP
void arp_send(enc28j60_frame_ptr *frame)
{
arp_msg_ptr *msg = (void*)frame->data;
msg->op = ARP_REPLY;
анесём также в заголовок физические адреса
msg->op = ARP_REPLY;
memcpy(msg->macaddr_dst,msg->macaddr_src,6);
memcpy(msg->macaddr_src,macaddr,6);
Затем занесём IP-адреса
memcpy(msg->macaddr_src,macaddr,6);
memcpy(msg->ipaddr_dst,msg->ipaddr_src,4);
memcpy(msg->ipaddr_src,ipaddr,4);
И в завершении функции отправим пакет
memcpy(msg->ipaddr_src,ipaddr,4);
eth_send(frame,sizeof(arp_msg_ptr));
}
В функции eth_read ответим на ARP-запрос
if(arp_read(frame,len-sizeof(enc28j60_frame_ptr)))
{
arp_send(frame);
}
Соберём код, прошьём контроллер. Для того, чтобы увидеть наш ответ, желательно установить бесплатную программу Wireshark. Это анализатор сетевых пакетов.
Установим в данной программе фильтр только на пакеты arp
Пропинугем наш IP-адрес таким же образом, как и прежде. Ответа на пинг мы не получим, но на запрос ARP в утилите мы увидим ответ
Можно также открыть и посмотреть структуру пакета ARP
Также в таблице соответствия адресов ARP компьютера мы видим теперь наши данные
В следующей части нашего урока мы поработаем над протоколом IP, а также научимся рассчитывать контрольную сумму заголовка и напишем для этого функцию.
Предыдущая часть Программирование МК STM32 Следующая часть
Техническая документация:
Документация на микросхему ENC28J60
Перечень ошибок ENC28J60 (Errata)
Отладочную плату можно приобрести здесь STM32F103C8T6
Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN
Переходник USB to TTL можно приобрести здесь USB to TTL ftdi ft232rl
Смотреть ВИДЕОУРОК (нажмите на картинку)
Sir why you didn't use LWIP TCP/ip stack with ENC28j60?
Please make tutorial on ENC28j60 with LWiP TCP/ip stack