В предыдущей статье я рассказывал о том, как хорошо работать с микроконтроллерами STM32 без операционной системы. Однако может наступить момент, когда вам понадобится наладить взаимодействие с вашим МК по сети. Например, что-нибудь типа умного дома или передача отладочной и диагностической информации на web страницу. Наличие Ethernet интерфейса — это конечно сильный аргумент для того, чтобы бросить STM32 и перейти на полноценный ARM процессор под управлением Linux. Однако, этот аргумент парируется очень просто: на рынке есть компактные Ethernet модули, которые можно задействовать в наших STM32 проектах. Речь идет о чипах семейства W5500 WIZnet, на основе которых эти модули и собраны. Добавляем к нашему проекту этот модуль (хвала Али Экспрессу, как обычно!), и получаем функциональность Ethernet в МК STM32.
Поскольку в этом эксперименте я использовал макетную плату без пайки, все стало выглядеть очень симпатично (по сравнению с предыдущими экспериментами). Поэтому не стыдно выложить фото этой сборки:
Работать с модулем W5500 — это сущий ад. В нем куча регистров, в которые нужно заносить и считывать информацию. Когда я раскрыл мануал этого чипа, то первое что я сделал — это сразу закрыл его и начал искать библиотеку, в которой вся эта регистровая часть уже реализована и которая предоставляет такие привычные и понятные интерфейсы: socket(), listen() и так далее. И я ее нашел.
Как работать с библиотекой я расскажу дальше, а пока поработаем с нашим фото.
Пройдемся по макетке слева направо и посмотрим, что я там разместил.
Макетная сборка
Модуль W5500
Слева, как вы уже догадались, Ethernet модуль W5500. В этом варианте исполнения его пины смотрят вниз, что удобно для размещения на макетной плате. Есть вариант и пинами вверх, что будет удобно если вы решите просто соединять контакты напрямую кабелями. Собственно чип W5500 распаян под зеленой платкой, из-за чего создается впечатление что кроме Ethernet разъема больше ничего нет. На самом деле это не так. Чип берет на себя всю работу по поддержке сетевых протоколов, а работать с ним нужно по интерфейсу SPI. Поэтому красные и темные проводки — это и есть соединения SPI с микроконтроллером.
Кто уже работал с SPI, сейчас испытывают небольшой диссонанс. Этот протокол вообще-то говоря принято использовать для внутриплатных соединений, и выводить его наружу считается моветоном. Пришлось поступиться принципами ради демонстрационных целей, потому что нужна скорость, которую другие популярные интерфейсы — I2C и UART обеспечивать не могут. Если же вы распаяете модуль W5500 на своей собственной плате, то правила поведения в приличном обществе будут соблюдены.
UART
Смещаем взгляд правее и видим вертикально воткнутую платку. Это адаптер UART-USB, с которым мы познакомились раньше. Его мы используем исключительно для отладочных целей, для того чтобы выводить сообщения нашей программы на экран PC.
От МК этой плате требуется только одна линия: Tx (отдаем строчки), которая на адаптере будет обозначаться уже как Rx (принимаем строчки). Ну и само собой кабель, который вы видите на торце платы, подключен к USB разъему PC.
Переключатель на плате устанавливаем в положение 3.3В: это будут уровни линий передачи данных, с которыми работает адаптер.
МК STM32F103 Blue Pill
По центру — наш микроконтроллер, плата МК STM32F103C8T6. Здесь неожиданностей нет, единственное я использовал компактную версию под названием Blue Pill. Есть еще Black Pill, Red Pill но честно говоря не знаю чем все они принципиально отличаются друг от друга. Работать будут все.
В комплекте с этими платами идут линейки пинов, которые я распаял снизу. Это позволяет вставить пины контроллера в макетную плату. Если вы используете Pill’ы в своих устройствах, запаивать пины нет необходимости — можно сразу паять соединения на ламели по краям платы. В нашей конфигурации используются контакты соответствующие UART1 и SPI2.
К разъему JTAG в торце платы МК как обычно подключен программатор/отладчик ST-LINK V2. Его мы видим сверху. Его место — также в USB разъеме PC.
USB разъем для электропитания не используется — напряжение подается непосредственно на пины МК.
Электропитание
На правой стороне макетной платы расположен весьма удобный модуль электропитания, который обеспечивает независимые напряжения 5В или 3.3 В по обеим линиям питания макетной платы (синие и красные линии). Своими пинами модуль ложится в аккурат на эти линии, плюс к этому есть возможность подключиться еще сверху. Входное напряжение для модуля — 12В.
Модуль питания сконфигурирован джамперами на выходное напряжение 3.3В, отбор питания идет по внешним линиям модулями W5500 и МК STM32, которым требуется 3.3В. На фото видны эти желтые и коричневые короткие перемычки, которые идут рядом.
Нюанс: вы пожете подключить к МК вместо 3.3В 5В к соответствующему (другому естественно!) контакту. Эти 5В будут преобразованы в 3.3В.
Внимание! Не подключайте к плате внешнее питание 3.3В и 5В от USB одновременно. Можете потерять МК ) Также по этой причине провод +5В для JTAG от USB PC болтается в воздухе, как может заметить внимательный читатель )
Модуль UART требует электропитание 5В, которое мы обеспечиваем внешним проводком который подключается к пину +5В модуля питания. Есть подозрение, что он прекрасно будет работать и без этого проводка от USB, когда тот подключен (и работает на самом деле).
Ситуация когда к одной цепи питания модуля подключаются два источника питания — не совсем здоровая. Картинку портит поступающие 5В от USB, которые преобразуются в 3.3В и эта цепь потенциально может конфликтовать с внешней линией питания 3.3В. В таких случаях обычно ставят диод Шоттки, который защищает цепи питания 3.3В от реверсного тока. Будем надеяться, что так оно и есть )
Зачем вообще нужен модуль питания, если раньше мы прекрасно запитывали микроконтроллер от USB? Не забываем, что теперь у нас появился серьезный потребитель по напряжению 3.3В — это чип W5500, который не в лучшие для нас моменты готов принять до 185мА. Внутренний преобразователь уровня 5/3.3В микроконтроллера на такой подвиг не способен, если нам в голову придет мысль взять напряжение 3.3В оттуда.
Конфигурация
Как и раньше, для создания проекта воспользуемся услугами STM32CubeMX. По традиции создаем проект на основе Makefile, чтобы не городить огород с визуальными системами разработки (помните наш проект hardcore? Только Makefile и vim!). Как обычно, включаем пункт Debug:Serial Wire в меню SYS, чтобы иметь возможность прошивки и отладки. Сразу включатся пины PA13, PA14: через них STLINK будет общаться с МК.
Осталось сконфигурировать интерфейсы и все. Включаем USART1: Mode Asynchronous (Куб задействует пины PA9, PA10) и включаем SPI2: Mode Full-Duplex Master. На вкладке конфигурации для SPI2 нужно будет подправить параметр Prescaler: установить его в значение 4. Напоминаю еще раз, что UART нужен только для отладки, чтобы получать на нашем компе логи из программы контроллера.
Почему SPI2 а не SPI1? Так было в библиотеке поддержки чипа W5500, я не стал менять интерфейс. Видимо, разработчикам было удобно работать с пинами именно с этой стороны модуля микроконтроллера ) В нашем случае Куб выдаст для SPI пины PB13 — PB15.
Нам еще понадобится управлять пином PB12 как выходным (забегая вперед — библиотека использует его для включения чипа W5500). Поэтому кликаем на него и делаем GPIO_Output. И точно также, сразу делаем выходным пин PC13: к нему подключен светодиод МК, и грех не воспользоваться возможностью поморгать светодиодом в нужных местах.
Создаем проект и переходим к следующему шагу.
Соединения
Поскольку распиновка модулей W5500 и UART-USB и так известна, а распиновку Blue Pill мы уже получили с помощью Куба, займемся соединениями. Работа приятная, медитативная, навевает мысли о тщете всего сущего, хорошо заниматься этим перед сном, глубокое погружение гарантировано
Начнем с модуля W5500. Все, что нам от него нужно — это цепи SPI и питания. С подключением питания все понятно — задействуем цепи 3.3В и GND, самое главное — правильно соединить линии интерфейса SPI. Поскольку на модуле нет нумерации пинов, на схеме соединений слева будем указывать SPI обозначение пина по версии W5500, справа — номер пина и SPI обозначение по версии Куба:
|
Памятка по SPI:
- MISO — Master In, Slave Out: если мы в режиме мастер — принимаем данные, в режиме периферии — передаем;
- MOSI — Master Out, Slave In: в режиме мастер передаем данные, в режиме периферии — принимаем.
В нашей конфигурации W5500 будет периферийным модулем, который будет выбираться сигналом SCNn с МК. Поэтому по линии MISO данные будут идти от W5500 к МК, по линии MOSI — в противоположном направлении. Обратите внимание, что нет необходимости переполюсовки Tx/Rx как в UART: назначение вывода (вход или выход) меняется в зависимости от того, в каком режиме — Master или Slave работает модуль.
С модулем UART-USB все просто. Нужна только одна линия передачи данных:
И в заключение — подключаем программатор/отладчик ST-LINK V2:
Цепь 3.3В остается неподключенной!
Не забудьте соединить «земли» всех модулей с землей модуля питания и подать 3.3В на модули W5500 и Blue Pill. Модуль UART-USB, как я говорил до этого, подключается к пину 5В модуля питания.
W5500 Library
Наконец наступил долгожданный момент — подключение библиотеки модуля W5500, чтобы с ним можно было работать вменяемым образом. Саму библиотеку можно скачать здесь. На самом деле, это не совсем библиотека, а набор файлов которые нужно включить в наш проект. Они точно также будут компилиться и собираться, как и наши собственные файлы. Поэтому по структуре это не library, а дополнительные к нашему проекту кусочки. Но я все равно буду называть это библиотекой — по существу. Кому нравится — могут называть это также драйвером; сама WizNet вообще использует наименование Library_Driver.
Подобные продукты третьих сторон я храню отдельно от своего проекта, потому как не нужно дублировать исходники в каждом отдельном проекте и тем более включать их в систему контроля версий. Для этого у меня специальная директория — /home/user/bin, куда и скачаем библиотеку WizNet она же драйвер W5500.
Распаковываем архив и меням имя на ioLibrary_Driver. Далее, нужно настроить библиотеку на определенную версию чипа. Для этого в файле Ethernet/wizchip_conf.h ищем строчку вида
И меняем W5500 на модель чипа, которая у вас в наличии. Само собой у меня менять ничего не пришлось.
Теперь нужно как-то интегрировать исходники библиотеки в наш проект. Это делается через Makefile. Добавляем в него строки следующим образом (будьте внимательны: показаны также существующие строки, чтобы вам было проще ориентироваться по make-файлу):
Все достаточно просто, не правда ли? Наступил момент запуска библиотеки. Для этого ее нужно инициализировать и выполнить тестовый пример — запустить TCP сервер который будет принимать входящее соединение и отвечать чем-то в стиле «Hello World».
Software
Как вы наверное уже догадались, все это будет жить в файле tcp.c. Но вначале библиотеку нужно инициализировать. Код инициализации разместим в main.c, поскольку так ему будет проще доступаться к интерфейсным переменным.
Первым делом нужно приготовить для библиотеки наши callback функции, которые она будет дергать когда ей понадобится доступ к SPI для обмена с чипом WZ5500:
Теперь библиотеке нужно как-то сообщить о нашей проделанной работе. Регистрация наших callback-функций в библиотеке выполняется следующей парой строк:
Само собой, это уже вызовы функций библиотеки. Дальнейшая инициализация:
Обращаем внимание на то, что прямо здесь идут сетевые настройки модуля. В результате в структуре netInfo будет храниться вся сетевая информация, которую вы можете вывести на экран вашего компа через модуль UART-USB сразу после инициализации.
Ну а теперь можно вызывать нашу функцию tcp_server(), которая будет делать всю полезную работу. Функцию разместим в файле Src/tcp.c. Не забудем объявить ее в заголовке main.h:
Так уж и быть, выложу полное содержание tcp.c. Как все это работает, описал в комментах. Для тех, кто знаком с логикой создания входящих tcp соединений, трудностей не будет никаких.
Проверяем все это так. Соединяем патчкордом модуль W5500 и наш комп. Конфигурируем проводное соединение, у меня на PC Ubuntu это адрес 192.168.77.5 (заметьте, что это также адрес шлюза для W5500). С нашей машины пингуем модуль: ping 192.168.77.6, убеждаемся что пинги проходят.
Дальше, достаем швейцарский нож хакера — программу netcat, коннектимся к модулю:
и получаем в ответ долгожданное «Hello World», а в экране minicom наблюдаем логи, которые посылает нам trace через модуль UART-USB.
Некоторые размышления по структуре программы. В ожидании входящих соединений, МК видимо будет выполнять полезную работу. Например обрабатывать поток радиолокационных данных ) Возникает проблема одновременной поддержки двух процессов. В Linux среде это решается просто — системным вызовом select(), который может зависать на нескольких событиях. В STM32 Линукса нет, но зато для STM32 есть простая операционная система реального времени FreeRtos. И она умеет работать с потоками, то есть содержит простейший планировщик заданий. Даю наводку, а как вы ей распорядитесь — ваше дело )
Про прошивку МК и отладку я подробно написал в предыдущей статье. Поэтому здесь описание этих процессов опущено.
Спасибо за материал! Долго не мог найти простой пример первого шага с STM32 и W5500.
PS: также любим обычный текстовый редактор + make.
Пожалуйста )
Да, стремился делать такие статьи по принципу — какой инфы собранной в одном месте не хватало для начала. Детали можно найти в инете уже потом
Это наверное самое короткое и почти подробное описание старта W5500 на STM32. Настоящий Hello World! Спасибо.
Спасибо за отзыв!
Интерестная стаття по поводу мультипоточности freeRTOS с использованием очереди сообщений и мютексов:
http://easyelectronics.ru/freertos-primer.html
Мне кажется, что в строке
.gw = {192, 168, 1, 77}}; // адрес шлюза
перепутаны местами два последних байта
Да, точно.
Поправил, спасибо )
так и не понял,где вызывается функция tcp_server
она коллбек на что-то, тогда на что?
или она отрабатывает один раз и тогда её вызвать один раз в main?
не понятно
Функция tcp_server() вызывается один раз, после чего в теле функции работает бесконечный цикл while в котором ведется прослушивание входного сокета. При входящем соединении оно обрабатывается, после чего сокет закрывается.
Чтобы продолжить прослушивание сокета, функцию нужно вызывать еще раз и так далее.
Модель соединений простая и использована в демонстрационных целях. Но работает )
Все на пальцах объяснил с нуля.
Осталось добавить обработку прерывания наличия tcp соединения(w5500 такое вроди бы выставляет).
Чтобы не крутится в бесконечных циклах и все будет готово.
Нужно организовать минимальный обмен данными между контроллером и ПК.
Заказал W5500 буду стартовать по этому руководству.
Спасибо тебе мил человек.
Да, конечно, это только каркас. Далее лучше наладить обработку по прерыванию.
Успехов! )
Огромное спасибо , начал осваивать IDE Keil+cube . Хотелось бы увидеть WiFi модуль и простенький пример терминала с ним.
Да, был один небольшой проект с WiFi модулем ESP8266. Надо бы написать статью