Урок 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 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN Сетевой Модуль.
Переходник USB to TTL можно приобрести здесь ftdi ft232rl
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Sir why you didn't use LWIP TCP/ip stack with ENC28j60?
Please make tutorial on ENC28j60 with LWiP TCP/ip stack