Фред ИДИ (Fred EADY) Перевод: Дмитрий ИОФФЕ
Учебный курс
по WIZnet W5100
Вы готовы присоединиться к интернет-революции? Если да, то настало время работать с сетевым контроллером с аппаратной реализацией стека TCP-IP W5100 фирмы WIZnet. В этой статье автор рассказывает, как начать ваш первый проект на W5100. Перевод статьи Фреда Иди (Fred Eady) “iEthernet Bootcamp”, Circuit Cellar, Issue 208, опубликованной в ноябре 2007 года.
Недавно я получил письмо от читателя, который спрашивал, почему нет подробных статей о реализации TCP-IP с практическими рекомендациями. Честно говоря, я никогда не думал об этом, потому что обычно предпочитаю формальному стеку TCP-IP небольшие, понятные, пригодные для работы в домашних условиях Ethernet-драйверы. Как журнальный автор, я в первую очередь предположил, что нехватка литературы по стеку TCP-IP вызвана победой стоимости над интересом. Мне приходилось рассматривать много коммерческих предложений реализации стека TCP-IP, и, опираясь на свой опыт, я могу утверждать, что вы получаете то, за что платите. Мои читатели просто не могут позволить себе оплатить полнофункциональный стек TCP-IP для своих приложений и проектов. Таким образом, почему я должен предлагать им читать о том, что они не могут позволить себе использовать?
Вторая причина непопулярности статей о стеке TCP-IP в журнале — его сложность. Кто писал для журналов, тот знает, что количество слов в статье ограничено. Для объяснения всего того, что надо знать о стеках TCP-IP, потребуется целая серия статей.
Должен признать, что раньше я предлагал в своих статьях некоторые довольно дорогие вещи. Но сейчас, в силу указанных причин, стараюсь этого избегать. Однако когда я вижу что-то полезное для типичного читателя технических журналов, то стараюсь следить за этим. Например, я обнаружил, что среди читателей Circuit Cellar очень популярны микросхемы для Ethernet с поддержкой свободных стеков TCP-IP. Также я увидел, что многие читатели, разрабатывающие однокристальные Ethernet-устройства, даже не используют стек TCP-IP. Вместо этого они, так же как и я, используют простые драйверы протоколов, специально написанные для однокристальных Ethernet-устройств, которые они применяют в своих проектах. Я практикую то, что исповедую, и то, о чем собираюсь вам рассказать, — это самый лучший в мире «гаражный» драй-
вер Ethernet и TCP-IP стек. Вы хотите использовать в своем устройстве однокристальное Ethernet-решение, обеспечивающее всю мощь коммерческих полнофункциональных TCP-IP стеков в простом драйвере Ethernet? Тогда читайте дальше.
WIZnet W5100
Микросхема WIZnet W5100 — это однокристальное Ethernet-решение со встроенным стеком TCP-IP. Такой стек часто называют «зашитым». Все замечательные возможности для доступа в Интернет, которые предоставляет W5100, помещаются в компактном 80-выводном корпусе LQFP. Кроме встроенного стека TCP-IP, W5100 содержит встроенную IEEE 802.3 10Base-T и 802.3u 100Base-TX совместимую реализацию MAC и PHY уровней. Можно ожидать, что раз стек TCP-IP обеспечивает все необходимое, то устройство можно сразу подключить к сети Ethernet. Стек TCP-IP в W5100 поддерживает протоколы TCP, UDP, ICMP и ARP. Этого достаточно для большинства встроенных сетевых Ethernet-приложений, разрабатываемых обычными пользователями. Кроме того, устройство W5100 поддерживает PPPoE, что позволяет использовать его в приложениях ADSL.
Если вы когда-либо экспериментировали со встроенными Ethernet-устройствами, то знаете, что нехватка буферной памяти при приеме или передаче может оказаться болезненной и уменьшить производительность вашего устройства. Производители встроенных устройств для Ethernet знают об этом. Большинство однокристальных Ethernet-решений, предлагаемых в настоящее время, содержит достаточное количество специальной буферной памяти для приема и передачи. Микросхема W5100 не является исключением и имеет 16 кбайт внутренней буферной памяти.
Для обеспечения работы с небольшими микроконтроллерами в W5100 предусмотрено три способа обмена информацией с управ-
ляющим микроконтроллером: через SPI и при помощи прямого или косвенного доступа к памяти. Для лучшей совместимости с большинством современных микроконтроллеров напряжение питания W5100 сделано равным 3,3 В. Это позволяет непосредственно подключаться к малопотребляющим микроконтроллерам, которые тоже питаются от этого напряжения. Микросхема W5100 может также работать с разработанными ранее системами с напряжением питания 5 В, потому что ее подсистема ввода/вывода может выдерживать такое напряжение.
W5100 поддерживает до четырех одновременно активных сокетов. Таким образом, все, что пользователь должен знать, — это основы программирования сокетов, потому что W5100 разработана так, чтобы как можно удобнее предоставить все необходимое для работы встроенного устройства с Ethernet. Единственное, что W5100 не сделает для пользователя, — это написание его собственного кода и обработку фрагментации IP-пакетов.
Случайно у меня оказалось несколько микросхем W5100. Давайте создадим устройство на W5100 с нуля. Когда у нас получится аппаратная часть, мы добавим немного кода драйвера для микроконтроллера PIC18LF8722 фирмы Microchip Technology, установленного на нашей отладочной плате.
Устройство отладочной платы
Для удобства я предлагаю проект печатной платы на W5100 (рис. 1), разработанный для фирмы EDTP Electronics. У PIC18LF8722 достаточно способностей, чтобы обеспечить доступ к регистрам W5100 и буферной памяти в любом из режимов на выбор: прямой доступ, косвенный доступ, SPI. При использовании PIC18LF8722, кроме того, в наше распоряжение попадает мощный набор средств разработки от фирмы Microchip. Файл проекта лежит на FTP-сервере Circuit Cellar в формате ExpressPCB. Я выбрал ExpressPCB потому, что этот сервис относительно недорог и доступен каждому.
I : : V ІІ Ж-
ддв: . V>" U Чі-У Т
WIZne
’1 • 1^ -т* -.і an і і ■
Рис. 1. Отладочная плата с WIZnet W5100 на микроконтроллере PIC18LF8722 фирмы Microchip Technology
Программное обеспечение ExpressPCB загружается бесплатно, и качество получаемых печатных плат очень высокое. Другой плюс, связанный с использованием ExpressPCB, — это то, что вам не понадобится разрабатывать плату для W5100 с нуля. Можно использовать мой шаблон ExpressPCB и доработать его под свою задачу. Если у вас уже есть любимая САПР для подготовки печатных плат, можно легко перенести предлагаемый проект в вашу САПР, используя мой чертеж как руководство.
Проект для EDTP Electronics основан на микроконтроллере PIC18LF8722 в стандартной конфигурации, который подключен к базовой конфигурации W5100. Как можно увидеть на рис. 2, у PIC18LF8722 с запасом хватает выводов, чтобы подключиться к 15-разрядной адресной шине W5100, 8-разрядной шине данных и всем управляющим сигналам (*RD, *WR, *CS и *INT). В дополнение к соединениям для подключения к W5100 в режиме прямого доступа (A0:A14, D0:D7 и управляю-
щие сигналы) я подключил порт SPI и вывод разрешения SPI у W5100 к интерфейсу ввода/вывода SPI-микроконтроллера PIC18LF8722. Это позволит нам получить доступ к внутренностям W5100 в режиме SPI. Режим косвенной адресации, для которого требуются только две адресные линии, все восемь линий данных и все управляющие сигналы, в проекте EDTP тоже легко организовать, так как адресные линии притянуты к «земле» внутри W5100.
Все 80 линий ввода/вывода и питания PIC18F8722 разведены группами по 20 выводов со стандартным шагом 0,1". Доступ к микроконтроллеру обеспечивается через сертифицированный фирмой Microchip модуль программирования/отладки с тактовой частотой 20 МГц и порт RS-232. Я не включил в комплект никаких источников питания, потому что в продаже более чем достаточно готовых стабилизаторов с выходным напряжением 3,3 В, которые требуются для питания платы с W5100, и внешней аппаратуры для программирования и отладки.
Рядом с микросхемой W5100 на отладочной плате EDTP расположен необходимый для нее кварцевый резонатор на 25 МГц, а также экранированный разъем для сетевого кабеля со встроенным трансформатором (рис. 3). Я выбрал разъем RDI-125BAG1A фирмы U. D. Electronic из следующих соображений. Во-первых, посадочное место под RDI-125BAG1A в точности совпадает с посадочным местом под импульсный трансформатор, которое у меня уже было в библиотеке ExpressPCB. Во-вторых, в нем, кроме пары импульсных трансформаторов для приема и передачи и на-
грузочных резисторов, есть еще пара встроенных светодиодных индикаторов. Если вы когда-либо работали с отладочными платами для Ethernet от EDTP, сделанными на ASIX или Microchip, то заметите, что соединения физического уровня W5100 очень похожи на те, что используются в EDTP Electronics ASIX и Microchip ENC29J60.
Вы можете спросить, почему для встроенного в W5100 источника напряжения 1,8 В не предусмотрено никаких развязывающих компонентов. Этот вопрос часто задают службе поддержки. Однако если мы посмотрим на схему включения W5100 из фирменного руководства, то там тоже не увидим развязки по питанию 1,8 В.
Так как отладочная плата для WIZnet W5100 от EDTP предназначена для того, чтобы помочь максимально быстро создать свой проект и запустить его, я подключил светодиоды ко всем индикаторным линиям W5100. Пара светодиодов, встроенных в разъем RDI-125BAG1A, подключена к линиям состояния LINKLED и RXLED. К линиям TXLED, COLLED, FDXLED и SPDLED я подключил дискретные светодиоды, которые можно видеть на рис. 1 среди компонентов типоразмера 0805, окружающих WIZnet W5100. Я также предусмотрел джампер для выбора режима SPI в W5100, если вам этот режим потребуется. Единственная причуда, на которую я должен обратить ваше внимание, — это два резистора сброса номиналом 12,3 кОм, показанные на рис. 3, которые подключены к выводу RSET_BG W5100. Общий вид той части отладочной платы EDTP, которая относится
С6| |0,1 МКФ
+3,3 В DC
С5 -0,1 мкФ'
сз
0,1
мкФ
из II
С1+ VDD
R10UT
С1- T1IN
С2+ T2IN
R20UT
T20UT
С2— R2IN
V-
T10UT
V+ R1IN
GND
RS-232 Connector
АО___
ур.
/A3
/A4
/А5
/А6
/Ä7
/-----
А8___
/А9
/Ш~
/А11
/А12
/А13
/АЇ4-
/
/
36 _35_| 4Г
____44
____45
46
37
RAO/ANO
RA1/AN1
RA2/AN2/VREF
RA3/AN3/VREF+
RA4/T0CKI
RA5/AN4/HLVDIN
OSC2 /С LKO/RA6
OSC1/CLKI/RA7
RB0/INT0/FLT0
RB1/INT1
RB2/INT2
RB3/INT3
RB4/KBI0
RB5/KBI1/PGM
RB6/KBI2/PGC
RB7/KBI3/PGD
RC0/T1OSO/T13CKI RC1 /Т10SI/ECCP2/Р2А RC2/ECCP1/P1A -RC3/SCK1/SCL1 RC4/SDI1/SDA1 RC5/SD01 RC6/TX1/CK1 RC7/TX1/DT1
RD0/PSP0
RD1/PSP1
RD2/PSP2
RD3/PSP3
RD4/PSP4/SD02
RD5/PSP5/SDI2/SDA2
RD6/PSP6/SCK2/SCL2
RD7/PSP7/*SS2
RE0/*RD/P2D
RE1/*WR/P2C
RE2/*CS/P2B
RE3/P3C
RE4/P3B
RE5/P1C
RE6/P1B
RE7/ECCP2/P2A
RF0/AN5 RF1/AN6/C20UT RF2/AN7/C10UT RF3/AN8 RF4/AN9 RF5/AN Ю/CVREF RF6/AN11 RF7/*SS1
RG0/ECCP3/P3A
RG1/TX2/CK2
RG2/RX2/DT2
RG3/CCP4/P3D
RG4/CCP5/P1D
RG5/*MCLR/VPP
RH0/A16 RH1/A17 RH2/A1B RH3/A19 RH4/AN12/P3C RH5/AN13/P3B RH6/AN14/P1C RH7/AN15/P1B
RJ0/ALE
RJ1/*OE
RJ2/*WRL
RJ3/*WRH
RJ4/BA0
RJ5/*CE
RJ6/*LB
RJ7/*UB
VDD
VDD
VDD
VDD
AVDD
AVSS
VSS
VSS
VSS
VSS
_DQ/
_D1/
Р2/
_D3/
Р4/
Р6/
_DZ/
- *WR
-*CS
R18 470 0m Optional
Optional
+3,3 В DC
_f_C7 _T_C8 _ТГС9 _t_C10 HL C11
T0,1 —,—0,1 0,1 —I— 0,1 —I— 0,1
^ мкФ ^ мкФ^ ^ мкФ ^ мкФ | мкФ
Рис. 2. Схема микроконтроллера Р!С18ЬР8722 в стандартной конфигурации, который подключен к базовой конфигурации W5100
+3,3 В А
Рис. 3. Структура отладочной платы EDTP
к W5100, показан на рис. 4. Здесь нет ничего такого, с чем бы вы не могли справиться. За исключением пары резисторов 12,3 кОм, другие компоненты рядом с W5100 — это элементы фильтров и развязки. Компоненты физического уровня выстроены в ряд около импульсного трансформатора. Обратите внимание на статусные светодиоды слева и джампер для выбора БРІ справа.
Как можно видеть, аппаратная часть устройства с W5100 очень проста. Перед тем, как перейти к программированию W5100, заме-
Рис. 4. Общий вид той части отладочной платы EDTP, которая относится к W5100
тим, что на рис. 1 нет светодиода, который я подключил к выводу RG4 PIC18LF8722. Я использовал его для проверки работы программы микроконтроллера. Он вспыхивал с частотой 1 Гц по прерываниям от таймера 3.
«Гаражный» код для WIZnet W5100
С точки зрения программиста W5100 состоит из регистров общего назначения, регистров сокетов, памяти передатчика и памяти приемника. Основное содержание регистров общего назначения — локальные IP и MAC адреса W5100. Кроме того, в них находятся размеры областей памяти для приема и передачи и параметры PPP/PPPoE. Можно сразу убить двух зайцев: использовать регистры общего назначения для проверки линий ввода/вывода PIC18LF8722, написав для него программу, которая будет записывать данные в регистры W5100 и считывать их оттуда. Я буду использовать компилятор HI-TECH PICC-18 C совместно со средой проектирования MPLAB и технологией REAL ICE от Microchip в качестве инструментов для работы с W5100.
Но я не смог заставить мой W5100 правильно общаться с PIC18LF8722. При поверхностном осмотре платы с W5100 никаких проблем не обнаружилось. Тогда я вернулся к коду на C, чтобы попытаться обнаружить
ошибку. Оказалось, что большая часть выводов PIC18LF8722, предназначенных для работы с адресом и данными, просто не была припаяна к печатной плате. Для пайки микросхем с малым шагом выводов, подобных W5100, я обычно использую фен и делаю это так часто, что считаю такой процесс совершенно безупречным. Но в этот раз фен меня подвел.
Перейдем к написанию кода для ввода/вывода данных W5100. Официально поставляемый производителем код драйвера, которым я располагал, написан для устройств AVR. Вместо того чтобы писать свой собственный include-файл W5100 для PIC, я адаптировал фирменный include-файл. Непосредственно сейчас мне нужен include-файл с кодом, который извлекает адреса из внутренних регистров W5100. Фирменный include-файл содержит также определения для всего содержимого регистров W5100, которые обязательно пригодятся потом. Я потерял уйму времени на устранение дефектов собственноручной пайки, но вернул часть этих потерь, переделав оригинальные файлы для AVR под PIC.
Первым действием моего официального встроенного ПО был аппаратный сброс W5100 (см. листинг 1). Затем я перевел интерфейс W5100 в режим непосредственной адресации. Это означает, что я не должен трогать регистр режима W5100, который является первым ре-
Рис. 5. IP-адрес шлюза в отладочном окне Watch среды MPLAB
гистром общего назначения. Таким образом, мы можем начать наш первый тест ввода/вывода W5100/PIC18LF8722 с установки регистров адреса шлюза, расположенных в диапазоне адресов 0x0001:0x0004. Эти регистры определены в преобразованном мною include-файле как GAR0:GAR3. Преобразованный файл получил имя w5100_pic.h. Как можно видеть в листинге 1, я расположил рядом некоторые основные подпрограммы ввода/вывода PIC18LF8722 для чтения и записи регистров W5100. Затем я написал содержимое массива gwayipaddrc для набора регистров адреса шлюза W5100. Чтобы убедиться, что запись в регистры общего назначения выполнена, читаю содержимое GAR0:GAR3 в массив с именем svrmacaddrc. Можете себе представить, как я был доволен, наблюдая IP-адрес шлюза в шестнадцатеричном формате в отладочном окне Watch среды MPLAB (рис. 5). Затем я проверил, используя свою подпрограмму чтения, пару регистров общего RTR0, которая по умолчанию должна содержать 0x07D0, и следующий регистр RCR, по умолчанию содержащий 0x08. Все прошло хорошо. Затем я инициализировал регистры шлюза, MAC-адреса, маски подсети и IP-адреса W5100. В ходе записи IP-адреса шлюза в WIZnet и чтения его оттуда мы отладили базовые операции чтения и записи внутренних регистров W5100.
Следующим шагом на нашем пути подключения платы с W5100 к сети будет запись
информации в память сокетов. Используем отведенные по умолчанию 2 кбайта на сокет. Это означает, что мы не должны трогать регистры RMSR (размер памяти приемника) и TMSR (размер памяти передатчика), которые по умолчанию содержат значения 0x55. Как можно видеть в листинге 2, все, что нам на самом деле нужно сделать, — это установить границы областей памяти приемника и передатчика для каждого из четырех сокетов, поддерживаемых W5100. После распределения памяти для сокетов мы можем сосредоточиться на том, что нам нужно для работы с сокетами W5100.
#define chip_base_address 0x0000 #define RX_memory_base_address 0x6000
#define gS0_RX_BASE chip_base_address + RX_memory_base_address #define gS0_RX_MASK 0x0800 — 1
#define gS1_RX_BASE gS0_RX_BASE + (gS0_RX_MASK + 1) #define gS1_RX_MASK 0x0800 — 1
#define gS2_RX_BASE gS1_RX_BASE + (gS1_RX_MASK + 1) #define gS2_RX_MASK 0x0800 — 1
#define gS3_RX_BASE gS2_RX_BASE + (gS2_RX_MASK + 1) #define gS3_RX_MASK 0x0800 — 1 #define TX_memory_base_address 0x4000
#define gS0_TX_BASE chip_base_address + RX_memory_base_address
#define gS0_TX_MASK 0x0800 — 1
#define gS1_TX_BASE gS0_TX_BASE + (gS0_TX_MASK + 1)
#define gS1_TX_MASK 0x0800 — 1
#define gS2_TX_BASE gS1_TX_BASE + (gS1_TX_MASK + 1)
#define gS2_TX_MASK 0x0800 — 1
#define gS3_TX_BASE gS2_TX_BASE + (gS2_TX_MASK + 1)
#define gS3_TX_MASK 0x0800 — 1
Листинг 2. В справочных данных на W5100 это описано при помощи псевдокода
Самая важная часть листинга 3 — это код, который открывает UDP сокет W5100. Первым делом нужно сообщить W5100, с каким типом сокетов мы хотим работать. В настоящий момент мы работаем с UDP. Таким образом, я загружаю в регистр режима сокета 0 значение, задающее UDP. У меня уже есть приложение (EDTP Internet test panel), кото-
рое будет посылать ASCII символы на известный порт 7, и, как можно видеть в листинге 3, я загружаю в регистр порта источника сокета 0 число 0x0007. Мы уже загрузили информацию о наших IP и MAC адресах. Таким образом, добавление значения порта источника UDP позволяет нам открыть сокет UDP. По большому количеству нулей в коде инициализации сокета в листинге 3 видно, что мы открываем сокет 0 W5100 в режиме UDP.
do{
wr_wiz_reg(Sn_MR_UDP,Sn_MR(0)); //protocol = UDP wr_wiz_reg(0x00,Sn_P0RT0(0)); //well-known ECHO port wr_wiz_reg(0x07,Sn_P0RT1(0));
wr_wiz_reg(Sn_CR_0PEN,Sn_CR(0)); //give the open command if(rd_wiz_reg(Sn_SR(0)) != S0CK_UDP) //wait for the socket to come online
wr_wiz_reg(Sn_CR_CL0SE,Sn_CR(0)); }while(rd_wiz_reg(Sn_SR(0)) != S0CK_UDP);
do{
//look for incoming UDP datagrams i16 = rd_wiz_reg(Sn_IR(0));
}while(i16 == 0); wr_wiz_reg(0x04,Sn_IR(0));
//get the datagram size hi_byte = rd_wiz_reg(Sn_RX_RSR0(0)); lo_byte = rd_wiz_reg(Sn_RX_RSR1(0)); get_size = make16(hi_byte,lo_byte);
//get the datagram's buffer offset
hi_byte = rd_wiz_reg(Sn_RX_RD0(0));
lo_byte = rd_wiz_reg(Sn_RX_RD1(0));
get_offset = make16(hi_byte,lo_byte) & gS0_RX_MASK;
//calculate the datagram's starting buffer address get_start_address = gS0_RX_BASE + get_offset;
//UDP header size header_size = 8;
//store the UDP header information addri = get_start_address; for(i8=0;i8<header_size;++i8)
{
packet[ip_destaddr+i8] = rd_wiz_reg(addri++);
++get_offset;
}
//store the UDP data
get_start_address = gS0_RX_BASE + get_offset; udp_data_size = get_size — header_size; addri = get_start_address; for(i8=0;i8<udp_data_size;++i8)
{
char gwayipaddrc[4] = {192,168,0,1}; char svrmacaddrc[6];
#define make8(var,offset) ((unsigned int)var >> (offset * 8)) & 0x00FF #define T0_WIZ TRISF = 0x00 #define FR0M_WIZ TRISF = 0xFF
*************************************** void wr_wiz_addr(unsigned int addr)
{
addr_hi = (make8(addr,1)); addr_lo = addr & 0x00FF;
}
void wr_wiz_reg(char reg_data,unsigned int reg_addr)
{
T0_WIZ;
wr_wiz_addr(reg_addr); data_out = reg_data; clr_WR;
N0P();
set_WR;
FR0M_WIZ;
}
char rd_wiz_reg(unsigned int reg_addr)
{
char data;
wr_wiz_addr(reg_addr);
clr_RD;
N0P(); data = data_in; set_RD; return(data);
}
***************************************
clr_RSET;
msecs_timer2 = 0;
while(msecs_timer2 < 2);
set_RSET;
addri = GAR0;
for(i8=0;i8<4;++i8)
wr_wz_reg(gwayipaddrc[i8],addri++);
addri = GAR0;
for(i8=0;i8<4;++i8)
svrmacaddrc[i8] = rd_wz_reg(addri++);
Листинг 1. Вы не найдете кода этого уровня в примерах из справочных данных W5100.
Но без этих базовых подпрограмм ввода/вывода регистров ничего работать не будет
packet[UDP_data+i8] = rd_wiz_reg(addri++);
++get_offset;
}
//update the receive buffer pointers wr_wiz_reg(Sn_CR_RECV,Sn_CR(0));
//TRANSMIT******************************************************
//load destination IP address addri = Sn_DIPR0(0); for(i8=0;i8<4;++i8)
wr_wiz_reg(packet[ip_destaddr+i8],addri++);
//load destination port address addri = Sn_DP0RT0(0); for(i8=0;i8<2;++i8)
wr_wiz_reg(packet[UDP_srcport+i8],addri++);
//get transmit buffer offset
hi_byte = rd_wiz_reg(Sn_TX_WR0(0));
lo_byte = rd_wiz_reg(Sn_TX_WR1(0));
get_offset = make16(hi_byte,lo_byte) & gS0_TX_MASK;
//calculate transmit data buffer start address get_start_address = gS0_TX_BASE + get_offset;
//load data into transmit buffer addri = get_start_address; for(i8=0;i8<udp_data_size;++i8)
{
wr_wiz_reg(packet[UDP_data+i8],addri++);
++get_offset;
}
//update transmit buffer pointer
wr_wiz_reg((make8(get_offset,1)),Sn_TX_WR0(0));
wr_wiz_reg((make8(get_offset,0)),Sn_TX_WR1(0));
//send data
wr_wiz_reg(Sn_CR_SEND,Sn_CR(0));
while(rd_wiz_reg(Sn_CR(0)));
Листинг 3. Задумайтесь об этом. Все, что должно делать любое коммуникационное устройство — это прием и передача. Я получил логику этого кода из псевдокода в справочных данных W5100
После открытия сокета мы имеем возможность посылать и принимать пакеты UDP. Существует два способа обнаружить пришедший пакет UDP: можно опрашивать регистр Received Size этого сокета или бит RECV его
регистра прерываний (Interrupt). Как видно из кода приема пакета UDP, который находится в середине листинга 3, я выбрал последний способ.
Входящий пакет UDP устанавливает бит RECV регистра прерываний сокета. Наша первая реакция на это — сбросить бит RECV, записав 1 в соответствующую этому биту позицию в регистре прерываний. W5100 сама заботится о контрольной сумме, и мы как программисты никогда не смотрим на информацию о ней в пакете UDP. Размер входящего пакета UDP автоматически помещается в регистр Receive Size сокета. Мы читаем содержимое этого регистра и помещаем полученное значение в переменную get_size. Я использую имена переменных из текста в справочных данных на W5100, где это возможно, чтобы облегчить сравнение моего кода драйвера с псевдокодом обработки UDP, приведенным в примере из этого текста. Значение указателя чтения приемного буфера хранится в регистре Read Pointer сокета. Мы будем использовать это значение, чтобы сформировать базу для переменной get_offset. Значение этой переменной используем в сочетании с базовым адресом приемного буфера сокета для того, чтобы вычислить адрес начала заголовка пакета UDP. Предлагаемый в W5100 заголовок пакета UDP состоит из четырех байтов IP-адреса назначения, двух байтов адреса порта назначения и двух байтов информации о размере данных. Таким образом, значение переменной header_size равно восьми. После завершения расчета адреса мы можем использовать нашу подпрограмму чтения регистров W5100, чтобы сохранить данные в ОЗУ PIC18LF8722 для дальнейшего использования.
Если рассуждать логически, то, что не является заголовком, должно быть данными, потому что мы защищены от расчета контрольных сумм архитектурой W5100. При этом мы можем сделать вывод о том, что переменная udp_data_size содержит количество байтов данных, которое нам нужно извлечь и сохранить. Далее, используя наш самодельный код ввода/вывода для W5100, читаем данные из приемного буфера W5100 и сохраняем их в соответствующей области ОЗУ PIC18LF8722. Извлечение пакета UDP закончено. Мы завершаем сеанс приема записью команды RECV в регистр команд сокета, обновляя тем самым указатели приемного буфера. Чтобы правильно сориентироваться в псевдокоде из справочных данных W5100, обратите внимание: переменная udp_data_size не из этого псевдокода. Это переменная от Фреда.
Отправка пакета UDP еще проще, чем его прием. Мы повторно используем полученную ранее информацию и пошлем UDP-сообщение обратно отправителю. Обратимся еще раз к полученному заголовку пакета UDP, который содержит IP-адрес назначения и порт назначения UDP. Мы не напрасно побеспокоились заранее и сохранили оба числа из заголовка. Теперь все, что от нас требуется, —
это извлечь их из ОЗУ PIC18LF8722 и загрузить в соответствующие регистры сокета W5100. Я начинаю мою передачу пакета UDP так, как показано в нижней части листинга 3. Используя указатель записи буфера передачи сокета, я рассчитываю, где в W5100 находится этот буфер, и заполняю его данными, которые хочу передать. Затем передаю сохраненные ранее в ОЗУ PIC18LF8722 данные из пакета UDP в буфер передачи W5100. А W5100 передаст данные, расположенные между указателем чтения передатчика (transmit read pointer) и указателем записи передатчика (transmit write pointer) сокета. Таким образом, я должен обновить указатель записи передатчика, добавив к нему число байтов, которое мне надо передать. После того, как я это сделаю, я посылаю команду SEND и жду сигнала успешной передачи, который очистит регистр команд сокета. Теперь я могу послать команду CLOSE в регистр команд сокета, чтобы закрыть сокет или же отправить или принять следующий пакет UDP.
Заключение
Вы закончили учебный курс по W5100. Теперь у вас есть примеры кода для чтения и записи регистров W5100, кода для передачи и отправки пакетов UDP и универсальная отладочная плата для работы.
Вот подсказка, которая поможет вам в самом начале проектирования стендов с W5100: выполните только код до загрузки IP-адреса. Загрузите адрес шлюза, MAC-адрес, маску подсети и IP-адрес. Не открывайте другие сокеты. Сделав все это, вы сможете послать команду PING вашему устройству с W5100. Если получите ответ, то это будет означать, что аппаратура физического уровня и код чтения и записи регистров работают нормально. Тем самым вы также проверите линии адреса, данных и управляющих сигналов W5100 и убедитесь в их исправности. Поднять UDP — приятный и простой способ познакомиться с W5100. EDTP Internet Test Panel — это UDP-программа, которая работает на вашем персональном компьютере [1].
Исходные коды проекта можно загрузить с ftp-сервера журнала Circuit Cellar по адресу ftp://ftp.circuitceUar.com/pub/Circuit_CeUar/ 2007/208. ■
Литература
1. EDTP Internet test panel EDTP Electronics, Inc. www.edtp.com
2. HI-TECH PICC-18 C Compiler HI-TECH Software. www.htsoft.com
3. PIC18LF8722 Microcontroller, REAL ICE, and MPLAB Microchip Technology, Inc. www.microchip.com
4. RDI-125BAG1A Pulse transformer U.D. Electronic Corp. www.ude-corp.com
5. W5100 TCP/IP Ethernet controller WIZnet, Inc. www.ewiznet.com