ESP8266 Урок 5. Настраиваем toolchain и пишем свою прошивку в IDE Eclipse. Часть 1

 

 

 

Ну вот, наконец-то пришла пора нам вернуться к контроллеру с WiFi-модулем ESP8266.

До сих пор мы его изучали, пользуясь ПО, установленном в нём при покупке, а также прошивали готовое ПО.

А теперь мы попробуем прошивку для него написать самостоятельно.

Это можно сделать несколькими способами. Можно воспользоваться Arduino IDE, но только мне это что-то не понравилось из-за отсутствия гибкости написания кода и по нескольким другим причинам. Также можно воспользоваться SDK, который предоставляет нам производитель. Но воспользоваться им тоже можно по-разному. Само собой, нам потребуется кросс-компилятор, мы же ведь пишем и собираем ПО не на той машине, на которой оно будет работать. Кросс-компилятор нам, к сожалению, производитель не предоставляет, но найти его не сложно, так как существует много сборок в сети, большинство которых работают в ОС Linux, также есть несколько сборок и для Windows. Одной из таких сборок мы и воспользуемся.

Скачать её можно здесь. Также я добавлю на всякий случай ссылочку внизу страницы, чтобы не затерялась.

Также нам потребуется утилита esptool. Где её взять и как пользоваться, мы знаем. Она представляет из себя файл, интерпретируемый средой Python. Если у кого-то нет желания устанавливать Python, я дам ссылку на комплект утилит внизу страницы. В принципе, условимся на том, что его нет ни у кого, и данной утилитой, скомпилированной для Windows, мы и будем пользоваться.

Собирать проект мы будем в среде программирования Eclipse, с которой мы уже давно знакомы из уроков по языку C. Также для автоматизации процесса сборки прошивки, а также процесса загрузки её в FLASH-память контроллера, мы собственноручно напишем сценарий Makefile. А проект, как всегда, мы напишем простейший, который будет мигать светодиодом на плате.

Плату мы будем использовать другую — NodeMCU, в которой распаяна микросхема-конвертер USB-TTL, также управление перезагрузкой модуля и подготовкой его к прошиванию тоже настроено через интерфейс UART с помощью CTS и RTS.

Вот так выглядит модуль

 

 

Микросхема-конвертер может попасться разная. Поэтому драйвер нужен будет соответствующий. Ну, думаю, с этим проблем не будет. У меня лично CH340, пока проблем не заметил.

К плюсам данной сборки можно отнести помимо её удобного управления через USART размер FLASH-памяти 4 мегабайта, а также вывод огромного количества ножек наружу.

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

Теперь давайте приступим к установке и разворачиванию нашего ПО.

По ссылке, которую я дал выше, скачаем самую последнюю версию тулчейна

 

 

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

 

 

Жмём кнопку Install и тулчейн распакуется по указанному пути.

Теперь создадим какую-нибудь папку где угодно, в которой мы будем хранить весь наш тулчейн и SDK. Я, например, на диске D создал папку с именем ESP8266.

В данную папку скопируем из папки, в которую распаковался только что наш полный тулчейн, папку xtensa-lx106-elf, находящуюся в папке opt.

Также в папке D:\ESP8266 создадим папку ESP8266_NONOS_SDK, в которую скопируем содержимое ESP8266 NONOS SDK V2.2.1, скачанного с сайта espressif.

Также в папку D:\ESP8266 скопируем папку utils с тремя утилитами из архива с утилитами, ссылка на который есть внизу страницы.

Вот, в принципе, и весь тулчейн.

Надеюсь, что все смотрят мои уроки по языку C и у всех Eclipse и MinGW уже установлен, поэтому заострять на этом внимание не будем. А если это не так, то есть в данном курсе уроки по установке и того и другого.

Запустим IDE Eclipse и начнём создание нового проекта, для чего пройдём по меню File -> New -> Project

 

 

В открывшемся диалоге выберем C/C++ -> C Project и жмём Next

 

 

В следующем открывшемся диалоге выбираем Executable -> Empty Project -> Cross GCC, дадим имя нашему проекту и снова жмём Next

 

 

Затем в следующем разделе галку оставляем только на Release и жмём Finish

 

 

В дереве проектов у нас создалась пустая папка с именем проекта. Настроим некоторые свойства нашего проекта, вызвав соответствующее контекстное меню.

В свойствах в пункте C/C++ Build/Tool Chain Editor открывшегося диалога изменим текущий сборщик

 

 

В пункте C/C++ Build снимем 2 галки и напишем команду для сборки проекта в соответствующее поле редактирования, а текст другого поля отредактируем, убрав оттуда папку Debug, и нажмём кнопку Apply and Close

 

 

Остальные настройки мы добавим позже.

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

Создадим новые папки с именами inc. src и build в дереве с проектом

 

 

Создадим в папке src файл main.c и добавим в него пока следующее содержимое

 

 

Вместо привычной функции main, в которую мы попадаем при запуске программы, для контроллера esp используется функция с именем user_init.

ICACHE_FLASH_ATTR — это атрибут, который обозначает, что функция с данным атрибутом выполняется из FLASH-памяти, если надо выполнить функцию из RAM-памяти, то будет атрибут IRAM_ATTR, а если это будет обработчик прерывания, то IRAM_ATTR.

Добавим в дерево проекта пока пустой Makefile, будем писать его постепенно

 

 

В открывшемся диалоге выберем обычный файл и жмём кнопку Next

 

 

Присваиваем имя файлу и жмём Finish

 

 

 

Добавим в Makefile следующую строку (будем писать его постепенно, чтобы было немного понятнее)

 

 

Это означает, что цели all и clean — это чисто наборы команд, чтобы сборщик не искал файлы с такими именами.

В принципе, из уроков по C мы с утилитой make уже знакомы, поэтому нам будет проще. Конечно, знакомы пока мы с ней на очень первоначальном уровне, но ничего, развитие будет потом. Поэтому здесь мы также пока не будем применять автоматические переменные и прочие вещи, сложные для понимания. Впоследствии мы обязательно будем всё это использовать. Есть в примерах в SDK готовые сценарии, но, думаю, у них очень для нас сложный текст, а хочется всё же понять, что там и к чему. Вот я и решил сценарий писать самостоятельно и развивать его постепенно.

Далее давайте добавим в наш сценарий команду сборки из пока единственного файла с исходным кодом main.c объектного файла main.o

 

 

Это всё одна команда с таким большим набором параметров. Потом мы всё упростим и часть параметров уберём в переменные. Обратный слэш говорит сборщику, что следующая строка — это продолжение текущей.

Все параметры мы сейчас разбирать не будем, чтобы не забивать пока себе голову лишней информацией. Расскажу про некоторые.

-I — это параметр, за которым следует каталог, в котором компилятор будет искать заголовочные файлы. Причём путь к каталогу следует за параметром сразу, без применения пробела. Таких каталогов у нас будет три. Два из SDK, а один из нашего проекта, куда мы будем добавлять свои заголовочные файлы.

Далее мы включаем отладочную информацию в сборку, хотя это не обязательно, мы не будем пока заниматься отладкой, отключаем оптимизацию. Затем мы велим компилятору применять стандарт c99. Также мы велим ему любые предупреждения считать ошибками.

Если мы сейчас попытаемся собрать наш проект, то у нас ничего не выйдет

 

 

Дело в том, что нужно подключить некоторые библиотечные файлы из SDK, которые объяснять нашему компилятору, что и к чему и почему именно user_init(), а не main().

Подключим такие файлы в main.c

 

 

Последний подключенный файл нужен для работы с GPIO.

Если мы опять попытаемся собрать проект, то получим ошибку отсутствия необходимого заголовочного файла

 

 

В данном случае у нас два выхода. Первый — в файле osapi.h закомментировать подключение данного файла, но чтобы этого не делать после обновления SDK, есть второй путь — создать такой файл в директории inc. Так и поступим, создадим файл с именем user_config.h в данном каталоге следующего содержания

 

 

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

 

 

У нас опять два пути решения проблемы. Первый — закомментировать дубль, а второй — так как это предупреждение, отключить то, чтобы компилятор считал предупреждения ошибками. Тут мы выберем первый путь, так как при втором у нас постоянно будет в консоли мельтешить предупреждение.

Поэтому найдём файл c_types.h и закомментируем там 68 сроку

 

 

При следующей попытке сборки у нас наконец-то всё соберётся без ошибок и на выходе мы получим долгожданный main.o

 

 

Это уже хорошо, но нам нужна прошивка, а это пока только объектный файл. Также наш код пока ещё ничего не делает.

В функции user_init вызовем функцию из SDK, которая произведёт первичную инициализацию системы ввода-вывода

 

 

Описание данной функции есть в заголовочном файле gpio.h.

Светодиод, которым мы будем мигать, на нашей плате подключен к ножке порта GPIO2. В ESP01 он подключен к ножке GPIO1.

Для использования ножки как обычный GPIO, а не как альтернативный вход или выход, мы используем вот такой макрос

 

 

Данный макрос в свою очередь вызывает другой макрос WRITE_PERI_REG, который записывает в регистр, указанный в первом параметре первоначального макроса, значение, которое рассчитывается из второго параметра, причём оно складывается со значением, уже находящемся в регистре.

В принципе нам не так важно, как работает макрос. На официальном сайте espressif есть вся документация, описывающая, как работать с SDK. Процесс настройки ножки GPIO описан в файле 2c-esp8266_non_os_sdk_api_reference_en.pdf в пункте 7.1

 

 

Также нас может напрягать ситуация, что в нашем исходном коде всё подчёркивается. как будто у нас везде ошибки

 

 

Это непорядок. Всё дело в том, что директории с заголовочными файлами, которые мы показали компилятору в командной строке в Makefile, не видны среде Eclipse.

Поэтому в свойствах проекта в ветке C/C++ General/Path and Symbols надо будет во вкладке Includes выбрать пункт GNU C и добавить их в список

 

 

Вот теперь всё нормально

 

 

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

Теперь мы можем, например, выбрав по пункту Open Declaration контекстного меню на вызове функции gpio_init просмотреть описание данной функции

 

 

Так как в следующей вызванной функции ножка порта будет обозначаться обычным числом, что не совсем читабельно, то объявим вот такой макрос

 

 

Добавим также функцию задержки, так как мы пока не будем использовать таймер, который сможет подсчитать точное время

 

 

В функции main() добавим бесконечный цикл, в котором после небольшой задержки с помощью использования нужной функции из SDK установим низкое состояние ножки порта

 

 

Описание данной функции также есть в документации

 

 

Первый параметр — маска ножек, которые надо установить в высокое состояние, второй — маска бит, которые нужно сбросить в низкое состояние, третий — маска ножек, которые надо включить на выход, четвёртый — маска ножек, которые надо настроить на вход. Данная функция чем-то похожа на макрос MODIFY_REG из библиотеки CMSIS для ARM. Так как у нас ножка уже на выход настроена, то в 3 и 4 параметре мы никакие биты не устанавливаем. В первом параметре тоже 0, так как мы ни на какой ножке высокий уровень не устанавливаем, а вот во втором параметре мы используем маску для установки низкого уровня на нашей ножке GPIO2.

При установке в низкое состояние наш светодиод, наоборот, будет светиться, так как он подключен к шине питания анодом, а катодом к ножке порта.

С помощью такой же функции мы после такой же задержки установим на нашей ножке уже высокое состояние

 

 

Здесь мы просто поменяли местами первый и второй параметр.

Также с помощью данной универсальной функции мы настроим нашу ножку на выход перед бесконечным циклом

 

 

В следующей части урока мы закончим писать код нашего первого проекта, а также файл сценария Makefile, и проверим нашу первую прошивку в действии.

 

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

 

Исходный код

 

Утилиты для прошивки

 

 

Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU

Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266

Переходник USB to TTL можно приобрести здесь ftdi ft232rl

Многофункциональный переходник CJMCU FT232H USB к JTAG UART FIFO SPI I2C можно приобрести здесь ftdi ft232rl

 

 

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

 

ESP8266 Настраиваем toolchain и пишем свою прошивку в IDE Eclipse

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

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

*