Русский
Русский
English
Статистика
Реклама

Platformio

Начинаем писать под stm8, выбираем среды разработки и стартуем

28.04.2021 12:07:29 | Автор: admin
image

На пути в программировании stm8 есть развилка, о ней сегодня и поговорим.

Определимся что речь будет идти о средах которые могут писать под си. Для начала поговорим о подходах, я выделю 2 основных.

Первый установка ST Visual Develop и выбор в качестве компилятора COSMIC Бывший платный, а ныне бесплатный, но со своими заморочками; регистрация, получение ключа, и прочие танцы с бубном.

Второй же вариант, более простой VS Code + PlatformIO и компилятор SDCC полностью свободный. И опять же не все так просто. Sdcc не умеет исключать не используемые функции. Я решил этот вопрос хоть и успешно, но не без дополнительных действий при написании кода.

Первая среда, для любителей всё делать правильно


Для начала нам нужен ST Visual Develop. Устанавливаем и ставим запуск ярлыка всегда от администратора. В придачу к нему нам дают ST Visual Programmer, полезный инструмент, особенно когда стоит защита от записи и надо разблокировать микроконтроллер, а ведь китайские blue pill всегда приходят заблокированными. Китайцы бояться что мы украдём их круто оптимизированный Blink.

Вот так выглядит STVD
image
Я так понял её создали, когда в моде были 16 битные цвета...

Дальше нужно будет получить компилятор COSMIC и его лицензионный ключ. Заполняем то что просят, получаем дистрибутив и делаем запрос ключа по электронной почте (тут рулетка кому то сразу придёт, кому то придётся подождать).

После пройденного лабиринта из форм и запросов, когда всё уже установлено, начнём
image
image
При первом запуске нужно указать расположение ключа, его лучше поместить в директорию компилятора. После создания нажимаем F7, ошибок быть не должно. Если писать на чистых регистрах, то всё готово, но я такой хардкор не люблю, поэтому продолжим и добавим SPL библиотеку.

Распакуем куда-нибудь и заходим в папку STM8S_StdPeriph_Lib\Project\STM8S_StdPeriph_Template. Тут у нас шаблон проекта stm8s_conf.h это конфигурационный файл библиотеки, через него выбирается контроллер. Зайдём в main тут сразу с первых строк #include "stm8s.h" это ссылка на основную библиотеку, а так же кусок кода отладки который начинается с #ifdef USE_FULL_ASSERT, без отладочного кода будут сыпаться ошибки.

Теперь когда мы прошлись по верхам давайте пробовать запускать библиотеку. Добавляем в проект из шаблона main и конфигурационный файл в. В include files добавляем всё из STM8S_StdPeriph_Lib\Libraries\STM8S_StdPeriph_Driver\inc.
image
Теперь всё должно собраться.

Добавим stm8s_gpio.c и соберём простецкую мигалку. У меня один из светодиодов висит на D3, конфигурация ноги на выход выглядит так:

GPIO_DeInit(GPIOD);GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_SLOW);

Её вписываем в main до бесконечного цикла.

А вот функция смены состояния. GPIO_WriteReverse(GPIOD, GPIO_PIN_3); вписываем её в бесконечный цикл.

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

void Delay(uint16_t nCount){  /* Decrement nCount value */  while (nCount != 0)  {    nCount--;  }}

Впишем её в конец перед #ifdef USE_FULL_ASSERT. Так же впишем её прототип в начало, где под это выделено место в шаблонном main.

/* Private function prototypes -----------------------------------------------*/void Delay (uint16_t nCount);

Ну и наконец впишем функцию со значением в бесконечный цикл после функции смены состояния: Delay(0xFFFF);

Подключаем ST-Link и прошиваем, для этого нажимаем Start Debugging и Run. Светодиод моргает значит всё хорошо.

У кого не получилось вот полный main.c
/**  ******************************************************************************  * @file    Project/main.c   * @author  MCD Application Team  * @version V2.3.0  * @date    16-June-2017  * @brief   Main program body   ******************************************************************************  * @attention  *  * <h2><center> COPYRIGHT 2014 STMicroelectronics</center></h2>  *  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");  * You may not use this file except in compliance with the License.  * You may obtain a copy of the License at:  *  *        http://www.st.com/software_license_agreement_liberty_v2  *  * Unless required by applicable law or agreed to in writing, software   * distributed under the License is distributed on an "AS IS" BASIS,   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  * See the License for the specific language governing permissions and  * limitations under the License.  *  ******************************************************************************  */ /* Includes ------------------------------------------------------------------*/#include "stm8s.h"/* Private defines -----------------------------------------------------------*//* Private function prototypes -----------------------------------------------*/void Delay (uint16_t nCount);/* Private functions ---------------------------------------------------------*/void main(void){GPIO_DeInit(GPIOD);GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_SLOW);  /* Infinite loop */  while (1)  {GPIO_WriteReverse(GPIOD, GPIO_PIN_3);    Delay(0xFFFF);  }  }void Delay(uint16_t nCount){  /* Decrement nCount value */  while (nCount != 0)  {    nCount--;  }}#ifdef USE_FULL_ASSERT/**  * @brief  Reports the name of the source file and the source line number  *   where the assert_param error has occurred.  * @param file: pointer to the source file name  * @param line: assert_param error line source number  * @retval : None  */void assert_failed(u8* file, u32 line){   /* User can add his own implementation to report the file name and line number,     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */  /* Infinite loop */  while (1)  {  }}#endif/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


Теперь посмотрим со стороны на эту среду.

По плюсам; у неё есть полноценная отладка, поддержка SPL из коробки. По минусам; она старая из этого вытекает, не очень приятный интерфейс и старый диалект си, на который многие свежие библиотеки придётся переписывать, в частности ставить переменные только вначале функций. Вес кода оставляет желать лучшего. Ну последний камень, этот инструмент может просто взять и вылететь, такое бывает, нечасто, но всё же.

Вторая среда, для тех кто не любит заморачиваться.


Второй подход это свободный и обновляемый компилятор SDCC, а так же среда PlatformIO.

Для начала установим VS Code и станем рабами Microsoft, далее найдём расширение PlatformIO.

image

Ждём пока миллион ползунков пройдёт до конца и перезапускаем программу. Открываем расширение (может быть и само откроется). Создаём новый проект и выбираем ближайшую плату с stm8s (микроконтроллер можно будет изменить в конфигурационном файле). В качестве фреймворка выбираем SPL мы же не ардуинщики, нас интересует хардкор.

Не удивляйтесь, проект будет создаваться прилично долго, потому как он на ходу будет подгружать компилятор, библиотеки и тд. И вот перед нами возник девственно голый проект, закрываем его он нам больше не нужен. В меню где мы создавали проект, открываем пример spl-blink, суть в том что blink генерирует неплохой шаблон в котором можно сразу писать. Правим пример под себя и прошиваем, всё моргает.

Разберем поподробнее среду разработки. Во первых весь проект должен лежать в src, иначе среда ведёт себя неадекватно. Во вторых открываем stm8s_conf.h и видим что все библиотеки кроме GPIO закомментированы, если этого не сделать то у мк не хватит памяти что бы поместить весь SPL в микроконтроллер (помните в начале я говорил что он загружает все функции что видит в код?).

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

/* Private define ------------------------------------------------------------*/#define _GPIO_DeInit#define _GPIO_Init#define _GPIO_WriteReverse#define _CLK_DeInit#define _CLK_SYSCLKConfig#define _TIM4_DeInit#define _TIM4_ITConfig#define _TIM4_ClearITPendingBit#define _TIM4_Cmd#define _TIM4_TimeBaseInit#define _TIM4_ClearFlag#define _HAL_GPIO_WritePin#define _GPIO_WriteLow#define _GPIO_WriteHigh//#define STM8S003/* Includes ------------------------------------------------------------------*/#include "stm8s.h"/* Uncomment the line below to enable peripheral header file inclusion */#if defined(STM8S105) || defined(STM8S005) || defined(STM8S103) || defined(STM8S003) ||\    defined(STM8S001) || defined(STM8S903) || defined (STM8AF626x) || defined (STM8AF622x)// #include "stm8s_adc1.h" #endif /* (STM8S105) ||(STM8S103) || (STM8S001) || (STM8S903) || (STM8AF626x) */#if defined(STM8S208) || defined(STM8S207) || defined(STM8S007) || defined (STM8AF52Ax) ||\    defined (STM8AF62Ax)// #include "stm8s_adc2.h"


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

Пройдёмся по преимуществам: работает почти из коробки, полностью бесплатно без попрошайничества, редакции языка обновляются и не придётся учить и переписывать код под си 80-90г. Сам интерфейс настраиваемый и намного приятнее. Для тех кто не любит win есть linux версия.

По минусам: нету полноценной отладки (над ней активно работают, но пока ничего приближённого к cosmic я не видел), в проекте небольшой хаос, раскидать по папкам пока нельзя.

Послевкусие.


Ну и на последок есть ещё среды, варианты и компиляторы, но либо это тот же SDCC вкрученный силой в Eclipse или ещё куда и работающий хуже чем в VS Code, либо это платные варианты IAR, Raisonance. Я лично пользуюсь и тем и тем, но чаще VS Code. Рекомендовать ничего не буду каждому своё, увидимся в комментариях)

Подробнее..

Использование бюджетных JTAG-отладчиков в PlatformIO

09.05.2021 16:23:04 | Автор: admin

В этом туториале я хотел бы рассказать о том, как использовать ультрабюджетные JTAG-отладчики CJMCU FT232H и RV-Debugger-Lite в PlatformIO для прошивки и отладки устройств на платформах ESP32 и GD32. Полноценной инструкции на просторах интернета я не нашел, и в процессе настройки столкнулся со многими проблемами, поэтому этот туториал появляется здесь для вашего удобства. Оговорюсь сразу, что настройка прописана для Linux, но для Windows принципиальной разницы нет за исключением танцев с Zadig.

CJMCU FT232H + ESR32 Rev1 aka ESP32Dev

Имеется в виду вот этот дебаггер на основе чипа FT232H:

И вот эта плата на основе ESP-WROOM-32:

Настройки platformio.ini:

[env:esp32dev]platform = espressif32framework = arduinoboard = esp32devmonitor_speed = 115200upload_speed = 921600debug_tool = minimoduleupload_protocol = minimodule

Здесь у нас CJMCU FT232H за 700 рублей будет прикидываться отладчиком FT2232H MINI MODULE за 4500. Для этого необходимо внести следующие изменения в файл (закомментированные мной строки начинаются с ##):

/home/<username>/.platformio/packages/tool-openocd-esp32/share/openocd/scripts/interface/ftdi/minimodule.cfg

## FTDI MiniModule## http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf#interface ftdi##ftdi_device_desc "FT2232H MiniModule"##ftdi_vid_pid 0x0403 0x6010ftdi_vid_pid 0x0403 0x6014# Every pin set as high impedance except TCK, TDI, TDO and TMSftdi_layout_init 0x0008 0x000b# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip)# This choice is arbitrary. Use other GPIO pin if desired.##ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020## added# interface 1 is the uartftdi_channel 0reset_config none

Немаловажно закомментировать описание отладчика minimodule"ftdi_device_desc", иначеCJMCU FT232H не получит прав доступа. В том же файле мы меняем пару VID/PID, и ее же прописываем в:

/etc/udev/rules.d/99-platformio-udev.rules

SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6014",GROUP="plugdev", MODE="0666"

чтобы отладчик определялся.

Подключение следующее:

Функция JTAG

CJMCU FT232H

ESP32Dev

TDO

AD2

GPIO15

TDI

AD1

GPIO12

TCK

AD0

GPIO13

TMS

AD3

GPIO14

+3.3V

3V3

GND

GND

CJMCU FT232H + Sipeed Longan Nano

Имеется в виду вот такая вот плата на основе чипа GD32VF103CBT6:

Настройки platformio.ini:

[env:sipeed-longan-nano]platform = gd32vframework = gd32vf103-sdkboard = sipeed-longan-nanomonitor_speed = 115200debug_tool = um232hupload_protocol = um232h

Здесь у нас CJMCU FT232H будет прикидываться отладчиком UM232H за 2000 рублей. Для этого необходимо внести следующие изменения в файл:

/home/<username>/.platformio/packages/tool-openocd-gd32v/share/openocd/scripts/interface/ftdi/um232h.cfg

## FTDI UM232H as a JTAG interface## http://www.ftdichip.com/Products/Modules/DevelopmentModules.htm#UM232H## This should also work with a UM232H-B, but that has not been tested.# Note that UM232H and UM232H-B are 3.3V only.#interface ftdi#ftdi_device_desc "UM232H"ftdi_vid_pid 0x0403 0x6014##ftdi_layout_init 0xfff8 0xfffb##ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100##ftdi_layout_signal nSRST -data 0x0200 -oe 0x0200# interface 1 is the uartftdi_channel 0# just TCK TDI TDO TMS, no resetftdi_layout_init 0x0008 0x000b#ftdi_layout_init 0x0c08 0x0f1breset_config none

Здесь у нас чип совпадает, поэтому только закомментируем ftdi_device_desc, и не забываем внести описанные ранее изменения в 99-platformio-udev.rules.

Возможно вам придется поставить недостающую библиотеку libhidapi-hidraw0:

sudo apt-get install -y libhidapi-hidraw0

Подключение следующее:

Функция JTAG

CJMCU FT232H

Sipeed Longan Nano

TDO

AD2

JTDO

TDI

AD1

JTDI

TCK

AD0

JTCK

TMS

AD3

JTMS

+3.3V

3V3

GND

GND

RV-Debugger-Lite + Sipeed Longan Nano

И напоследок я хочу описать, как использовать ультрабюджетный отладчик RV-Debugger-Lite за 200 рублей.

Настройки platformio.ini:

[env:sipeed-longan-nano]platform = gd32vframework = gd32vf103-sdkboard = sipeed-longan-nanomonitor_speed = 115200debug_tool = sipeed-rv-debuggerupload_protocol = sipeed-rv-debugger

Здесь мы будем прикидываться его старшим братом Sipeed RV-Debugger. Сейчас его в продаже нет, но, если мне не изменяет память, он стоил в пределах 1000 рублей. Для этого мы редактируем файл:

/home/<username>/.platformio/packages/tool-openocd-gd32v/share/openocd/scripts/interface/ftdi/sipeed-rv-debugger.cfg

interface ftdi##ftdi_device_desc "Dual RS232"ftdi_vid_pid 0x0403 0x6010#autoexit true#interface cmsis-daptransport select jtagftdi_layout_init 0x0008 0x001bftdi_layout_signal nSRST -oe 0x0020 -data 0x0020

Здесь мы только комментируем ftdi_device_desc, так как чип почти совпадает: у RV-Debugger FT2232D, а у RV-Debugger-Lite определяется как FT2232C, хотя на самом деле он CH552T. Пара VID/PID у них совпадает.

Подключение следующее:

Функция JTAG

RV-Debugger-Lite

Sipeed Longan Nano

TDO

TDO

JTDO

TDI

TDI

JTDI

TCK

TCK

JTCK

TMS

TMS

JTMS

3V3

3V3

GND

GND

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

Литература

PIO (platformio) JTAG FT232H ESP32

Бюджетный отладчик к ESP-32 и его настройка

Debugging Longan Nano

Подробнее..

Программирование устройств на основе модуля ESP32

09.10.2020 14:15:38 | Автор: admin
Микроконтроллер это интегральная схема, способная выполнять программы. Сегодня на рынке представлено множество таких моделей от самых разных производителей. Цены на эти устройства продолжают падать. Однокристальные чипы находят широкое применение в самых разнообразных сферах: от измерительных приборов до изделий развлечений и всевозможной домашней техники. В отличие от персональных компьютеров микроконтроллер сочетает в одном кристалле функции процессора и периферийных устройств, содержит оперативную память и постоянное запоминающее устройство в для хранения кода и данных, однако обладает значительно мешьшими вычислительными ресурсами. ESP32 это микроконтроллер, разработанный компанией Espressif Systems. ESP32 представляют собой систему на кристалле с интегрированным Wi-Fi и Bluetooth контроллерами. В серии ESP32 используется ядро Tensilica Xtensa LX6. Платы с ESP32 обладают хорошей вычислительной способностью, развитой периферией при этом весьма популярны ввиду низкой цены в диапазоне 7$ 14$: Aliexpress, Amazon.

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

  • Выбор среды разработки;
  • Настройка рабочего окружения, компиляция и загрузка проекта ESP-IDF;
  • Обработка сигналов ввода/вывода GPIO;
  • Широтно-импульсная модуляция с использованием модуля MCPWM;
  • Аппартный счетчик PCNT;
  • Подключение к WI-Fi и MQTT.


Обзор модуля ESP32-WROOM-32E


Согласно datasheet модуль содержит:

MCU
ESP32-D0WD-V3 embedded, Xtensa dual-core 32-bit LX6 microprocessor, up to 240 MHz
448 KB ROM for booting and core functions
520 KB SRAM for data and instructions
16 KB SRAM in RTC

Wi-Fi
802.11b/g/n
Bit rate: 802.11n up to 150 Mbps
A-MPDU and A-MSDU aggregation
0.4 s guard interval support
Center frequency range of operating channel: 2412 ~ 2484 MHz

Bluetooth
Bluetooth V4.2 BR/EDR and Bluetooth LE specification
Class-1, class-2 and class-3 transmitter
AFH
CVSD and SBC

Hardware
Interfaces: SD card, UART, SPI, SDIO, I 2 C, LED PWM, Motor PWM, I 2 S, IR, pulse counter, GPIO, capacitive touch sensor, ADC, DAC
40 MHz crystal oscillator
4 MB SPI flash
Operating voltage/Power supply: 3.0 ~ 3.6 V
Operating temperature range: 40 ~ 85 C
Dimensions: See Table 1

Certification
Bluetooth certification: BQB
RF certification: FCC/CE-RED/SRRC
Green certification: REACH/RoHS

image
Функциональная блок-диаграмма

Более подробно с особенностями микроконтроллера можно ознакомится на википедии .

В основе модуля лежит микросхема ESP32-D0WD-V3 *. Встроенный чип разработан с учетом возможности масштабирования и адаптации. Центральный процессор содержит два ядра, которыми можно управлять индивидуально, а тактовая частота ЦП регулируется от 80 МГц до 240 МГц. Чип также имеет сопроцессор с низким энергопотреблением, который можно использовать вместо ЦП для экономии энергии при выполнении задач, не требующих больших вычислительных мощностей, таких как мониторинг состояния пинов. ESP32 объединяет богатый набор периферийных устройств, начиная от емкостных сенсорных датчиков, датчиков Холла, интерфейса SD-карты, Ethernet, высокоскоростного SPI, UART, IS и IC.
Техническая документация представлена на официальном ресурсе

Информацию про распиновку модуля ESP-WROOM-32 можно легко найти на просторах сети, как здесь

Выбор среды разработки


Arduino IDE


Микроконтроллеры семейства AVR, а затем и платформа Arduino появились задолго до ESP32. Из ключевых особенностей Arduino является относительно низкий порог вхождения, позволяющий практически любому человеку создать что-то быстро и легко. Платформа внесла важный вклад в open source hardware сообщество и позволила приобщиться огромному числу радиолюбителей. Среду разработки Arduino IDE можно свободно скачать с оффсайта . Не смотря на очевидные ограничения по сравнению с профессиональной средой разработки, Arduino IDE покрывает 90% из того, что требуется достичь для любительских проектов. В сети также имеется достаточное количество статей на тему установки и настройки Arduino IDE для программирования модулей ESP32, например: Arduino core for the ESP32, habr.com, voltiq.ru и randomnerdtutorials.com.

Программируя ESP32 в среде Arduino необходимо учитывать распиновку, как указано на странице arduino-esp32

image
Распиновка модуля ESP32

Основное преимущество данного подхода разработки заключается в быстром вхождении и легкости создания проектов, используя те же принципы, как и для Arduino. А также использование многих библиотек, как и для Arduino. Еще одной хорошей особенностью является возможность совмещать библиотеки и принципы разработки Arduino с оригинальным ESP-IDF фреймворком.

PlatformIO


Как сказано на официальном ресурсе : Cross-platform PlatformIO IDE and Unified Debugger Static Code Analyzer and Remote Unit Testing. Multi-platform and Multi-architecture Build System Firmware File Explorer and Memory Inspection Другими словами PlatformIO это экосистема для разработки встроенных устройст, поддерживающая множество платформ, включая Arduino и ESP32. В качестве IDE используется Visual Studio Code или Atom. Установка и настройка достаточно простая после установки редактора кода выбираем PlatformIO из списка плагинов и устанавливаем. Опять же в сети много материалов на данную тему, начиная от официального источника здесь и здесь, и продолжая статьями с подробными иллюстрациями здесь и здесь.
PlatformIO по сравнению с Arduino IDE оладает всеми качествами современной среды разработки: организация проектов, поддержка плагинов, автодополнение кода и много другое.
Особенностью разработки на PlatformIO является унифицированная структура проекта для всех платформ

project_dir lib    README platformio.ini src     main.cpp


Каждый проект PlatformIO содержит файл конфигурации с именем platformio.ini в корневом каталоге проекта. platformio.ini имеет разделы (каждый из которых обозначен [заголовком]) и пары ключ / значение внутри разделов. Строки, начинающиеся с символа точка с зяпятой ; игнорируются и могут использоваться для комментариев. Параметры с несколькими значениями можно указать двумя способами:
  1. разделение значения с помощью , (запятая + пробел);
  2. многострочный формат, где каждая новая строка начинается как минимум с двух пробелов.


Следующей фичей разработки для ESP32 является возможность выбора фреймворка: Arduino или ESP-IDF. Выбирая Arduino в качестве фреймворка мы получаем ранее описанные преимущества разработки.

image

В составе PlatformIO входит удобный инструментарий билда, загрузки и отладки проектов

image

Espressif IoT Development framework


Для ESP32 компания Espressif разработала фреймворк под названием IoT Development Framework, известный как ESP-IDF. Его можно найти на Github здесь. Проект содержит очень хорошую документацию и снабжен примерами, которые можно брать за базу. Установка и настройка среды окружения хорошо описана в разделе Get Started. Имеется несколько вариантов установки и работы с фреймворком.

Клонирование проекта из репозитория и ручная установка утилит.

Клонирование проекта из Github

mkdir -p ~/espcd ~/espgit clone --recursive https://github.com/espressif/esp-idf.git


Для Windows установка утилит разработки возможна с помощью инсталлятора или с помощью скриптов для командной строки:

cd %userprofile%\esp\esp-idfinstall.bat


Для PowerShell

cd ~/esp/esp-idf./install.ps1


Для Linux и macOS

cd ~/esp/esp-idf./install.sh


Следующим шагом является настройка переменных окружений среды. Если установка инструментов разработки была выполнена на Windows с помощью инсталлятора, то ярлык на командную консоль добавляется в меню и на рабочий стол, после чего можно открывать командную оболочку и работать с проектами. Альтернативный спрособ запуска командной оболочки для Windows:

%userprofile%\esp\esp-idf\export.bat

или Windows PowerShell:
.$HOME/esp/esp-idf/export.ps1


Linux и macOS:
. $HOME/esp/esp-idf/export.sh

Следует обратить внимание на пробел между точкой и путем к скрипту

Далее в руководстве рекомендуется добавить алиас на скрипт настройки переменных окружения в пользовательский профиль если работа производитя в системе Linux или macOS. Для этого необходимо скопировать и вставить следующую команду в профиль своей оболочки (.profile, .bashrc, .zprofile, и т.д.):
alias get_idf='. $HOME/esp/esp-idf/export.sh'


Вызывая команду get_idf в консоль экспортируются необходимы переменные окружения. В моем случае также необходимо было прописать алиас на запуск виртуального окружения python

alias esp_va=source $HOME/.espressif/python_env/idf4.2_py2.7_env/bin/activate

и добавить его в следующий алиас
alias get_idf='esp_ve && . $HOME/esp/esp-idf/export.sh'


Для создание нового проекта с нуля можно склонировать исходники с github.com или скопировать из каталога с примерами esp-idf/examples/get-started/hello_world/.

Информация о структуре проекта, утилитах компиляции, загрузки, настройки и др. Находиться здесь

Проект представляет собой каталог со следующей структурой:

- myProject/             - CMakeLists.txt             - sdkconfig             - components/ - component1/ - CMakeLists.txt                                         - Kconfig                                         - src1.c                           - component2/ - CMakeLists.txt                                         - Kconfig                                         - src1.c                                         - include/ - component2.h             - main/       - CMakeLists.txt                           - src1.c                           - src2.c             - build/


Конфигурация проекта содержится в файле sdkconfig в корневом каталоге. Для изменения настроек необходимо вызвать команду idf.py menuconfig (или возможно idf.py.exe menuconfig в Windows).
В одном проекте обычно создаются два приложения project app (основной исполняемый файл, т.е. ваша кастомная прошивка) и bootloader app (программа начального загрузчика проекта).
components это модульные части автономного кода, которые компилируются в статические библиотеки (файлы .a) и связаны с приложением. Некоторые из них предоставляются самой ESP-IDF, другие могут быть получены из других источников.
Утилита командной строки idf.py предоставляет интерфейс для простого управления сборками проекта. Ее расположение в Windows %userprofile%\.espressif\tools\idf-exe\1.0.1\idf.py.exe. Она управляет следующими инструментами:

  • CMake настраивает проект для сборки
  • Консольный сборщик проекта: Ninja, либо GNU Make)
  • esptool.py для прошивки модулей.

Каждый проект имеет один файл CMakeLists.txt верхнего уровня, который содержит параметры сборки для всего проекта. Минимальная конфигурация файла включает следующие необходимые строчки:
cmake_minimum_required(VERSION 3.5)include($ENV{IDF_PATH}/tools/cmake/project.cmake)project(myProject)


Проект ESP-IDF можно рассматривать как совокупность компонентов, в котором каталог main является главным комонентом, запускающим код. Поэтому в данной директории также содержится файл CMakeLists.txt. Чаще всего его структура подобна:
idf_component_register(SRCS "main.c" INCLUDE_DIRS ".")

Где указывается, что исходный файл main.c необходимо зарегистрировать для компонента, а файлы заголовков содержаться в текущем каталоге. При необходимости можно переименовать каталог main устаовив EXTRA_COMPONENT_DIRS в прокте CMakeLists.txt. Подробно можно ознакомиться здесь

Помимо этого в каталоге находится исходный main.с (имя может быть любое) файл с точкой входа функцией void app_main(void).
Кастомые компоненты создатся в каталоге components. Подробнее процесс описан в разделе Component Requirements.

Подключение модуля ESP32 компьютеру в большинстве случаев проиводится с помощью USB-кабеля подобно платам Arduino за счет имеющегося бутлоадера. Подробнее процесс описан здесь . Едиственное, что необходимо это наличие драйвера конвертора USB to Uart в системе, который можно скачать по ссылкам из приведенного источника. После установки драйвера, необходимо определить номер COM-порта в системе для загрузки скомпилированной прошивки в модуль.
Конфигурирование. В большинстве случаев подходят настройки по умолчанию. Но для вызова консольного интервейса меню необходимо перейти в каталог проекта и в командной строке набрать:

idf.py menuconfig


image
Меню с конфигурационными настройками

После вызова этой команды файл sdkconfig будет создан, если его ранее не было или заново сконфигурирован. В более ранних туториалах можно встретить команды make menuconfig, что являются уставревшими.
Добавление кастомных настроек в файл sdkconfig возможно вручную, например:

## WiFi Settings кастомное меню #CONFIG_ESP_HOST_NAME="имя точки"CONFIG_ESP_WIFI_SSID="название точки доступа"CONFIG_ESP_WIFI_PASSWORD="пароль"


Но предпочтительным является способ с помощью дополнительного конфигурационного файла Kconfig.projbuild, который необходимо располагать в каталоге с компонентом. Содержимое файла может быть следующим:

# put here your custom config valuemenu "Example Configuration"config ESP_WIFI_SSID    string "Keenetic"    default "myssid"    help    SSID (network name) for the example to connect to.config ESP_WIFI_PASSWORD    string "password"    default "mypassword"    help    WiFi password (WPA or WPA2) for the example to use.endmenu


После вызова команды idf.py menuconfig в файле sdkconfig автоматически добавиться дополнительный раздел. Вызов команды idf.py menuconfig возможен и в проекте PlatformIO, однако нужно учитывать факт отличия структура проекта PlatformIO от классического ESP-IDF, из-за чего файл sdkconfig с может заново сгенериться и потярять кастомные настройки. Тут возможны вышеупомянутые варианты правка файла руками, временнное переименование каталога src в main, или настройка файла CMakeLists.txt

Компиляция и загрузка проекта.
Для билда проекта необходимо набрать команду

idf.py build


Эта команда скомпилирует приложение и все компоненты ESP-IDF, а затем сгенерирует загрузчик, таблицу разделов и двоичные файлы приложения.

$ idf.py buildRunning cmake in directory /path/to/hello_world/buildExecuting "cmake -G Ninja --warn-uninitialized /path/to/hello_world"...Warn about uninitialized values.-- Found Git: /usr/bin/git (found version "2.17.0")-- Building empty aws_iot component due to configuration-- Component names: ...-- Component paths: ...... (more lines of build system output)[527/527] Generating hello-world.binesptool.py v2.3.1Project build complete. To flash, run this command:../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin  build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.binor run 'idf.py -p PORT flash'


Следует учитывать, что первоначальный процесс компиляции даже простого проекта занимает время, так, в отличие от Arduino фреймворка компилируются многие дополнительные модули ESP-IDF. Дальнейшее изменение исходников приводит только к компиляции этих же файлов. Исключение составляет изенения конфигурации.

Для загрузки скомпилированных двоичных файлов (bootloader.bin, partition-table.bin и hello-world.bin) на плату ESP32 необходимо запустить команду

idf.py -p PORT [-b BAUD] flash


где PORT мы заменяет на тот, что нам нужно (COM1, /dev/ttyUSB1), а также опционально можем изменить скорость загрузки, указав необходимое значения для BAUD

Для остлеживания загруженной программы можно использовать любую утилиту мониторинга com-порта, как HTerm , CoolTerm , или использовать утилиту мониторинга IDF Monitor, для ее запуска необходимо ввести команду:

idf.py -p PORT monitor


ESP-IDF Eclipse Plugin



Документация по установки и настройки плагина находится здесь

image

Предустановки для использования:

  • Java 11 and above; (хотя и на java 8 работает, возможно из-за этого глюки);
  • Python 3.5 and above;
  • Eclipse 2020-06 CDT;
  • Git;
  • ESP-IDF 4.0 and above ;


Плагин довольно неплохо интегрирован в среду разработки, автоматизирует львиную долю функционала. Но, к сожалению, не без ложки дегтя. В eclipse версиях позже 2019-09 в esp-idf проектах в Windows до сих пор присутствует баг с индексированием исходных файлов

image

Кроме этого наблюдаются и другие глюки, когда проект просто не билдится по непонятным причинам. Помогает только зарытие проекта и перезагрузка eclipse.

ESP-IDF Visual Studio Code Extension


И последний, на мой взгляд самый интересный вариант это официальный плагин для Visual Studio Code.
Как и PlatformIO легко устанавливается из раздела расширений. Установка и настройка ESP-IDF фреймворка в этом расширении представлена в качестве меню onboarding, о чем также говорится в описании. Загрузка и установка всех компонентов происходит автоматически в процессе прохождения этапов меню. Можно привести все скрины процесса, но они интуитивно понятны, и практически не требуют пояснения. В пользу PlatformIO можно отметить более удобный инструментарий билда, загрузки и мониторинга проекта. В отличие от этого esp-idf плагин управляется с помощью меню команд, что можно вызвать с помощью клавиши F1, или сочетании клавишь, описанных в мануале.

image
Первоначальная настройка плагина

Преимущество использования плагина в том, что соблюдается классическая структура проекта, нет необходимости как-то еще шаманить с настройками (в PlatformIO такая необходимость возникает). Есть один нюанс, если мы хотим открыть ранее созданных проект в visual studio code с esp-idf плагином, то нам всего лишь необходимо скопировать в корень с проектом каталог .vscode, который можно получить сгенерировав хотя бы один раз шаблонный проект с помощью esp-idf плагина.

image
Меню команд

FreeRTOS



Согласно википедии FreeRTOS многозадачная операционная система реального времени (ОСРВ) для встраиваемых систем.. FreeRTOS обеспечивает мультизадачность за счет совместного использования процессорного времени всеми потоками, или в терминологии ОС задачами (task). На мой взгляд наиболее полное и внятное руководство по FreeRTOS на русском находится здесь . На языке оригинала мануалы можно изучить из официального источника. Я лишь приведу рисунок состояния задач

image

FreeRTOS была портирована на широкий спектр аппаратных платформ, включая процессоры Xtensa, используемые в ESP32. Подробнее можно ознакомиться в документации

GPIOs


GPIO или универсальный ввод/вывод это возможность дискретного управления пина сигналом 1 или 0.

Как видно из самого названия такие пины имеют два рабочих режима ввод или вывод. В первом случая мы читаем значение, во втором записываем. Еще одним важным фактором при работе с GPIO является уровень напряжения. ESP32 это устройство с напряжением 3,3 В. Поэтому следует быть осторожным при работе с другими устройствами, которые имеют 5В и выше. Также важно понимать, что максимальный ток, которым можно нагружать вывод GPIO, составляет 12 мА. Для использования функций GPIO, предоставляемых ESP-IDF нам необходимо подключить заголовок driver/gpio.h. Затем можно вызвать gpio_pad_select_gpio (), чтобы указать функцию данного вывода. На ESP32 доступно 34 различных GPIO. Они обозначены как:

  • GPIO_NUM_0 GPIO_NUM_19
  • GPIO_NUM_21 GPIO_NUM_23
  • GPIO_NUM_25 GPIO_NUM_27
  • GPIO_NUM_32 GPIO_NUM_39

Следующая нумерация не входит в число пинов 20, 24, 28, 29, 30 и 31.
Таблицу с распиновком можно посмотреть здесь
Следует обратить внимание, что пины GPIO_NUM_34 GPIO_NUM_39 используют только режим ввода. Их нельзя использовать для вывода сигнала. Кроме того, контакты 6, 7, 8, 9, 10 и 11 используются для взаимодействия с внешней флеш-картой по SPI, не рекомендуется их использовать для других целей, но если очень хочется, то можно. Тип данных gpio_num_t это перечисление со значениями, соответствующими номерам пинов. Рекомендуется использовать эти значения, а не числа. Направление пина устанавливается с помощью функции gpio_set_direction (). Например, для установки пина как выход:

gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);


Для установки пина в качестве входа:

gpio_set_direction(GPIO_NUM_17, GPIO_MODE_INPUT);


Если мы настроили GPIO как выход, то можем установить его значение равным 1 или 0, вызывая gpio_set_level ().

Следующий пример переключает GPIO раз в секунду:

gpio_pad_select_gpio(GPIO_NUM_17);gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);while(1) {    printf("Off\n");    gpio_set_level(GPIO_NUM_17, 0);    vTaskDelay(1000 / portTICK_RATE_MS);    printf("On\n");    gpio_set_level(GPIO_NUM_17, 1);    vTaskDelay(1000 / portTICK_RATE_MS);}


В качестве альтернативы настройке всех атрибутов отдельных пинов мы можем установить свойства одного или нескольких контактов с помощью вызова функции gpio_config (). Она принимает в качестве входных данных структуру gpio_config_t и устанавливает направление, pull up, pull down и настройки прерывания для всех выводов, представленных в битовой маске. Например:

gpio_config_t gpioConfig;gpioConfig.pin_bit_mask = (1 << 16) | (1 << 17);gpioConfig.mode = GPIO_MODE_OUTPUT;gpioConfig.pull_up_en = GPIO_PULLUP_DISABLE;gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE;gpioConfig.intr_type = GPIO_INTR_DISABLE;gpio_config(&gpioConfig);


Pull up и pull down настройки
Обычно читается, что входной пин GPIO имеет сигнал высокого или низкого уровня. Это означает, что он подключен к источнику питания или к земле. Однако, если пин не подключен ник чему, то он находится в плавающем (floating) состоянии. Часто необходимо установить начальный уровень неподключенного пина как высокий или низкий. В таком случае производится аппаратная (подключение c помощью резисторов) или программная поддяжка вывода соответственно к +V pull up или к 0 pull down. В ESP32 SDK мы можем определить GPIO как pull up или pull down с помощью функции gpio_set_pull_mode (). Эта функция принимает в качестве входных данных номер контакта, который мы хотим установить, и режим поддяжки, связанный с этим контактом. Например:
gpio_set_pull_mode (21, GPIO_PULLUP_ONLY);


GPIO обработка прерывания
Чтобы обнаружить изменение входного сигнала на пине мы можем периодически опрашивать его сотояние, однако это не лучшее решение по ряду причин. Во-первых мы должны циклически делать проверку, тратя процессорное время. Во-вторых в момент опроса состояние пина может быть уже не актуальное за счет задержки и можно пропустить входные сигналы. Решением этих проблем является прерывание. Прерывание похоже на дверной звонок. Без звонка нам придется периодически проверять, есть ли кто-нибудь у двери. В исходном коде мы можем определить функцию обратного вызова прерывания, которая будет вызываться, когда вывод изменяет значение своего сигнала. Мы также можем определить, что является причиной вызова обработчика, установив следующие параметры:
  • Disable не вызывать прерывание при изменении сигнала;
  • PosEdge вызов обработчика прерывания при изменении с низкого на высокий;
  • NegEdge вызов обработчика прерывания при изменении с высокого на низкий;
  • AnyEdge вызов обработчика прерывания либо при изменении с низкого на высокий, либо при изменении с высокого на низкий;


image

Обработчик прерывания может быть отмечен для загрузки в ОЗУ во время компиляции. По умолчанию сгенерированный код находится во флэш-памяти. Если предварительно пометить его как IRAM_ATTR, он будет готов к немедленному выполнению из опреативной памяти.

void IRAM_ATTR my_gpio_isr_handle(void *arg) {...}


image

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

image

Следующий пример демонстрирует обработку прерывания входных сигналов. Настоятельно рекомендую ознакомится с управлением очередями во FreeRTOS для дальнейшего понимания кода, если вы еще с этим не знакомы. В примере показаны две задачи:
test1_task, которая разблокируется при наступлении события прерывания при активации сигнала на пине 25, и в консоль единократно выводится сообщение Registered a click;
test2_task периодически опрашивается, и при активации сигнала на пине 26 каждые 100 мсек в консоль выводится сообщение GPIO 26 is high!.
В примере также установлен программный таймер xTimer, он не является обязательным для данного случая, скорее как пример асинхронной задержки.
Антидребезг производится с помощью функции timeval_durationBeforeNow, которая проверяет, длится ли нажатие более 100 мсек. Есть и другие программные шаблоны против дребезга, но смысл примерно тот же. В составе ESP-IDF также имеется пример работы GPIO

Обработка входных сигналов
#include <stdio.h>#include "freertos/FreeRTOS.h"#include "freertos/task.h"#include "driver/gpio.h"#include "esp_log.h"#include "freertos/queue.h"#include "c_timeutils.h"#include "freertos/timers.h"static char tag[] = "test_intr";static QueueHandle_t q1;TimerHandle_t xTimer;#define TEST_GPIO (25)static void handler(void *args) {    gpio_num_t gpio;    gpio = TEST_GPIO;    xQueueSendToBackFromISR(q1, &gpio, NULL);}void test1_task(void *ignore) {    struct timeval lastPress;    ESP_LOGD(tag, ">> test1_task");    gpio_num_t gpio;    q1 = xQueueCreate(10, sizeof(gpio_num_t));    gpio_config_t gpioConfig;    gpioConfig.pin_bit_mask = GPIO_SEL_25;    gpioConfig.mode = GPIO_MODE_INPUT;    gpioConfig.pull_up_en = GPIO_PULLUP_DISABLE;    gpioConfig.pull_down_en = GPIO_PULLDOWN_ENABLE;    gpioConfig.intr_type = GPIO_INTR_POSEDGE;    gpio_config(&gpioConfig);    gpio_install_isr_service(0);    gpio_isr_handler_add(TEST_GPIO, handler, NULL);    while(1) {        //ESP_LOGD(tag, "Waiting on queue");        BaseType_t rc = xQueueReceive(q1, &gpio, portMAX_DELAY);        //ESP_LOGD(tag, "Woke from queue wait: %d", rc);        struct timeval now;        gettimeofday(&now, NULL);        if (timeval_durationBeforeNow(&lastPress) > 100) {            if(gpio_get_level(GPIO_NUM_25)) {                ESP_LOGD(tag, "Registered a click");                if( xTimerStart( xTimer, 0 ) != pdPASS ) {                    // The timer could not be set into the Active state.                }            }        }        lastPress = now;    }    vTaskDelete(NULL);}void test2_task(void *ignore) {    gpio_set_direction(GPIO_NUM_26, GPIO_MODE_INPUT);    gpio_set_pull_mode(GPIO_NUM_26, GPIO_PULLDOWN_ONLY);    while(true) {        if(gpio_get_level(GPIO_NUM_26)) {            ESP_LOGD(tag, "GPIO 26 is high!");            if( xTimerStart( xTimer, 0 ) != pdPASS ) {                    // The timer could not be set into the Active state.                }        }        vTaskDelay(100/portTICK_PERIOD_MS);    }}void vTimerCallback( TimerHandle_t pxTimer ) {    ESP_LOGD(tag, "The timer has expired!");}void app_main(void){    xTaskCreate(test1_task, "test_task1", 5000, NULL, 8, NULL);    xTaskCreate(test2_task, "test_task2", 5000, NULL, 8, NULL);    xTimer = xTimerCreate("Timer",       // Just a text name, not used by the kernel.                            2000/portTICK_PERIOD_MS,   // The timer period in ticks.                            pdFALSE,        // The timers will auto-reload themselves when they expire.                            ( void * ) 1,  // Assign each timer a unique id equal to its array index.                            vTimerCallback // Each timer calls the same callback when it expires.                        );}



PCNT (Pulse Counter)



Модуль PCNT (счетчик импульсов) предназначен для подсчета количества нарастающих и / или спадающих фронтов входного сигнала. Каждый блок модуля имеет 16-битный регистр со знаком и два канала, которые можно настроить для увеличения или уменьшения значения счетчика. Каждый канал имеет входной сигнал, который фиксирует изменение сигнала, а также вход управления, который можно использовать для включения или отключения счета. Входы имеют дополнительные фильтры, которые можно использовать для устранения нежелательных выбросов сигнала.

Счетчик PCNT имеет восемь независимых счетных единиц (units), пронумерованных от 0 до 7. В API они указаны с помощью pcnt_unit_t. Каждый модуль имеет два независимых канала, пронумерованных 0 и 1 и указанны с помощью pcnt_channel_t.
Конфигурация предоставляется отдельно для каждого канала устройства с помощью pcnt_config_t и охватывает:

  • Номер юнита и номер канала к которому относится эта конфигурация;
  • Номера GPIO импульсного входа и входа стробирующего импульса;
  • Две пары параметров: pcnt_ctrl_mode_t и pcnt_count_mode_t для определения того, как счетчик реагирует в зависимости от состояния управляющего сигнала и того, как выполняется подсчет положительного / отрицательного фронта импульсов.
  • Два предельных значения (минимальное / максимальное), которые используются для установления точек наблюдения и запуска прерываний, когда счетчик импульсов достигает определенного предела.


Затем настройка конкретного канала выполняется путем вызова функции pcnt_unit_config () с указанной выше конфигурационной структурой pcnt_config_t в качестве входного параметра.
Чтобы отключить импульс или управляющий вход в конфигурации, нужно указать PCNT_PIN_NOT_USED вместо номера GPIO.

После выполнения настройки с помощью pcnt_unit_config () счетчик сразу же начинает работать. Накопленный значение счетчика можно проверить, вызвав pcnt_get_counter_value ().

Следующие функции позволяют управлять работой счетчика: pcnt_counter_pause (), pcnt_counter_resume () и pcnt_counter_clear ()

Также возможно динамически изменять ранее установленные режимы счетчика с помощью pcnt_unit_config (), вызывая pcnt_set_mode ().

При желании контакт импульсного входа и контакт входа управления можно изменить на лету с помощью pcnt_set_pin ().

Модуль PCNT имеет фильтры на каждом из импульсных и управляющих входов, добавляя возможность игнорировать короткие выбросы в сигналах. Длина игнорируемых импульсов предоставляется в тактовых циклах APB_CLK с помощью вызова pcnt_set_filter_value (). Текущие настройки фильтра можно проверить с помощью pcnt_get_filter_value (). Цикл APB_CLK работает на частоте 80 МГц.
Фильтр запускается / приостанавливается вызовом pcnt_filter_enable () / pcnt_filter_disable ().
Следующие события, определенные в pcnt_evt_type_t, могут вызвать прерывание. Событие происходит, когда счетчик импульсов достигает определенных значений:

  • Минимальные или максимальные значения счетчика: counter_l_lim или counter_h_lim, указанные в pcnt_config_t;
  • Достижение уставки 0 или уставки 1, что устанавливаются с помощью функции pcnt_set_event_value ().
  • Количество импульсов = 0


Чтобы зарегистрировать, включить или отключить прерывание для указанных выше событий, необходимо вызвать pcnt_isr_register (), pcnt_intr_enable (). и pcnt_intr_disable (). Чтобы включить или отключить события при достижении пороговых значений, также потребуется вызвать функции pcnt_event_enable () и pcnt_event_disable ().
Чтобы проверить, какие пороговые значения установлены на данный момент, нужно использовать функцию pcnt_get_event_value ().
Пример из ESP-IDF представлен здесь

Я использовать счетчик PCNT для вычислени скорости вращения колеса. Для этого необходимо считать количество импульсов на оборот, после чего обнлять счетчик.

Пример кода
typedef struct {      uint16_t delay; //delay im ms      int pin;      int ctrl_pin;      pcnt_channel_t channel;      pcnt_unit_t unit;      int16_t count;} speed_sensor_params_t;esp_err_t init_speed_sensor(speed_sensor_params_t* params) {      /* Prepare configuration for the PCNT unit */    pcnt_config_t pcnt_config;    // Set PCNT input signal and control GPIOs    pcnt_config.pulse_gpio_num = params->pin;    pcnt_config.ctrl_gpio_num = params->ctrl_pin;    pcnt_config.channel = params->channel;    pcnt_config.unit = params->unit;    // What to do on the positive / negative edge of pulse input?    pcnt_config.pos_mode = PCNT_COUNT_INC;   // Count up on the positive edge    pcnt_config.neg_mode = PCNT_COUNT_DIS;   // Keep the counter value on the negative edge    pcnt_config.lctrl_mode = PCNT_MODE_REVERSE; // Reverse counting direction if low    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;    // Keep the primary counter mode if high    pcnt_config.counter_h_lim = INT16_MAX;    pcnt_config.counter_l_lim = - INT16_MAX;     /* Initialize PCNT unit */    esp_err_t err = pcnt_unit_config(&pcnt_config);    /* Configure and enable the input filter */    pcnt_set_filter_value(params->unit, 100);    pcnt_filter_enable(params->unit);    /* Initialize PCNT's counter */    pcnt_counter_pause(params->unit);    pcnt_counter_clear(params->unit);    /* Everything is set up, now go to counting */    pcnt_counter_resume(params->unit);    return err;}int32_t calculateRpm(speed_sensor_params_t* params) {    pcnt_get_counter_value(params->unit, &(params->count));    int32_t rpm = 60*(1000/params->delay)*params->count/PULSE_PER_TURN;    pcnt_counter_clear(params->unit);    return rpm;}



Широтно-импульсная модуляция (ШИМ) с использованием модуля MCPWM


Информация о модуле представлена здесь
В сети имеется много статей на тему ШИМ, особенно если искать применительно к Arduino.
Википедия дает короткое и емкое определение Широтно-импульсная модуляция (ШИМ, англ. pulse-width modulation (PWM)) процесс управления мощностью методом пульсирующего включения и выключения прибора. Принцип регулирования с помощью ШИМ изменение ширины импульсов при постоянной амплитуде и частоте сигнала.

image

Частота ШИМ Ардуино 488,28 Гц., разрешение 8 разрядов (0255), и имеется возможность использования шести аппаратных выводов 3, 5, 6, 9, 10, 11. Однако, используя настройки регисторов микроконтроллера AVR можно добиться и других значений частоты ШИМ.
Микроконтроллер ESP32 имеет в своем арсенале отдельный модуль MCPWM, а точнее два модуля, каждый из которых имеет три пары ШИМ выводов

image

Далее в документации выходы отдельного блока помечены как PWMxA / PWMxB.
Более подробная блок-схема блока MCPWM представлена ниже. Каждая пара A / B может синхронизироваться любым из трех таймеров Timer 0, 1 и 2. Один и тот же таймер может использоваться для синхронизации более чем одной пары выходов ШИМ. Каждый блок также может собирать входные данные, такие как сигналы синхронизации, обнаруживать сигналы тревог, такие как перегрузка по току или перенапряжение двигателя, а также получать обратную связь с помощью сигналов захвата, например, на положение ротора.

image

Объем конфигурации зависит от типа двигателя, в частности, от того, сколько выходов и входов требуется, и какой будет последовательность сигналов для управления двигателем.
В нашем случае опишем простую конфигурацию для управления щеточным двигателем постоянного тока, который использует только некоторые из доступных ресурсов MCPWM. Пример схемы показан ниже. Он включает в себя H-мост для переключения поляризации напряжения, подаваемого на двигатель (M), и обеспечения достаточного тока для его управления.

image

Конфигурация включает следующие шаги:

  • Выбор блока MPWn, который будет использоваться для привода двигателя. На плате ESP32 доступны два модуля, перечисленных в mcpwm_unit_t.
  • Инициализация двух GPIO в качестве выходных сигналов в выбранном модуле путем вызова mcpwm_gpio_init (). Два выходных сигнала обычно используются для управления двигателем вправо или влево. Все доступные параметры сигналов перечислены в mcpwm_io_signals_t. Чтобы установить более одного вывода за раз, нужно использовать функцию mcpwm_set_pin () вместе с mcpwm_pin_config_t.
  • Выбор таймера. В устройстве доступны три таймера. Таймеры перечислены в mcpwm_timer_t.
  • Установка частоты таймера и начальной загрузки в структуре mcpwm_config_t.
  • Вызов mcpwm_init () с указанными выше параметрами.


Способы управления ШИМ следующие:

  • Мы можем установить высокое или низкое значение для конкретного сигнала с помощью функции mcpwm_set_signal_high () или mcpwm_set_signal_low (). Это заставит двигатель вращаться с максимальной скоростью или остановиться. В зависимости от выбранного выхода A или B двигатель будет вращаться вправо или влево.
  • Другой вариант подать на выходы сигнал ШИМ, вызвав mcpwm_start () или mcpwm_stop (). Скорость двигателя будет пропорциональна режиму ШИМ.
  • Чтобы изменить режим ШИМ, необходимо вызвать mcpwm_set_duty () и указать значение режима в ролцентах. При желании можно вызвать mcpwm_set_duty_in_us (), чтобы устанавливать значение в микросекундах. Проверить текущее установленное значение можно с помощью вызова mcpwm_get_duty (). Фазу сигнала ШИМ можно изменить, вызвав mcpwm_set_duty_type (). Коэффициент заполнения устанавливается индивидуально для каждого выхода A и B с помощью mcpwm_generator_t. Значение коэффициента заполнения относится к длительности высокого или низкого выходного сигнала. Это настраивается при вызове mcpwm_init (), как описано выше, и выборе одной из опций в mcpwm_duty_type_t.


Пример кода для коллекторного двигателя находится здесь

В своем проекте я практически использовал код из примера, немного подкорректировав его и добавил управление вторым двигателем. Для независимого управления ШИМ-каналами необходимо каждый из них настроить отдельным таймером, например MCPWM_TIMER_0 и CPWM_TIMER_1:

Пример кода
void mcpwm_example_gpio_initialize(void){    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_PWM0A_OUT);    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0B, GPIO_PWM0B_OUT);    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_PWM1A_OUT);    mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1B, GPIO_PWM1B_OUT);    //mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_SYNC_0, GPIO_SYNC0_IN);    mcpwm_config_t pwm_config;    pwm_config.frequency = 1000;    //frequency = 500Hz,    pwm_config.cmpr_a = 0;    //duty cycle of PWMxA = 0    pwm_config.cmpr_b = 0;    //duty cycle of PWMxb = 0    pwm_config.counter_mode = MCPWM_UP_COUNTER;    pwm_config.duty_mode = MCPWM_DUTY_MODE_0;    mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);    //Configure PWM0A & PWM0B with above settings    mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config);    //Configure PWM0A & PWM0B with above settings          // deadtime (see clock source changes in mcpwm.c file)    mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_BYPASS_FED, 80, 80);   // 1us deadtime    mcpwm_deadtime_enable(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_BYPASS_FED, 80, 80);  }



Подключение к WI-Fi и работа с MQTT


Тема протокола Wi-FI достаточно обширная. Для описания протокола понадобиться серия отдельных статей. В официальном руководстве можно ознакомиться с разделом Wi-Fi driver. Описание программного API находится здесь . Примеры кода можно посмотреть здесь

Библиотеки Wi-Fi обеспечивают поддержку для настройки и мониторинга сетевых функций ESP32 WiFi. Следующие доступные конфигурации:

  • Режим станции (также известный как режим STA или режим клиента WiFi). ESP32 подключается к точке доступа.
  • Режим AP (он же режим Soft-AP или режим точки доступа). Станции подключаются к ESP32.
  • Комбинированный режим AP-STA (ESP32 одновременно является точкой доступа и станцией, подключенной к другой точке доступа).
  • Различные режимы безопасности для вышеперечисленных (WPA, WPA2, WEP и т. Д.)
  • Поиск точек доступа (активное и пассивное сканирование).
  • Смешанный режим для мониторинга пакетов WiFi IEEE802.11.


MQTT протокол. Ознакомится с темой можно здесь или здесь . Руководство ESP-IDF с примерами находится здесь .

Для настройки MQTT в коде сначала необходимо подключиться к сети Wi-Fi. После чего установить подключение к брокеру. Обработка сообщения производится в коллбеке в качестве параметра которого выступает esp_mqtt_event_handle_t event. Если тип события равен MQTT_EVENT_DATA, значит можно парсить топик и данные. Можно настроить различное поведение в результате успешного подключения, отключение и подписки на топики.

Пример подключени к Wi-Fi:
tcpip_adapter_init();    wifi_event_group = xEventGroupCreate();    ESP_ERROR_CHECK(esp_event_loop_create_default());    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );    wifi_config_t sta_config = {        .sta = {            .ssid = CONFIG_ESP_WIFI_SSID,            .password = CONFIG_ESP_WIFI_PASSWORD,            .bssid_set = false        }    };    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &sta_config) );    ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]", CONFIG_ESP_WIFI_SSID, "******");    ESP_ERROR_CHECK( esp_wifi_start() );    ESP_LOGI(TAG, "Waiting for wifi");    xEventGroupWaitBits(wifi_event_group, BIT0, false, true, portMAX_DELAY);    //MQTT init    mqtt_event_group = xEventGroupCreate();    mqtt_app_start(mqtt_event_group);



Подключение к MQTT брокеру
void mqtt_app_start(EventGroupHandle_t event_group){    mqtt_event_group = event_group;    const esp_mqtt_client_config_t mqtt_cfg = {        .uri = "mqtt://mqtt.eclipse.org:1883",    //mqtt://mqtt.eclipse.org:1883        .event_handle =  mqtt_event_handler,        .keepalive = 10,        .lwt_topic = "esp32/status/activ",        .lwt_msg = "0",        .lwt_retain = 1,    };    ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());    client = esp_mqtt_client_init(&mqtt_cfg);    esp_mqtt_client_start(client);



Обработчик MQTT
esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event){    esp_mqtt_client_handle_t client = event->client;    int msg_id;    command_t command;    // your_context_t *context = event.context;    switch (event->event_id) {        case MQTT_EVENT_CONNECTED:             xEventGroupSetBits(mqtt_event_group, BIT1);            ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");            msg_id = esp_mqtt_client_subscribe(client, "esp32/car/#", 0);            msg_id = esp_mqtt_client_subscribe(client, "esp32/camera/#", 0);            ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);            break;        case MQTT_EVENT_DISCONNECTED:            ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");            break;        case MQTT_EVENT_SUBSCRIBED:            ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);            msg_id = esp_mqtt_client_publish(client, "esp32/status/activ", "1", 0, 0, 1);            ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);            break;        case MQTT_EVENT_UNSUBSCRIBED:            ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);            break;        case MQTT_EVENT_PUBLISHED:            ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);            break;        case MQTT_EVENT_DATA:            ESP_LOGI(TAG, "MQTT_EVENT_DATA");            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);            printf("DATA=%.*s\r\n", event->data_len, event->data);            memset(topic, 0, strlen(topic));            memset(data, 0, strlen(data));            strncpy(topic, event->topic, event->topic_len);            strncpy(data, event->data, event->data_len);            command_t command = {                .topic = topic,                .message = data,            };            parseCommand(&command);            break;        case MQTT_EVENT_ERROR:            ESP_LOGI(TAG, "MQTT_EVENT_ERROR");            break;        default:            break;    }    return ESP_OK;}



На этом я завершаю свое повествование об использовании модуля ESP32. В статье были рассмотрены примеры на ESP-IDF, как фреймворка максимально использующего ресурсы модуля. Программирование с использованием других платформ, как javaScript, MicroPython, Lua можно найти на соответствующих ресурсах. В следующей статье, как уже упоминалось, я приведу практический пример использовании микроконтроллера. Сравню программный подход Arduino и ESP-IDF.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru