This is the full developer documentation for KitsLab Wiki # KitsLab Wiki > База знаний, примеры и документация для отладочных плат KitsLab. import { LinkCard, CardGrid } from '@astrojs/starlight/components'; ## Платы ## Инструменты # Отладочные платы > Отладочные платы KitsLab на STM32 и RISC-V: документация, распиновки и примеры. - [Доска H723](/boards/bh723/) - [Щепа F042](/boards/sf042/) - [Щепа L432](/boards/sl432/) - [Вагонка-ВГ015](/boards/vg015/) # Доска H723 > Доска H723 — отладочная плата на STM32H723ZGT6 (550 МГц) с SDRAM 32 МБ, Wi-Fi/BLE на ESP32-C2 и слотом microSD: характеристики, распиновка разъёмов, быстрый старт, схема. Распиновка Доски H723: разъёмы J1 и J2, SWD-разъём, кнопка BOOT/USER ## Характеристики - Микроконтроллер: STM32H723ZGT6 - Ядро: Arm Cortex-M7, кэш инструкций 32 КБ и кэш данных 32 КБ - Частота ядра: 550 МГц - Flash: 1 МБ - ОЗУ: 564 КБ - Напряжение питания: 1,62–3,6 В - 2× 16-битных АЦП, 1× 12-битный АЦП - Таймеры (20) - SPI/I2S/SAI, ETH, FDCAN, FMC, I2C, OCTOSPI, UART, USB_OTG - DCMI, DMA2D, LTDC (до 24 бит) - PSSI (до 16 бит) - RNG - CORDIC, CRC, DFSDM, FMAC - GPIO на разъёмах: 51 - SDRAM MT48LC16M16A2, 256 Мбит (32 МБ), 16-битная шина - Wi-Fi/BLE модуль ESP32-C2, связь с STM32 по SPI 62,5 МГц - Слот microSD (SDMMC, 4 бита, 50 МГц) - USB-C: питание, сеть USB-NCM, прошивка по USB (DFU) - Кнопки RESET и BOOT/USER, светодиод - Разъём SWD для отладчика - Схема: [h723-sch.pdf](/media/boards/h723-sch.pdf) - [GitHub — прошивка и примеры](https://github.com/Kits-Lab-Dev/Board-H723) - [Рецепты — готовые модули на C](/boards/bh723/recipes/) - [ПО для разработки](/boards/bh723/software/) Назначение выводов STM32H723 на плате (CubeMX) ## Описание Отладочная плата ***Доска-H723*** предназначена для разработки и тестирования высокопроизводительных встраиваемых приложений. Она сочетает быстрое ядро, большую внешнюю память, Wi-Fi и BLE, microSD и разъёмы с выведенными линиями LTDC, I2C, SPI, UART, CAN, АЦП и ШИМ — подойдёт для IoT-устройств, устройств с графическим экраном, промышленной автоматики и других требовательных проектов. ## Быстрый старт Плата поставляется с прошитыми STM32H723 и ESP32-C2. Чтобы начать: 1. Распакуйте `sd-card.zip` из [релизов](https://github.com/Kits-Lab-Dev/Board-H723/releases) в корень карты FAT32 и вставьте карту в плату. 2. Подключите плату к ПК кабелем USB-C. Она появится в системе как сетевая карта (USB-NCM, драйвер есть в Windows 10/11, Linux и macOS): плата — `192.168.4.1`, ПК получает `192.168.4.2` по DHCP. Проверка — `ping 192.168.4.1`. 3. Войдите по SSH: `ssh root@192.168.4.1`. Пароль плата создаёт сама при первом запуске и сохраняет в `/SD/.ssh/password` на карте. Подробнее — на странице [ПО для разработки](/boards/bh723/software/). 4. Файлы на карту заливаются по SFTP, скрипты Lua запускаются командой `lua -f /SD/x.lua`. 5. Для своей прошивки на C — [ПО для разработки](/boards/bh723/software/) и [рецепты](/boards/bh723/recipes/). ## Что умеет готовая прошивка | Возможность | Подробности | |---|---| | Сеть | USB-NCM (USB-Ethernet), Wi-Fi клиент и точка доступа, DHCP-сервер | | Скорость Wi-Fi | TCP до 25 Мбит/с на приём и до 35 Мбит/с на отправку (зависит от эфира) — рецепт [tcp_speed](/boards/bh723/recipes/tcp_speed/) | | SSH и SFTP | оболочка, загрузка файлов на SD-карту и в RAM-диск | | Файловые системы | `/SD` (FatFs, microSD в 4 бита), `/RAM` (RAM-диск 4 МБ в SDRAM) | | Lua | интерпретатор для быстрых опытов: GPIO, SPI, I2C, UART, потоки, Wi-Fi, сокеты, HTTPS | | BLE | Nordic UART, плата видна как `Mynewt_BLEuart` | | Дисплей | RGB 800×480 по LTDC через переходник на J1/J2 и сенсорный экран GT911 — рецепты [lcd_ltdc](/boards/bh723/recipes/lcd_ltdc/), [lvgl_demo](/boards/bh723/recipes/lvgl_demo/), [lvgl_clock](/boards/bh723/recipes/lvgl_clock/) | ## Wi-Fi/BLE Модуль на основе ESP32-C2 связывает плату с внешним миром: - Wi-Fi 802.11 b/g/n (2,4 ГГц): - инфраструктурный режим (STA/AP) - подключение к локальной сети и интернету - серверы и клиенты TCP/UDP, HTTP, MQTT и т. д. - Bluetooth Low Energy (BLE 5.0): - GATT-серверы и клиенты - обмен данными с мобильными устройствами - использование ESP32-C2 как BLE-адаптера для STM32 ESP32-C2 подключён к STM32 по SPI, поэтому стек TCP/IP можно держать как на STM32 (удобные сокеты), так и на ESP32-C2 (экономия ресурсов STM32). UART позволяет загружать прошивку в ESP32-C2. Соединение STM32 и ESP32-C2: ``` STM32 ESP32 PF6 --- (CS) ---------- IO10 PF7 --- (CLK) --------- IO6 PF8 --- (MISO) -------- IO2 PF9 --- (MOSI) -------- IO7 PF10 -- (EN) ---------- EN PE2 --- (BOOT) -------- IO9 PE3 --- (DATA_READY) -- IO4 PB6 --- (HANDSHAKE) --- IO3 PB3 --- (TX) ---------- TXD PB4 --- (RX) ---------- RXD IO1 --> LED ``` ## microSD Карта подключена к STM32H723ZGT6 через SDMMC2 в 4-битном режиме, High Speed 50 МГц. Файловая система FAT (FAT32) через библиотеку FatFs. Скорость зависит от карты: и запись, и чтение — до 10 МБ/с (рецепт [sd_file](/boards/bh723/recipes/sd_file/)). ## SDRAM Память подключена к FMC (Flexible Memory Controller) микроконтроллера STM32H723ZGT6: - прямой доступ к памяти как к внешней SRAM - адресно-данный интерфейс, 16-битная шина - режим Burst для ускорения последовательного доступа SDRAM расширяет внутреннюю SRAM микроконтроллера: в прошивке под неё — `sdramMalloc()`, RAM-диск и память Lua. ## Разъёмы J1 и J2 — гребёнки 2×20 с шагом 2,54 мм. Номера контактов — как на схеме; нечётные и чётные контакты — два ряда гребёнки. Выводы SDRAM, microSD и USB на разъёмы не выведены; линии ESP32-C2 выведены частично (см. ниже). Картинка в начале страницы — те же разъёмы на фотографии платы. | Контакты | J1, нечётный | J1, чётный | J2, нечётный | J2, чётный | |---|---|---|---|---| | 1 / 2 | GND | GND | GND | GND | | 3 / 4 | 3V3 | 3V3 | 3V3 | 3V3 | | 5 / 6 | PC7 | PC6 | RST | GND | | 7 / 8 | PC9 | PC8 | PG7 | PG6 | | 9 / 10 | PA9 | PA8 | PG3 (LED) | PD13 | | 11 / 12 | PA15 | PA10 | PD12 | PD11 | | 13 / 14 | PC11 | PC10 | PB15 (лог RX) | PB14 (лог TX) | | 15 / 16 | PD2 | PC12 | PB13 | PB12 | | 17 / 18 | PD4 | PD3 | PB11 | PB10 | | 19 / 20 | GND | GND | GND | GND | | 21 / 22 | PG14 | PG13 | PB2 | PB1 | | 23 / 24 | PB7 | PB5 | PB0 | PC5 | | 25 / 26 | PB9 | PB8 | PC4 | PA7 | | 27 / 28 | PE4 | PE5 | PA6 | PA5 | | 29 / 30 | PE6 | PB4 / ESP RXD | PA4 | PA3 | | 31 / 32 | PB3 / ESP TXD | ESP IO18 | PC1 | PA2 | | 33 / 34 | ESP IO0 | ESP IO5 | PA1 | PA0 | | 35 / 36 | 3V3 | VBAT | VREF+ | 3V3 | | 37 / 38 | 5V | 5V | 5V | 5V | | 39 / 40 | GND | GND | GND | GND | - `ESP RXD`, `ESP TXD`, `ESP IO0/IO5/IO18` — линии ESP32-C2. PB4 и PB3 соединены с UART ESP32-C2 перемычками JP3 и JP4 (замкнуты). - PG3 — светодиод платы, он мигает 2 Гц из задачи простоя прошивки. - PB14 и PB15 — лог USART1 (115200 8N1), они же на SWD-разъёме. - 5V на разъёмах — напряжение VBUS с USB-C. Плата питается от USB-C: 5 В → преобразователь SY8089 → 3,3 В. - Перемычки JP1 (VREF+ ↔ 3V3) и JP2 (VBAT ↔ 3V3) разомкнуты: внешнее опорное напряжение АЦП подключают на VREF+ (J2, контакт 35), батарейку RTC — на VBAT (J1, контакт 36). - Свободные для своих задач: I2C1 (PB8 — SCL, PB7 — SDA), FDCAN2 (PB12 — RX, PB13 — TX, нужен внешний трансивер), ШИМ на TIM1–TIM4, TIM8. - Подробная таблица занятой периферии, память и такты — [docs/board.md](https://github.com/Kits-Lab-Dev/Board-H723/blob/main/docs/board.md) в репозитории. ### Разъём SWD (J6) 2×4: 1 — 3V3, 2 — SWDIO, 3 — GND, 4 — SWCLK, 5 — GND, 6 — не подключён, 7 — PB15 (USART1 RX), 8 — PB14 (USART1 TX). Отладчик [«Лобзик»](https://github.com/Kits-Lab-Dev/lobzik-skill) подключается сюда и сразу даёт лог USART1. ### Кнопки - **RESET** — сброс. - **BOOT/USER** (PC13) — если нажать её при сбросе, плата входит в системный загрузчик STM32 (USB DFU). В готовой прошивке долгое нажатие (около 1 с) — сброс, короткое нажатие свободно для своих задач (рецепт [gpio_button](/boards/bh723/recipes/gpio_button/)). ## Прошивка - **По USB, без кнопок:** `python tools/dfu_flash.py` из репозитория. Скрипт отправляет плате UDP-пакет `dfu`, плата переходит в загрузчик, скрипт записывает прошивку и ждёт, пока плата снова ответит на ping. Команда `reboot dfu` в SSH делает то же самое. - **С кнопками:** зажать BOOT, нажать RESET (или переподключить USB), отпустить BOOT — плата в DFU. Дальше `STM32_Programmer_CLI -c port=usb1 -w BoardH723.hex -s 0x08000000`. На Windows нужен драйвер STM32 DFU, он ставится вместе со STM32CubeProgrammer. - **Через отладчик «Лобзик»** по SWD — прошивка, чтение памяти и регистров, разбор HardFault. - **Модуль ESP32-C2** прошивается через STM32: команда `reboot esploader` в SSH включает мост USB-UART, дальше esptool. Подробности — в [AGENTS.md](https://github.com/Kits-Lab-Dev/Board-H723/blob/main/AGENTS.md). # Рецепты для Доски-H723 > Рецепт — небольшой законченный модуль на C: recipes/<имя>/<имя>.c + .h и README с объяснением, как он устроен. Рецепты проверены на плате, в README — настоящий вывод лога; исключение — i2c_bme280,… Рецепт — небольшой законченный модуль на C: `recipes/<имя>/<имя>.c` + `.h` и README с объяснением, как он устроен. Рецепты проверены на плате, в README — настоящий вывод лога; исключение — `i2c_bme280`, проверенный без датчика (см. его README). Рецепты подключаются к основному проекту `examples/BoardH723` без правки его кода. | Рецепт | Что показывает | |---|---| | [gpio_button](/boards/bh723/recipes/gpio_button/) | кнопка BOOT по прерыванию, подавление дребезга, светодиод | | [uart_dma](/boards/bh723/recipes/uart_dma/) | приём UART через DMA в кольцевой буфер, команды из терминала | | [i2c_bme280](/boards/bh723/recipes/i2c_bme280/) | сканер шины I2C, датчик BME280/BMP280: температура, давление, влажность | | [wifi_http](/boards/bh723/recipes/wifi_http/) | подключение к Wi-Fi, HTTP GET на сокетах FreeRTOS+TCP | | [tcp_speed](/boards/bh723/recipes/tcp_speed/) | скорость TCP по Wi-Fi: окна TCP, энергосбережение, клиент для ПК | | [sd_file](/boards/bh723/recipes/sd_file/) | дозапись в файл на SD, замер скорости записи и чтения | | [rtos_queue](/boards/bh723/recipes/rtos_queue/) | две задачи FreeRTOS и очередь между ними | | [lcd_ltdc](/boards/bh723/recipes/lcd_ltdc/) | дисплей RGB 800×480: LTDC, DMA2D, двойной буфер в SDRAM, картинка с SD | | [lvgl_demo](/boards/bh723/recipes/lvgl_demo/) | интерфейс на LVGL 9: сенсорный экран GT911, графики, русский шрифт TTF с SD | | [lvgl_clock](/boards/bh723/recipes/lvgl_clock/) | часы (NTP) и погода (open-meteo) на LVGL, анимация пузырей; Wi-Fi и город — в файле на SD | ## Как включить Список рецептов через `;` в опции `H723_RECIPES`: ```bash cd examples/BoardH723 cmake --preset Release -DH723_RECIPES="gpio_button;sd_file" cmake --build build/Release python ../../tools/dfu_flash.py ``` CMake добавляет в сборку все `.c` из папок рецептов и генерирует `build/Release/recipes_start.c`, который вызывает `<имя>_start()` каждого рецепта. `appTask` (`app/app.c`) вызывает его, когда уже работают USB-сеть, SDRAM, ESP32-C2, SD-карта, Lua и SSH. Выключить рецепты — `-DH723_RECIPES=""`. Рецепты не зависят от Lua и работают в прошивке без него (`-DH723_WITH_LUA=OFF`); только `wifi_http`, `tcp_speed` и `lvgl_clock` тогда подключаются к сети сами — имя и пароль задаются в `wifi_http.h`, опциями `-DTCP_SPEED_SSID`/`-DTCP_SPEED_PASSWORD` и в `/SD/clock.ini`. `lcd_ltdc`, `lvgl_demo` и `lvgl_clock` выводят на один дисплей — вместе их не включают. Вывод рецептов — в лог USART1 115200 (PB14, на разъёме отладчика J6 и на J2). ## Свой рецепт 1. Папка `recipes/my_thing/` с `my_thing.c`, где есть `void my_thing_start(void)`. 2. `my_thing_start()` только создаёт задачу FreeRTOS и сразу возвращается: `appTask` на ней не задерживается. 3. `cmake --preset Release -DH723_RECIPES="my_thing"`. 4. Если рецепту нужны библиотеки или код другого рецепта — они подключаются в `recipes/my_thing/recipe.cmake` (образец — `lvgl_demo/recipe.cmake`). Правила, которые соблюдают все рецепты: - Задачи, очереди и стеки — статически (`xTaskCreateStatic`): их размер виден при сборке, а не выясняется при нехватке кучи во время работы. - Буферы для DMA — не в обычных `static`-массивах: они попадают в DTCM, куда DMA1/DMA2 доступа не имеют. Подходят `pvPortMalloc` (RAM_D1) или `sdramMalloc` (SDRAM), с выравниванием по 32 байта и очисткой/инвалидацией кэша. - Прерывания, из которых зовутся функции `...FromISR`, — с приоритетом 5 и ниже по важности (число ≥ 5). - Свободные выводы и периферия — в `docs/board.md` репозитория. --- Рецепты в репозитории: [recipes](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes) # gpio_button — кнопка по прерыванию и светодиод > Короткое нажатие кнопки BOOT/USER переключает светодиод D2 (PG3). Кнопка обрабатывается по прерыванию с подавлением дребезга контактов. Короткое нажатие кнопки BOOT/USER переключает светодиод D2 (PG3). Кнопка обрабатывается по прерыванию с подавлением дребезга контактов. ## Включить ```bash cmake --preset Release -DH723_RECIPES="gpio_button" ``` ## Вывод на плате ``` gpio_button: started, press BOOT to toggle LED gpio_button: press 1 (196 ms), LED on gpio_button: press 2 (202 ms), LED off gpio_button: press 3 (181 ms), LED on gpio_button: press 4 (152 ms), LED off ``` Подавление дребезга: если прерывание пришло, а уровень на выводе не изменился, в лог попадает `gpio_button: bounce, ignored`, и светодиод не переключается. ## Как это работает - **Схема.** Кнопка замыкает PC13 на 3,3 В, резистор 10 кОм на плате тянет вывод к земле: нажата — 1, отпущена — 0. Та же кнопка подаёт 1 на BOOT0, поэтому если **держать её во время сброса**, стартует системный загрузчик (DFU), а не прошивка. - **Долгое нажатие занято.** Прошивка (`app/app.c`) сбрасывает плату, если кнопку держать ~1 с. Рецепт считает только нажатия короче `SHORT_PRESS_MS` (800 мс). - **Прерывание по обоим фронтам.** PC13 переводится в режим `GPIO_MODE_IT_RISING_FALLING` — линия EXTI13. Её обработчик `EXTI15_10_IRQHandler` и `HAL_GPIO_EXTI_Callback` живут в `app/exti.c` и отдают прерывание приложению через `appGpioExti(pin)`; что приложение не забрало, уходит в Lua (`pio.attachInterrupt`), если прошивка собрана с ним. Рецепт переопределяет `appGpioExti` и забирает PC13 себе. - **Дребезг.** Контакты кнопки при нажатии несколько миллисекунд замыкаются и размыкаются, давая пачку прерываний. Прерывание только будит задачу (`vTaskNotifyGiveFromISR`): ждать и печатать в нём нельзя, пока оно идёт, стоит вся система. Задача ждёт 20 мс, сбрасывает накопившиеся уведомления и читает вывод. Если уровень не изменился — это был дребезг. - **Приоритет прерывания 6** — из него можно звать `...FromISR` (см. правила в [общем README](/boards/bh723/recipes/)). - **Светодиод.** Обычно им мигает idle-задача (`appLedHeartbeat` в `app/app.c`); рецепт выключает мигание и управляет PG3 сам. Состояние хранится в переменной, а не читается с вывода: `HAL_GPIO_ReadPin` сразу после записи в выход может вернуть старое значение. ## Переделать под себя - Внешняя кнопка: любой свободный вывод (`docs/board.md`), кнопка на GND и подтяжка `GPIO_PULLUP` — тогда нажата = 0. Меняются `BUTTON_PORT`, `BUTTON_PIN` и проверка уровня. Для выводов 0–4 у линий EXTI свои обработчики, для 5–9 — `EXTI9_5_IRQHandler`, тоже в `app/exti.c`. - `appGpioExti` переопределяется только в одном модуле, поэтому при нескольких кнопках все выводы обрабатываются в этой одной функции. - Двойное нажатие, удержание и т. п. — в `buttonTask` есть время нажатия (`ms`), этого достаточно. --- Исходники рецепта: [recipes/gpio_button](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/gpio_button) # i2c_bme280 — датчик на I2C > Сканирует шину I2C1, находит датчик Bosch BME280 (температура, давление, влажность) или BMP280 (без влажности) и печатает показания раз в 2 секунды. Драйвер — один файл без сторонних библиотек,… Сканирует шину I2C1, находит датчик Bosch BME280 (температура, давление, влажность) или BMP280 (без влажности) и печатает показания раз в 2 секунды. Драйвер — один файл без сторонних библиотек, формулы — из даташита. ## Подключение | Модуль датчика | Доска-H723 | |---|---| | VCC / VIN | 3V3 (J1-3) | | GND | GND (J1-1) | | SCL | PB8 (J1-26) | | SDA | PB7 (J1-23) | Адрес 0x76, если вывод SDO модуля на GND, и 0x77 — если на 3,3 В; рецепт пробует оба. ## Включить ```bash cmake --preset Release -DH723_RECIPES="i2c_bme280" ``` ## Вывод на плате Без датчика (шина с подтяжками, никто не отвечает; задача ждёт датчик): ``` i2c_bme280: started i2c_bme280: no devices on I2C1 (PB8 SCL, PB7 SDA) ``` С датчиком ожидается такой вывод (на живом BME280 на плате не проверялось): ``` i2c_bme280: device at 0x76 i2c_bme280: BME280 at 0x76 i2c_bme280: 24.31 C, 99012 Pa (742 mmHg), 41.5 %RH ``` ## Как это работает - **Шина.** I2C1 настроен в CubeMX (`hi2c1`, ~100 кГц). Подтяжек на плате нет — у модулей датчиков они свои; рецепт включает ещё встроенные (~40 кОм), чтобы шина без модуля не «висела в воздухе». - **Сканер.** `HAL_I2C_IsDeviceReady` посылает каждый адрес 0x08–0x77; ответил ACK — устройство есть. Полезно первым делом при любом новом датчике: виден адрес и что проводка цела. - **Регистры.** Датчик читается как память: `HAL_I2C_Mem_Read(адрес, регистр, буфер, длина)`. `0xD0` — ID (0x60 BME280, 0x58 BMP280), `0x88…0xA1` и `0xE1…0xE7` — калибровка, `0xF7…0xFE` — сырые измерения. - **Калибровка.** Каждый датчик на заводе прошит своими коэффициентами. Сырые числа АЦП без них бессмысленны; рецепт читает коэффициенты один раз при старте. - **Компенсация.** Целочисленные формулы из даташита (раздел 4.2.3): сначала температура (`tFine`), потом давление и влажность — они от неё зависят. Все 8 байт измерений читаются одной транзакцией, чтобы значения были из одного цикла измерения. - **Режим.** «Нормальный»: датчик сам меряет раз в секунду, прошивка просто читает последнее. Для батарейных устройств — «принудительный» (`ctrl_meas` с режимом `01`) перед каждым чтением. - **Таймауты.** Все обмены по I2C — с таймаутом 10 мс: отвалившийся датчик даёт ошибку, а не зависание. ## Переделать под себя - Другой датчик I2C — та же схема: `i2cScan`, чтение ID, `readRegs`/`writeReg`, формулы из его даташита. - Точнее и с меньшим шумом: передискретизация (биты `osrs` в `0xF2`/`0xF4`) и фильтр IIR (`0xF5`). - Высота по давлению: `h ≈ 44330 × (1 − (p / p0)^0.1903)` м, `p0` — давление на уровне моря. - Lua-модуль `wire` тоже работает с I2C1, но на PB8/PB9 — одновременно с рецептом его лучше не запускать. --- Исходники рецепта: [recipes/i2c_bme280](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/i2c_bme280) # lcd_ltdc — дисплей RGB 800×480 > Выводит на дисплей с параллельным интерфейсом RGB картинку с SD-карты и гоняет по ней квадрат. Контроллер LTDC сам читает кадр из SDRAM и выдаёт его на дисплей, рисует DMA2D — процессор в этом… Выводит на дисплей с параллельным интерфейсом RGB картинку с SD-карты и гоняет по ней квадрат. Контроллер LTDC сам читает кадр из SDRAM и выдаёт его на дисплей, рисует DMA2D — процессор в этом почти не участвует. ## Подключение Дисплей 800×480 с интерфейсом RGB (24 бита данных, CLK, HSYNC, VSYNC, DE) — через переходник на разъёмы J1 и J2. Подсветка и питание дисплея — от переходника. | Сигнал | Вывод | Контакт | | Сигнал | Вывод | Контакт | | Сигнал | Вывод | Контакт | |---|---|---|---|---|---|---|---|---|---|---| | R0 | PG13 | J1-22 | | G0 | PE5 | J1-28 | | B0 | PE4 | J1-27 | | R1 | PA2 | J2-32 | | G1 | PE6 | J1-29 | | B1 | PC10 | J1-14 | | R2 | PA1 | J2-33 | | G2 | PA6 | J2-27 | | B2 | PA3 | J2-30 | | R3 | PB0 | J2-23 | | G3 | PC9 | J1-7 | | B3 | PA8 | J1-10 | | R4 | PA5 | J2-28 | | G4 | PB10 | J2-18 | | B4 | PA10 | J1-12 | | R5 | PA9 | J1-9 | | G5 | PC1 | J2-31 | | B5 | PB5 | J1-24 | | R6 | PB1 | J2-22 | | G6 | PC7 | J1-5 | | B6 | PA15 | J1-11 | | R7 | PC4 | J2-25 | | G7 | PD3 | J1-18 | | B7 | PD2 | J1-15 | CLK — PG7 (J2-7), HSYNC — PC6 (J1-6), VSYNC — PA4 (J2-29), DE — PC5 (J2-24). Эти 28 выводов заняты дисплеем целиком: ШИМ Lua-модуля `pio` на PA1–PA3, PA5, PA6, PA8, PB0, PB1, PC6–PC9 с ним не совместим. Свободными остаются, например, I2C1 (PB8, PB7), FDCAN2 (PB12, PB13) и USART1. ## Включить ```bash cmake --preset Release -DH723_RECIPES="lcd_ltdc" ``` Картинка — `/SD/lcd.bmp`: BMP 24 бита без сжатия, лучше 800×480 (меньшая встанет по центру). Без файла на экране цветные полосы. ## Вывод на плате ``` lcd_ltdc: started lcd_ltdc: 800x480 RGB565, pixel clock 25000 kHz, refresh 43 Hz lcd_ltdc: /SD/lcd.bmp 800x480 loaded in 175 ms lcd_ltdc: 43 fps, draw 506 us/frame ``` 43 кадра в секунду — по одному на каждый кадр развёртки; на рисование кадра уходит 0,5 мс. С работающим дисплеем SD-карта пишет 10,1 МБ/с и читает 10,7 МБ/с (`sd_file`), SSH, SFTP и Lua работают как без дисплея. ## Как это работает - **Такт пикселя.** LTDC тактируется от выхода R PLL3: 250 МГц / 10 = 25 МГц (`PeriphCommonClock_Config` в `main.c`). Полный кадр с порогами — 1057 × 549 тактов, отсюда 43 Гц. - **Тайминги развёртки** — `LCD_HSYNC`, `LCD_HBP`, `LCD_HFP` и вертикальные в `lcd_ltdc.h`, из документации панели. В регистры LTDC пишутся накопленные суммы: импульс, + задний порог, + видимая часть, + передний порог, каждая минус 1. - **Регистры, а не HAL.** Модули HAL для LTDC и DMA2D в проекте не включены (их нет в `.ioc`), а регистров немного — рецепт не зависит от настроек CubeMX. - **Кадровые буферы — в SDRAM**, два по 768 КБ (RGB565, 2 байта на пиксель). На экране один, рисуется другой; `lcdSwap` меняет адрес слоя с перезагрузкой по кадровому гасящему импульсу (`LTDC_SRCR_VBR`) и ждёт его — поэтому картинка не рвётся. - **RGB565 вместо ARGB8888** — вдвое меньше памяти и нагрузки на шину SDRAM. Линии R0–R2, G0–G1, B0–B2 LTDC при этом всё равно выдаёт, дополняя цвет до 24 бит. - **DMA2D рисует сам**: заливка прямоугольника (режим «регистр → память»), копия картинки («память → память») и перевод BMP из RGB888 в RGB565 («память → память с преобразованием»). - **Перерисовывается только изменившееся.** Шину SDRAM делят LTDC (~33 МБ/с на чтение кадра), DMA2D, процессор, Lua и RAM-диск. Копия всего фона в каждом кадре добавила бы ~65 МБ/с и 17 мс работы DMA2D. Поэтому фон пишется в оба буфера один раз, а в каждом кадре закрывается фоном только место, где квадрат был два кадра назад (буферы чередуются). - **Своя периферия с DMA рядом с дисплеем.** Пока LTDC читает кадр, доступ к SDRAM идёт с очередью. Буферы DMA для периферии, которой важно успевать (SD-карта, быстрый UART, SPI), лучше держать во внутренней памяти (`pvPortMalloc`, AXI SRAM) — так сделан и драйвер SD-карты. - **Кэш.** SDRAM кэшируется. Память под буферы инвалидируется после выделения: иначе «грязные» строки кэша от прежних владельцев могли бы вытесниться поверх того, что пишет DMA2D. Данные BMP, прочитанные процессором, перед DMA2D выгружаются из кэша (`SCB_CleanDCache_by_Addr`). Буферы выровнены по 32 байта — размер строки кэша. - **BMP** хранит строки снизу вверх и выравнивает их до 4 байт, поэтому DMA2D переводит картинку по строке. Файл читается через FatFs блоками по 32 КБ: драйвер SD передаёт их одной командой, мелкие чтения через stdio в разы медленнее. ## Переделать под себя - Другая панель — размер и тайминги в `lcd_ltdc.h`; частоту пикселя меняет делитель `PLL3R` (в `.ioc`, от него же тактируется АЦП). Полярности сигналов — регистр `LTDC->GCR`. - Текст, кнопки, графики и сенсорный ввод — рецепт [lvgl_demo](/boards/bh723/recipes/lvgl_demo/): LVGL рисует прямо в кадровые буферы этого драйвера (`lcdFrameBuffer`, `lcdShow`). - Рисование процессором по пикселям — в `backBuffer`, а перед `lcdSwap` выгрузить изменённое из кэша (`SCB_CleanDCache_by_Addr`), иначе LTDC покажет старые данные. - Сенсорная панель дисплея обычно подключается по I2C — см. рецепт [i2c_bme280](/boards/bh723/recipes/i2c_bme280/). --- Исходники рецепта: [recipes/lcd_ltdc](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/lcd_ltdc) # lvgl_clock — часы и погода на LVGL > Часы с секундами, дата по-русски и погода за окном: температура, «ощущается как», минимум и максимум на сегодня, влажность, ветер, значок погоды. Время — из интернета (NTP), погода — с… Часы с секундами, дата по-русски и погода за окном: температура, «ощущается как», минимум и максимум на сегодня, влажность, ветер, значок погоды. Время — из интернета (NTP), погода — с [open-meteo.com](https://open-meteo.com) (бесплатно, без ключа). На фоне всплывают разноцветные пузыри случайного размера и скорости, касание экрана выпускает новые. Сеть Wi-Fi и город задаются в файле на SD-карте — прошивку под другой город пересобирать не нужно. ## Подключение Дисплей 800×480 и тач GT911 — как в рецепте [lvgl_demo](/boards/bh723/recipes/lvgl_demo/). На карте — шрифты `/SD/fonts/PT_Sans-Web-*.ttf` и настройки `/SD/clock.ini` (оба есть в `sd-card.zip`): ```ini ssid = my_wifi password = my_password city = Москва ``` - `city` — город по-русски или латиницей; координаты и часовой пояс находит open-meteo. - Вместо города — `latitude` и `longitude` в градусах (север и восток — со знаком плюс). - `utc_offset` — часовой пояс вручную, часы от UTC (бывает дробным: `5.5`). Без него пояс берётся по месту. - Пустой `ssid` — рецепт сам к Wi-Fi не подключается и ждёт, пока это сделает кто-то другой (`/SD/boot.lua` в прошивке с Lua). Файл — в UTF-8; правится в любом редакторе на ПК или по SFTP на живой плате (`/SD/clock.ini`), новые настройки читаются при загрузке. ## Включить Как и `lvgl_demo`, рецепт собирается без Lua — иначе прошивка не помещается во Flash: ```bash cmake --preset Release -DH723_WITH_LUA=OFF -DH723_RECIPES="lvgl_clock" cmake --build build/Release ``` Прошивка с SSH — 727 КБ. Код LVGL, драйверы дисплея и тача берутся из `lvgl_demo`, HTTP — из `wifi_http` (`recipe.cmake`), поэтому вместе с ними, а также с `lcd_ltdc`, рецепт не включают. ## Вывод на плате ``` lvgl_clock: started lvgl_clock: Wi-Fi: подключение к my_wifi… gt911: product 911, panel 800x480 lvgl_clock: screen ready IP Address: 192.168.1.50 lvgl_clock: Wi-Fi: my_wifi, адрес 192.168.1.50 lvgl_clock: Москва -> 55.7520, 37.6178 (585 ms) wifi_http: connect api.open-meteo.com (94.130.142.35):80 error -116 lvgl_clock: weather 10 C (feels 8), code 2, humidity 81 %, wind 2.9 m/s, UTC+10800 s, historical-forecast-api.open-meteo.com 487 ms ``` Если провайдер не пускает к адресу `api.open-meteo.com` (строка с `error -116`), прогноз приходит со второго сервера (см. ниже). Загрузка процессора (`top` в SSH) — около 23 % с пузырями и 3 % без них. Что видно на экране, если что-то не так, — в строке состояния внизу слева: нет файла настроек, подключение к Wi-Fi, город не найден, сервер погоды не отвечает. ## Как это работает - **Две задачи.** `clockNet` подключается к Wi-Fi, находит город и раз в 15 минут спрашивает погоду — сетевые запросы длятся секундами, и экран в это время не замирает. `lvglClock` рисует. LVGL не потокобезопасна, поэтому сетевая задача экрана не трогает: она кладёт данные в общую структуру (`shared`) в критической секции и увеличивает счётчик `seq`. Таймер LVGL раз в 250 мс копирует структуру и перерисовывает погоду, только если счётчик изменился. - **Город → координаты.** `geocoding-api.open-meteo.com/v1/search?name=...` — название в адресе кодируется побайтно в `%XX` (UTF-8). В ответе — широта, долгота и название по-русски. - **Погода.** `/v1/forecast` с параметрами `current=` (сейчас) и `daily=` (минимум и максимум на сегодня), `timezone=auto` — open-meteo добавляет в ответ смещение пояса места `utc_offset_seconds`, по нему идут часы. Код погоды WMO (0 — ясно, 61 — дождь, 95 — гроза…) превращается в текст и значок в `weatherText`. - **Два сервера погоды.** Тот же запрос понимают `api.open-meteo.com` и `historical-forecast-api.open-meteo.com` — они на разных адресах. Некоторые провайдеры не пускают к первому; рецепт пробует оба и запоминает тот, что ответил. - **HTTP без TLS.** open-meteo отвечает и по обычному HTTP, поэтому хватает сокетов FreeRTOS+TCP (`wifiHttpGet` из `wifi_http`) — без Mbed TLS и его ~60 КБ Flash. Ответ приходит кусками `chunked`; `wifiHttpGet` склеивает их, тело — обычная строка. - **JSON без библиотеки.** Ответ короткий и одинаковый по структуре: `jsonNumber` ищет `"ключ":` после начала нужного объекта (`"current":{`) и читает число `strtof`. Для чего-то сложнее подойдёт библиотека разбора JSON, например cJSON. - **Время.** NTP-клиент (`libs/ntp`) ставит часы RTC по поясу `TIME_ZONE` (по умолчанию +3). Рецепт переводит их в пояс места: `RTC − TIME_ZONE + utc_offset`. Пока время не пришло (в RTC 2023 год или раньше), на экране «--:--». Секунды меняются раз в секунду, часы и минуты — раз в минуту, дата — раз в сутки: LVGL перерисовывает только изменённые надписи. - **Значок погоды** — несколько объектов LVGL с закруглением: круг — солнце (ночью — луна, `is_day`), три круга и прямоугольник — облако, полоски — дождь, кружки — снег. - **Пузыри.** Таймер раз в 330 мс с вероятностью 1/3 выпускает пузырь в случайном месте снизу (`lv_rand`, зерно — счётчик тактов ядра). У пузыря две анимации `lv_anim`: подъём за верх экрана (мелкие быстрее) и бесконечное покачивание по горизонтали (`lv_anim_set_reverse_duration`, `lv_anim_path_ease_in_out`). В конце подъёма `lv_obj_delete_anim_completed_cb` удаляет пузырь. Пузыри — в отдельном слое, созданном первым, поэтому рисуются под надписями. Касание (`LV_EVENT_PRESSED` экрана) — четыре пузыря из точки касания; надписи и карточка не кликабельны, чтобы касание доходило до экрана. - **Нагрузка.** Каждый сдвиг пузыря — перерисовка куска градиентного фона и цифр под ним. Экран обновляется 30 раз в секунду вместо 50 (`lv_display_get_refr_timer`), пузырей — не больше 10. ## Переделать под себя - Другие данные погоды — параметры `current=` и `daily=` в `fetchWeather` (список — в [документации open-meteo](https://open-meteo.com/en/docs)) и `jsonNumber` с нужным ключом. Прогноз на несколько дней — `forecast_days=3`, значения в `daily` — массивы по дням. - Число и размер пузырей — `MAX_BUBBLES`, `bubble()`; без пузырей — убрать таймер `bubbleTimer`, загрузка процессора упадёт до 3 %. - Цвета и раскладка — `buildScreen`. Шрифты с карты рисуются любого размера (`lvglLoadFont`). --- Исходники рецепта: [recipes/lvgl_clock](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/lvgl_clock) # lvgl_demo — интерфейс на LVGL с сенсорным экраном > Экран с показаниями платы на библиотеке LVGL 9: температура кристалла, свободная память, адреса сети, графики температуры, загрузки процессора, ОЗУ и SDRAM за две минуты, переключатель светодиода.… Экран с показаниями платы на библиотеке [LVGL 9](https://lvgl.io): температура кристалла, свободная память, адреса сети, графики температуры, загрузки процессора, ОЗУ и SDRAM за две минуты, переключатель светодиода. Русский текст — шрифтом TTF с SD-карты. ## Подключение Дисплей RGB 800×480 (RGB050M1) — как в рецепте [lcd_ltdc](/boards/bh723/recipes/lcd_ltdc/). Сенсорная панель GT911 — на I2C1: | Сигнал тача | Вывод | Контакт | |---|---|---| | SCL | PB8 | J1-26 | | SDA | PB7 | J1-23 | | INT | PB9 | J1-25 | | RST | PD4 | J1-17 | На SD-карте — шрифты `/SD/fonts/PT_Sans-Web-Regular.ttf` и `PT_Sans-Web-Bold.ttf` (есть в архиве `sd-card.zip`; без них экран работает со встроенным шрифтом без кириллицы). ## Включить LVGL занимает ~240 КБ Flash, поэтому вместе со всем остальным прошивка не помещается: выключается Lua (или SSH, `-DH723_WITH_SSH=OFF`). ```bash cmake --preset Release -DH723_WITH_LUA=OFF -DH723_RECIPES="lvgl_demo" cmake --build build/Release ``` Прошивка с SSH и LVGL — 724 КБ. ## Вывод на плате ``` lvgl_demo: started gt911: product 911, panel 800x480 lvgl_demo: fonts loaded in 105 ms lvgl_demo: screen ready, full redraw 52881 us ``` Полная перерисовка экрана — 53 мс; дальше LVGL перерисовывает только изменившееся (раз в секунду — цифры и графики). Загрузка процессора при этом — около 5 %. ## Как это работает - **Задача LVGL одна.** LVGL не потокобезопасна: интерфейс создаётся и меняется только в задаче `lvgl`, которая крутит `lv_timer_handler()`. Данные от других задач — через очередь или флаги, которые читает таймер LVGL (`lv_timer_create`). - **Вывод — прямо в кадровые буферы LTDC** (`LV_DISPLAY_RENDER_MODE_DIRECT`). Буферов два, в SDRAM; LVGL рисует в невидимый и сама переносит изменённые места из видимого. Функция вывода (`flush` в `lvgl_port.c`) выгружает кэш и показывает готовый буфер с ближайшего кадра (`lcdShow` из `lcd_ltdc`). - **Кэш.** Процессор рисует через кэш (write-back), а LTDC читает память напрямую, поэтому перед показом весь кэш данных (32 КБ) выгружается в SDRAM — это быстрее, чем выгружать буфер построчно. Операции DMA2D LVGL сама окружает выгрузкой и инвалидацией кэша. - **DMA2D** (`LV_USE_DRAW_DMA2D`) заливает прямоугольники и копирует картинки, процессору остаются буквы, скругления и линии графиков. - **Память LVGL — в SDRAM**: `lv_malloc_core` и соседние функции в `lvgl_port.c` вызывают `sdramMalloc` (`LV_USE_STDLIB_MALLOC = LV_STDLIB_CUSTOM`). - **Шрифты с карты.** Tiny TTF (`LV_USE_TINY_TTF`) рисует буквы из файла TTF любого размера. Файл один раз читается в SDRAM (`lvglLoadFont`), следующие размеры используют те же данные; нарисованные буквы кэшируются. Во Flash шрифтов нет, кроме запасного латинского. - **Файлы для LVGL** — буква `S:`: `"S:fonts/x.ttf"` открывается как `/SD/fonts/x.ttf` (`LV_USE_FS_STDIO`). Так же загружаются картинки. - **Тач GT911** опрашивается по I2C при каждом обновлении LVGL (раз в 20 мс): регистр состояния `0x814E` (бит 7 — новые данные), координаты первого касания с `0x8150`, затем состояние сбрасывается записью нуля. При сбросе уровень INT задаёт адрес контроллера (0 — 0x5D). Разрешение панели контроллер хранит сам — `gt911: panel 800x480`. - **Размер.** В `config/lv_conf.h` выключены ненужные форматы пикселей программного рисования (каждый — десятки КБ), LVGL собирается с `-Os` (`recipe.cmake`). - **Зависимости рецепта** — в `recipe.cmake`: исходники LVGL из `third_party/lvgl` и драйвер дисплея из рецепта `lcd_ltdc` (его пример при этом не запускается). ## Переделать под себя - Свой экран — функция `buildScreen` в `lvgl_demo.c`; документация и примеры виджетов — [docs.lvgl.io](https://docs.lvgl.io/9.6/). - Экраны можно собирать мышкой в [SquareLine Studio](https://squareline.io) или [EEZ Studio](https://www.envox.eu/studio/) — они выдают код на C для LVGL 9. - Другой шрифт — любой TTF с кириллицей на карте и путь в `lvgl_demo.h`. Шрифты бывают большими: для экономии SDRAM подходят версии с урезанным набором символов. - Картинки — PNG или BMP на карте (`LV_USE_LODEPNG` / `LV_USE_BMP` в `lv_conf.h`) и `lv_image_set_src(img, "S:images/logo.png")`. - На той же шине I2C1 можно держать и другие датчики (например, BME280 из рецепта [i2c_bme280](/boards/bh723/recipes/i2c_bme280/)), но HAL I2C не потокобезопасен — обращения к шине из разных задач нужно закрыть мьютексом. --- Исходники рецепта: [recipes/lvgl_demo](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/lvgl_demo) # rtos_queue — две задачи FreeRTOS и очередь > Задача-датчик раз в секунду меряет температуру кристалла (встроенный датчик DTS) и кладёт измерение в очередь. Задача-обработчик забирает измерения и раз в 5 штук печатает среднее. Так обычно и… Задача-датчик раз в секунду меряет температуру кристалла (встроенный датчик DTS) и кладёт измерение в очередь. Задача-обработчик забирает измерения и раз в 5 штук печатает среднее. Так обычно и делят работу в прошивке: кто добывает данные, не ждёт того, кто их обрабатывает. ## Включить ```bash cmake --preset Release -DH723_RECIPES="rtos_queue" ``` ## Вывод на плате ``` rtos_queue: started, period 1000 ms rtos_queue: #5 t=7475 ms, die 58 C (avg of 5), queued 0 rtos_queue: #10 t=12475 ms, die 59 C (avg of 5), queued 0 rtos_queue: #15 t=17475 ms, die 59 C (avg of 5), queued 0 ``` `queued 0` — обработчик успевает, очередь не копится. `t` растёт ровно на 5000 мс. ## Как это работает - **Очередь копирует данные.** `xQueueSend` кладёт в очередь копию структуры `rtosQueueSample`, а не указатель — после отправки датчик может спокойно менять свою переменную. - **Обработчик не тратит процессор, пока ждёт.** `xQueueReceive` с таймаутом усыпляет задачу до прихода данных. Таймаут (2 периода) нужен, чтобы заметить, что датчик замолчал. - **Датчик не ждёт обработчика.** `xQueueSend(..., 0)`: если очередь полна, измерение теряется с предупреждением, а не стопорит датчик. Для данных, которые терять нельзя, ставят таймаут или `portMAX_DELAY`. - **Ровный период.** `vTaskDelayUntil` отсчитывает от прошлого пробуждения, а не от конца работы, поэтому период не «плывёт» из-за времени измерения. - **Приоритеты.** Обработчик на уровень выше датчика: как только в очереди что-то появилось, планировщик сразу переключается на него. - **Статическая память.** Очередь (`xQueueCreateStatic`) и задачи (`xTaskCreateStatic`) — в статических массивах, их размер виден при сборке. ## Переделать под себя - Своё измерение — поля в `rtosQueueSample` и код в `sensorTask`. - Частота и усреднение — `RTOS_QUEUE_PERIOD_MS`, `RTOS_QUEUE_BATCH`. - Если обработчик делает долгую работу (запись на SD, отправка по сети), стоит увеличить `RTOS_QUEUE_LENGTH`, чтобы очередь пережила паузы. - Стек: `uxTaskGetStackHighWaterMark(NULL)` внутри задачи покажет, сколько слов стека ни разу не использовалось. --- Исходники рецепта: [recipes/rtos_queue](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/rtos_queue) # sd_file — файл на SD-карте > Раз в 10 секунд дописывает строку с датой и временем работы в /SD/recipes/log.txt. При старте один раз меряет скорость: пишет и читает файл 4 МБ блоками по 32 КБ. Раз в 10 секунд дописывает строку с датой и временем работы в `/SD/recipes/log.txt`. При старте один раз меряет скорость: пишет и читает файл 4 МБ блоками по 32 КБ. ## Включить ```bash cmake --preset Release -DH723_RECIPES="sd_file" ``` Нужна карта microSD с FAT32 или exFAT. ## Вывод на плате ``` sd_file: started, log /SD/recipes/log.txt every 10 s sd_file: 4096 KB write 10240 KB/s, read 10694 KB/s sd_file: /SD/recipes/log.txt += 2026-03-14 10:02:03 #1 uptime 3 s sd_file: size 68 bytes sd_file: /SD/recipes/log.txt += 2026-03-14 10:02:13 #2 uptime 13 s sd_file: size 103 bytes ``` Размер 68 байт после первой строки — в файле уже была строка с прошлого запуска: файл дописывается, а не перезаписывается. Скорость зависит от карты: на разных картах запись 1,8–10 МБ/с. ## Как это работает - **Пути.** Тома FatFs называются `/SD` и `/RAM` (RAM-диск 4 МБ в SDRAM). Эти пути понимают и стандартный C (`fopen`, `fprintf` — обёртки в `libs/disks/wrappers.c`), и FatFs напрямую (`f_open`, `f_write`). - **Текст — через stdio.** `sdFileAppend` открывает файл в режиме `"a"`, пишет строку и сразу закрывает. `fclose` сбрасывает буфер и обновляет запись в каталоге; если держать файл открытым и пропадёт питание, последние данные потеряются. - **Большие объёмы — через FatFs и крупными блоками.** Драйвер SD (`libs/disks/sddisk.c`) передаёт до 64 секторов одной командой. Блоки по 32 КБ дают скорость в разы выше, чем запись по байту или по строке; буфер такого размера берётся из SDRAM (`sdramMalloc`). - **Карта появляется не сразу.** Её монтирует `appTask`, задача рецепта ждёт `sdDiskIsMounted()`. - **Время.** Из RTC: его ставит NTP-клиент, когда есть интернет через Wi-Fi. У HAL есть правило: сначала `HAL_RTC_GetTime`, потом `HAL_RTC_GetDate`: чтение времени фиксирует теневые регистры до чтения даты, и при обратном порядке следующие показания будут старыми. ## Переделать под себя - Логгер данных: `sdFileAppend("/SD/data.csv", строка)` из своей задачи. При записи чаще раза в секунду строки выгоднее копить (в буфере или файле на RAM-диске `/RAM/...`) и переносить на SD пачкой. - Коды ошибок FatFs (`FRESULT`) — в `third_party/fatfs/source/ff.h`. --- Исходники рецепта: [recipes/sd_file](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/sd_file) # tcp_speed — скорость TCP по Wi-Fi > Плата подключается к точке доступа Wi-Fi и держит два TCP-порта: на 5001 ПК шлёт данные, плата принимает их и выбрасывает; с 5002 плата шлёт поток, пока ПК не закроет соединение. Скорость считают… Плата подключается к точке доступа Wi-Fi и держит два TCP-порта: на 5001 ПК шлёт данные, плата принимает их и выбрасывает; с 5002 плата шлёт поток, пока ПК не закроет соединение. Скорость считают обе стороны. Клиент для ПК — `tcp_speed.py` в этой папке. ## Включить Имя и пароль сети — опциями CMake, в код они не попадают: ```bash cmake --preset Release -B build/Speed -DH723_WITH_LUA=OFF -DH723_WITH_SSH=OFF -DH723_WITH_TLS=OFF \ -DH723_RECIPES="tcp_speed" -DTCP_SPEED_SSID="my_wifi" -DTCP_SPEED_PASSWORD="my_password" cmake --build build/Speed python ../../tools/dfu_flash.py build/Speed/BoardH723.hex ``` Без `TCP_SPEED_SSID` рецепт сам не подключается и ждёт, пока Wi-Fi поднимет `/SD/boot.lua` (прошивка с Lua). Адрес платы — в логе (`IP Address: ...`), дальше на ПК: ```bash python recipes/tcp_speed/tcp_speed.py 192.168.1.50 10 ``` ## Вывод ПК: ``` PC->board: 25.5 Mbit/s (32833536 B, 10.3 s) board->PC: 34.8 Mbit/s (43487800 B, 10.0 s) ``` Плата: ``` tcp_speed: power save 1 -> 0 IP Address: 192.168.1.50 tcp_speed: listening, rx port 5001, tx port 5002 tcp_speed: rx 32833536 bytes in 10319 ms, 25.4 Mbit/s tcp_speed: tx 43540480 bytes in 10013 ms, 34.7 Mbit/s ``` Замеры с роутером TP-Link в диапазоне 2,4 ГГц (ПК подключён к тому же роутеру на 5 ГГц): | Прошивка | ПК → плата | Плата → ПК | |---|---|---| | без Lua, SSH и TLS, окна рецепта, энергосбережение выключено | 24–25 Мбит/с | 33–35 Мбит/с | | то же, окна TCP по умолчанию | 12 Мбит/с | 14 Мбит/с | | с Lua и SSH, точка доступа и BLE работают, энергосбережение включено | 14–15 Мбит/с | 35–37 Мбит/с | Эфир 2,4 ГГц меняется от минуты к минуте: прогоны подряд расходятся на 10–20 %. ## Как это работает - **Окно TCP.** Отправитель держит в пути не больше окна получателя и ждёт подтверждений, поэтому скорость не выше «окно / время ответа». В FreeRTOS+TCP окно по умолчанию — половина буфера сокета, 8 сегментов (11,7 КБ). Рецепт задаёт буферы и окна опцией `FREERTOS_SO_WIN_PROPERTIES` на слушающем сокете, принятые соединения её наследуют. Окно приёма — 32 сегмента: с большим ПК шлёт пачками, очередь на ESP32-C2 переполняется, и TCP на ПК после потерь сбрасывает скорость. Окно отправки — 44 сегмента (64 КБ, предел без масштабирования окна). Глобальные размеры в `FreeRTOSIPConfig.h` не увеличены: каждый активный сокет (SSH, Lua) занимал бы до 90 КБ кучи. - **Подтверждения.** FreeRTOS+TCP откладывает ACK на полный сегмент до 20 мс — при приёме потока это потолок около 18 Мбит/с. Сборка заменяет задержку на 2 мс (`patch_source` в `examples/BoardH723/CMakeLists.txt`), это действует на все сокеты. - **Энергосбережение.** По умолчанию радио ESP32-C2 спит между маяками точки доступа (`WIFI_PS_MIN_MODEM`), и приём идёт рывками. Рецепт выключает его: `wifiSetPowerSaveMode(WIFI_PS_NONE)` — плата потребляет больше. - **Приём без копии.** `FreeRTOS_recv` с флагом `FREERTOS_ZERO_COPY` отдаёт указатель прямо в буфер сокета, `FreeRTOS_ReleaseTCPPayloadBuffer` освобождает место. - **Потолок.** Кадры между STM32 и ESP32-C2 идут по SPI 62,5 МГц транзакциями по 1600 байт — около 0,2 мс на кадр, это примерно 40 Мбит/с на отправку. Приём ограничивает ESP32-C2: радио и около 25 КБ свободной памяти на буферы. - **Прошивка ESP32-C2.** Цифры выше получены с актуальной прошивкой [esp32c2phy](https://github.com/Kits-Lab-Dev/esp32c2phy) (ветка `main`): двойной буфер SPI, приём из эфира без копии. Как прошить ESP32-C2 — `AGENTS.md`, раздел «Прошивка». --- Исходники рецепта: [recipes/tcp_speed](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/tcp_speed) # uart_dma — приём UART через DMA > Принимает символы с USART1 (тот же порт, куда идёт лог) через DMA в кольцевой буфер, собирает строки и выполняет команды: help, led on, led off, uptime. Любая другая строка печатается обратно с… Принимает символы с USART1 (тот же порт, куда идёт лог) через DMA в кольцевой буфер, собирает строки и выполняет команды: `help`, `led on`, `led off`, `uptime`. Любая другая строка печатается обратно с длиной. ## Включить ```bash cmake --preset Release -DH723_RECIPES="uart_dma" ``` Терминал на USART1 115200 8N1: PB15 — вход платы (RX), PB14 — выход (TX). Через отладчик «Лобзик» это его виртуальный COM-порт; можно и любой USB-UART 3,3 В на J2 (13 — PB15, 14 — PB14). ## Вывод на плате Команды отправлены с ПК в терминал USART1: ``` uart_dma: started, type 'help' in USART1 terminal uart_dma: commands: help, led on, led off, uptime uart_dma: led on uart_dma: uptime 15503 ms uart_dma: rx 'hello board 123' (15 bytes) ``` При переполнении строка из 300 символов принимается и обрезается до 127 (длина буфера строки), восемь строк подряд по 42 байта принимаются целыми, хотя кольцевой буфер DMA (256 байт) за это время оборачивается несколько раз. ## Как это работает - **DMA в кольцевом режиме.** DMA1 Stream3 по запросу `USART1_RX` пишет каждый принятый байт в буфер 256 байт и, дойдя до конца, начинает сначала. Процессор в приёме байтов не участвует. - **Когда разбирать буфер.** `HAL_UARTEx_ReceiveToIdle_DMA` вызывает колбэк в трёх случаях: буфер заполнен наполовину, заполнен целиком и линия замолчала (событие IDLE — пауза в один символ). Последнее важно: команда из 6 символов не заполнит буфер, но придёт сразу после паузы. - **Новые данные — от прошлой позиции до текущей.** Колбэк получает позицию DMA в буфере; байты между прошлой и новой позицией (с переходом через край) уходят в `StreamBuffer` FreeRTOS. - **Прерывание короткое.** В колбэке только копирование в `StreamBuffer`; строки собирает и команды выполняет обычная задача `uartRx`, которой можно печатать и ждать. - **Память для DMA.** Буфер — в RAM_D1 (`pvPortMalloc`), выровнен по 32 байта (строка кэша); RAM_D1 кэшируется, поэтому перед чтением — `SCB_InvalidateDCache_by_Addr`. - **Шум на линии.** Без подтяжки неподключённый вход ловит помехи и ошибки кадра; рецепт включает подтяжку PB15 к 3,3 В. После ошибки UART приём перезапускается в `rxError`. - **Передача не тронута.** Лог печатает через тот же `huart1` (DMA1 Stream2); приём и передача у HAL независимы. ## Переделать под себя - Свои команды — в `handleLine`. - Свой протокол (бинарный, Modbus, NMEA) — байты берутся из `uartDmaRead()` и разбираются своим кодом, без `uartTask`. - Другой UART: свободны USART2 (PA2/PA3), USART3 (PB10/PB11), UART4 (PA0/PA1) и другие — их нужно сначала включить (CubeMX или вручную: такты, выводы, `HAL_UART_Init`), затем поменять `huart`, `DMA_REQUEST_...` и, при занятом Stream3, номер потока DMA. --- Исходники рецепта: [recipes/uart_dma](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/uart_dma) # wifi_http — Wi-Fi и HTTP-запрос > Подключается к точке доступа Wi-Fi и раз в минуту делает GET http://example.com/: адрес по DNS, TCP-соединение, запрос, код ответа и объём. Только сокеты FreeRTOS+TCP, без библиотек. Подключается к точке доступа Wi-Fi и раз в минуту делает `GET http://example.com/`: адрес по DNS, TCP-соединение, запрос, код ответа и объём. Только сокеты FreeRTOS+TCP, без библиотек. ## Включить Имя и пароль сети — в `wifi_http.h`: ```c #define WIFI_HTTP_SSID "my_wifi" #define WIFI_HTTP_PASSWORD "my_password" ``` Если оставить пустыми, рецепт сам не подключается и ждёт, пока Wi-Fi поднимет кто-то другой — `/SD/boot.lua` (`wifi.connect(...)`) в прошивке с Lua. В прошивке без Lua (`-DH723_WITH_LUA=OFF`) имя и пароль нужно задать здесь. ```bash cmake --preset Release -DH723_RECIPES="wifi_http" ``` ## Вывод на плате Wi-Fi поднял `boot.lua`, плата получила адрес 192.168.1.50. Строки `->` с адресом — отладочный уровень лога (`DBG`): ``` wifi_http: started, GET http://example.com/ every 60 s IP Address: 192.168.1.50 wifi_http: example.com -> 8.6.112.6 wifi_http: GET http://example.com/ -> 200, 932 bytes, 3160 ms wifi_http: example.com -> 8.6.112.6 wifi_http: GET http://example.com/ -> 200, 929 bytes, 146 ms ... wifi_http: example.com -> 8.6.112.0 wifi_http: connect example.com (8.6.112.0):80 error -116 wifi_http: example.com -> 8.47.69.0 wifi_http: GET http://example.com/ -> 200, 930 bytes, 5417 ms ``` Первый запрос после подключения дольше (3 с). В конце — перебор адресов: первый не ответил за 5 с (`-116` — таймаут), сработал второй. При ошибке рецепт пишет, на каком шаге: 1 — DNS, 2 — сокет, 3 — соединение (с адресом и кодом ошибки), 4 — отправка, 5 — нет ответа HTTP. ## Как это работает - **Wi-Fi.** ESP32-C2 на плате — сетевой адаптер: TCP/IP работает на STM32 (FreeRTOS+TCP), а ESP передаёт кадры Ethernet по SPI. Подключение — те же вызовы, что в Lua: `espFeatureEnable(ftWifi)`, `wifiSetWiFiMode(WIFI_MODE_STA)`, `wifiConnect()` из `libs/esp/control.h`. `autoReconnect = true` — ESP сам переподключается при обрыве. - **Адрес.** Плата получает IP по DHCP от роутера. Задача ждёт, пока интерфейс поднят и у него есть шлюз: если DHCP не ответил, стек сам назначает адрес 169.254.x.x без шлюза, и с ним в интернет не выйти. - **Три сети одновременно.** У платы есть USB-сеть (192.168.4.1), точка доступа (192.168.11.1) и Wi-Fi-клиент. Пакет в интернет уходит через тот интерфейс, где есть шлюз, — Wi-Fi-клиент. - **DNS и несколько адресов.** `FreeRTOS_getaddrinfo` спрашивает DNS-сервер, выданный роутером, и возвращает список адресов. У крупных сайтов адресов несколько, и какой-то может не отвечать — `httpConnect` пробует их по очереди. Кэш DNS хранит до 4 адресов на имя (`ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY` в `config/FreeRTOSIPConfig.h`), поэтому повторный запрос из кэша отдаёт весь список, а не один последний адрес ответа — он может оказаться мёртвым. Ошибки FreeRTOS+TCP — отрицательные `pdFREERTOS_ERRNO_*`. - **Таймауты.** `FREERTOS_SO_RCVTIMEO`/`SNDTIMEO` по 5 с: без них `recv` ждёт вечно, если сервер замолчал. - **Конец ответа.** Заголовок `Connection: close` — сервер закрывает соединение после ответа, и `FreeRTOS_recv` возвращает ошибку: так конец ответа виден без разбора `Content-Length`. - **Тело ответа.** Если передать `wifiHttpGet` буфер, ответ принимается в него целиком; тело начинается после пустой строки `"\r\n\r\n"` и возвращается в `res.body`. Ответ с `Transfer-Encoding: chunked` (куски «длина в hex, данные») склеивается в обычную строку. Не поместился в буфер — код `-6`, начало ответа при этом в буфере есть. - **Закрытие.** `FreeRTOS_shutdown`, дождаться ответного закрытия, затем `FreeRTOS_closesocket`. Если сразу звать `closesocket`, соединение у сервера может остаться висеть. ## Переделать под себя - Другой адрес — `WIFI_HTTP_HOST`, `WIFI_HTTP_PATH`. Пример разбора тела (JSON с погодой) и подключения к сети из своего кода (`wifiHttpJoin`, `wifiHttpOnline`) — рецепт [lvgl_clock](/boards/bh723/recipes/lvgl_clock/). - Отправка данных на сервер (POST) — тот же код, в запросе `POST`, заголовки `Content-Type` и `Content-Length` и тело после пустой строки. - HTTPS — через Mbed TLS (`libs/tls`, его уже использует Lua-модуль `ssl`); в рецепт не входит. --- Исходники рецепта: [recipes/wifi_http](https://github.com/Kits-Lab-Dev/Board-H723/tree/main/recipes/wifi_http) # ПО для разработки > ПО для Доски H723: STM32CubeCLT, CMake, VSCode, сборка и прошивка по USB, отладка, SSH и Lua, готовый проект с FreeRTOS, Wi-Fi, USB-Ethernet и рецепты на C. Для программирования Доски H723 понадобятся компилятор и утилиты ST, CMake, Git и Python 3. Редактор — любой; для VSCode в проекте уже есть задачи сборки, прошивки и отладки. ## Что установить - [STM32CubeCLT](https://www.st.com/en/development-tools/stm32cubeclt.html) 1.18 или новее — компилятор `arm-none-eabi-gcc`, CMake, Ninja, `STM32_Programmer_CLI` и GDB-сервер. Все эти программы должны быть в `PATH`. - [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html) — генератор кода периферии; нужен, только если меняются выводы, такты или DMA. - [Git](https://git-scm.com/) и [Python 3](https://www.python.org/) — для скриптов прошивки и сборки архива SD-карты. - [Visual Studio Code](https://code.visualstudio.com/) и расширения: - [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools-extension-pack) — подсветка и навигация по коду; - [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) — сборка из редактора; - [Cortex-Debug](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) — прошивка и отладка из редактора. :::note Скачать STM32CubeCLT, STM32CubeMX и пакеты с библиотеками для STM32H7 можно с нашего [облака](https://disk.yandex.ru/d/Fjw2cZVs_fMvog). ::: ## Получение исходников Сторонние библиотеки подключены как git submodule, поэтому после клонирования их нужно скачать: ```bash git clone https://github.com/Kits-Lab-Dev/Board-H723.git cd Board-H723 git submodule update --init ``` Архив [zip](https://github.com/Kits-Lab-Dev/Board-H723/archive/refs/heads/main.zip) для сборки не подходит: в нём нет сторонних библиотек. На Windows: - перед клонированием включите длинные пути: `git config --global core.longpaths true`, иначе часть файлов wolfSSL не создастся; - клонируйте в короткий путь, например `C:\src\Board-H723`: при длинном пути CMake предупреждает о пределе в 250 символов на путь объектного файла. ## Что в репозитории В папке `examples` два проекта: - `BoardH723` — готовый проект для платы: - драйвер Wi-Fi и BLE (ESP32-C2 по SPI с DMA), совместимый с сокетами Unix; - USB-NCM (USB-Ethernet) и DHCP-сервер для USB и точки доступа Wi-Fi; - FreeRTOS и FreeRTOS+TCP; - FatFs: microSD (`/SD`) и RAM-диск в SDRAM (`/RAM`), менеджер памяти SDRAM; - SSH-сервер с SFTP (загрузка файлов на SD-карту) и терминалом; - интерпретатор Lua: GPIO, SPI, I2C, UART, потоки, Wi-Fi, сокеты, HTTPS; - `ESP-Loader` — мост USB-UART для прошивки ESP32-C2 через STM32. Рядом лежат [рецепты](/boards/bh723/recipes/) — готовые модули на C, `docs/board.md` с описанием железа для прошивки и `tools/` со скриптами. Состав и лицензии сторонних библиотек — `THIRD_PARTY.md`. ## Сборка ```bash cd examples/BoardH723 cmake --preset Release cmake --build build/Release ``` Результат — `build/Release/BoardH723.elf`, `.hex` и `.bin`; ELF содержит отладочную информацию. Собирается GCC 13 (из STM32CubeCLT) и GCC 14 (Arm GNU Toolchain). Опции CMake добавляются к первой команде: | Опция | Что делает | |---|---| | `-DH723_WITH_SSH=OFF` | убирает SSH и SFTP | | `-DH723_WITH_TLS=OFF` | убирает HTTPS для Lua | | `-DH723_WITH_LUA=OFF` | убирает Lua целиком, вместе с HTTPS для него — освобождается Flash под LVGL | | `-DH723_IDLE_SLEEP=ON` | в простое ядро засыпает командой WFI: кристалл остывает с 66 до 51 °C | | `-DH723_RECIPES="a;b"` | подключает рецепты, [список](/boards/bh723/recipes/) | Размер прошивки при GCC 13: около 808 КБ со всем, 629 КБ без SSH, 530 КБ без SSH и TLS; без Lua, но с SSH — 482 КБ. ## Сборка и отладка из VSCode 1. Откройте папку `examples/BoardH723`. CMake Tools предложит выбрать пресет — выберите `Release`. 2. При настройке проекта CMake создаёт в `.vscode` файлы `tasks.json` и `launch.json` из шаблонов `tasks.json.in` и `launch.json.in`: - задача `build` — сборка; - задача `DFU Upload` — сборка и запись прошивки через `STM32_Programmer_CLI` по USB DFU; - конфигурация отладки `stlink` для Cortex-Debug. 3. В переменной среды `STM32CLT_PATH` должен быть путь к STM32CubeCLT: по нему конфигурации находят программатор и файл описания регистров `STM32H723.svd`. ## Прошивка **По USB, без кнопок и отладчика.** Плата подключена кабелем USB-C, в ней работает прошивка из этого проекта: ```bash python tools/dfu_flash.py ``` Скрипт отправляет плате UDP-пакет `dfu`, плата перезагружается в системный загрузчик STM32, скрипт записывает `build/Release/BoardH723.hex`, запускает прошивку и ждёт ответа на ping — около 40 секунд. Другой файл: `python tools/dfu_flash.py путь/к/файлу.hex`. **Если плата не отвечает** (нет USB-сети, прошивка старая или зависла): зажмите BOOT, нажмите RESET (или переподключите USB), отпустите BOOT — плата входит в DFU — и запустите скрипт ещё раз. На Windows для DFU нужен драйвер STM32 DFU, он ставится вместе со STM32CubeProgrammer; устройство в диспетчере называется «STM32 BOOTLOADER». **Отладчик «Лобзик»** по SWD (разъём J6) — прошивка, чтение памяти и регистров на работающей плате, разбор HardFault, лог USART1: [навык и скрипты](https://github.com/Kits-Lab-Dev/lobzik-skill). **Модуль ESP32-C2** прошивается через STM32 командой `reboot esploader` в SSH (или `rtos.reboot("esploader")` в Lua): плата запускает мост ESP-Loader с SD-карты, и на ПК появляется USB-UART для esptool. Прошивка модуля — проект [esp32c2phy](https://github.com/Kits-Lab-Dev/esp32c2phy), собирается ESP-IDF 5.4. ## SD-карта Плата работает и без карты, но SSH, Lua и многие рецепты используют её. Содержимое карты — файлы из `examples/BoardH723/app/SD` (скрипт загрузки `boot.lua`, библиотеки Lua, шрифты, `utils/ESPLoader.bin`): - готовый архив `sd-card.zip` лежит в [релизах](https://github.com/Kits-Lab-Dev/Board-H723/releases); его распаковывают в корень карты FAT32; - собрать архив самостоятельно: `python tools/make_sd_zip.py` (результат — `build/sd-card.zip`); - на работающую плату файлы заливаются по SFTP в `/SD/`. ## Вход по SSH Плата в USB-сети — `192.168.4.1`, вход `ssh root@192.168.4.1`; по Wi-Fi — на адрес, выданный роутером (команда `ip` в терминале). Пароль при первом запуске плата создаёт сама, сохраняет в файл `/SD/.ssh/password` на SD-карте и печатает в лог (USART1). Сменить пароль — исправить этот файл и перезагрузить плату. Без карты войти по паролю нельзя. Вход по ключу: создайте пару `ssh-keygen -t rsa -b 4096`, скопируйте открытый ключ на карту в `/SD/.ssh/mcu.key.pub` и входите командой `ssh root@192.168.4.1 -i ~/.ssh/mcu.key`. Пока на карте есть этот файл, вход по паролю выключен. Команды терминала: `help`, `ls`, `cat`, `cd`, `top`, `ip`, `reboot` (`reboot dfu` — в загрузчик USB, `reboot esploader` — режим прошивки ESP32-C2), `lua -f /SD/x.lua`, `exit`. Терминал режет аргументы по пробелам и не понимает кавычки — Lua-код запускайте файлом. ## Lua Lua — дополнительный интерпретатор для быстрых опытов; основной язык проекта — C. Скрипты кладут на SD-карту и запускают командой `lua -f /SD/x.lua`; `/SD/boot.lua` выполняется при загрузке. Описание модулей — в репозитории, в `examples/BoardH723/libs/lua/docs`: `pio` (GPIO, ШИМ, АЦП), `serial`, `spi`, `i2c`, `lthread`, `wifi`, `rtos`. ## Рецепты Готовые модули на C — кнопка, UART с DMA, датчик на I2C, Wi-Fi и HTTP, скорость TCP, файлы на SD, задачи FreeRTOS, дисплей и LVGL — с объяснением, как они устроены: [Рецепты для Доски H723](/boards/bh723/recipes/). Подключаются к проекту `BoardH723` одной опцией CMake и не требуют правки его кода. ## Свой код и CubeMX - Своё приложение проще всего начать с ближайшего рецепта. Иначе — файлы в `app/` или `libs/<имя>/`, добавленные в `target_sources` и `board_includes` в `CMakeLists.txt`. Новые задачи FreeRTOS создаются из `appTask` (`app/app.c`) после запуска нужных подсистем. - В файлах, созданных CubeMX (`Core/`, `Drivers/`), правьте только внутри блоков `/* USER CODE BEGIN ... */ ... /* USER CODE END ... */` — остальное перезаписывается при генерации. Такты, выводы, MPU, DMA и периферию меняют в `BoardH723.ioc` и генерируют код заново. - Выводы SDRAM, microSD, ESP32-C2 и USB разведены на плате — не переназначайте их ([таблица занятых выводов](https://github.com/Kits-Lab-Dev/Board-H723/blob/main/docs/board.md)). MPU-регион SDRAM должен остаться «не Shareable». - Внутренней памяти мало: большие буферы берите из SDRAM (`sdramMalloc`) или из кучи FreeRTOS (`pvPortMalloc`; `malloc` уже перенаправлен в неё). - Сторонние библиотеки в `third_party/` не правятся: настройки лежат в `config/`, неизбежные правки — в `cmake/patch_source.cmake`. - В коде проекта (`app/`, `libs/`, `Core/`, `recipes/`) неявное объявление функции, смешение указателя с целым и `return` без значения — ошибки сборки: объявляйте функции в заголовках. - Лог выводится в USART1 (115200 8N1, PB14 TX / PB15 RX; разъём J6 и J2); макросы `INF`, `WRN`, `ERR` из `app/log.h`. :::tip[Для ИИ-агентов] В репозитории есть [AGENTS.md](https://github.com/Kits-Lab-Dev/Board-H723/blob/main/AGENTS.md) — как собрать, прошить и проверить плату. Вся вики одним файлом: [llms-full.txt](/llms-full.txt), только Доска H723 — [board-h723.txt](/_llms-txt/board-h723.txt). ::: # Щепа F042 > Щепа F042 — плата на STM32F042 (Cortex-M0) с USB Type-C, совместима с NUCLEO-F042K6: распиновка, работа в Arduino IDE и PlatformIO, прошивка по DFU. ## Характеристики - Микроконтроллер: STM32F042K6T6 - Ядро: ARM Cortex-M0 - Частота ядра: 48 MHz - Флэш память : 32 Кбайт - ОЗУ: 6 Кбайт - Напряжение питания: 2.0 V - 3.6 V - Таймеры (6) - SPI/I2S (1) - I2C (1) - USART (2) - 12-bit АЦП, 10 каналов (1) - GPIO (20) - RTC - USB Device (Type C) - Выход для подключения отладчика - Пользовательская кнопка (можно использовать для перехода в режим загрузчика) ## Описание Совместимость по выходам с `NUCLEO-F042K6`, USB подключен к микроконтроллеру (GPIO: PA11/PA12) для работы в режиме USB Device или встроенного загрузчика DFU. Для перехода в режим DFU нужно включить питание платы либо активировать RESET с нажатой кнопкой SW1. Для быстрого перехода в режим загрузчика можно активировать прерывание по выводу PB6(D5) (к нему подключена пользовательская кнопка) для этого нужно в функцию `void setup()` вставить код: ```cpp pinMode(5, INPUT); attachInterrupt(5, NVIC_SystemReset, RISING); ``` [Github - схемы и примеры](https://github.com/Kits-Lab-Dev/wood-chips-F042) ## Arduino IDE Для работы с платой в [Arduino IDE](https://www.arduino.cc/en/software) нужно добавить ссылку для менеджера плат в меню `Файл -> Параметры` в строку: `Дополнительные ссылки для Менеджера плат`: ``` https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json ``` В менеджере плат установить библиотеку `STM32 MCU based boards`: Выбрать целевую плату: Выбрать режим загрузки скетча: При необходимости подключить поддержку `USB CDC` - виртуальный com-порт: Для прошивки контроллера понадобится [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) [без VPN](https://disk.yandex.ru/d/Fjw2cZVs_fMvog) ### Пример ```cpp //Светодиод на D13 #define LED 13 //Кнопка на D5 #define BUTTON 5 void setup() { //Подключение пользовательской кнопки для быстрой перезагрузки и входа в режим загрузчика (DFU) pinMode(BUTTON, INPUT); pinMode(LED, OUTPUT); // Запуск USB Device в режиме CDC (виртуальный COM-порт) SerialUSB.begin(); } bool led = false; int i = 0; void loop() { // проверка нажата ли кнопка if (digitalRead(BUTTON) == HIGH) { //перезагрузка микроконтроллера NVIC_SystemReset(); } if (led) { led = false; digitalWrite(LED, HIGH); } else { led = true; digitalWrite(LED, LOW); } delay(250); i++; Serial.print(i); } ``` ## PlatformIO VSCode Для работы с платой в среде [VSCode](https://code.visualstudio.com/) нужно установить расширение [PlatformIO](https://platformio.org/platformio-ide). Создать новый проект, выбрать целевую плату и фреймворк: В файле `platformio.ini` добавить строку `upload_protocol = dfu` для загрузки прошивки через USB, при необходимости подключить поддержку `USB CDC` - виртуальный com-порт добавив `build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC -D USBCON` : ```ini [env:nucleo_f042k6] platform = ststm32 board = nucleo_f042k6 framework = arduino upload_protocol = dfu build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC -D USBCON ``` ### Пример ```cpp #include //Светодиод на D13 #define LED 13 //Кнопка на D5 #define BUTTON 5 void setup() { //Подключение пользовательской кнопки для быстрой перезагрузки и входа в режим загрузчика (DFU) pinMode(BUTTON, INPUT); pinMode(LED, OUTPUT); // Запуск USB Device в режиме CDC (виртуальный COM-порт) SerialUSB.begin(); } bool led = false; int i = 0; void loop() { // проверка нажата ли кнопка if (digitalRead(BUTTON) == HIGH) { //перезагрузка микроконтроллера NVIC_SystemReset(); } if (led) { led = false; digitalWrite(LED, HIGH); } else { led = true; digitalWrite(LED, LOW); } delay(250); i++; Serial.print(i); } ``` # Щепа L432 > Щепа L432 — плата на STM32L432 (Cortex-M4, 80 МГц) с USB Type-C, совместима с NUCLEO-L432KC: распиновка, Arduino IDE и PlatformIO, прошивка по DFU. ## Характеристики - Микроконтроллер: STM32L432KCU6 - Ядро: Arm Cortex-M4 - Частота ядра: 80 MHz - Флэш память : 256 Кбайт - ОЗУ: 64 Кбайт - Напряжение питания: 1.65 V - 3.6 V - Таймеры (4) - SPI/I2S (2) - I2C (2) - USART (2) - 12-bit АЦП, 10 каналов (1) - GPIO (20) - RTC - USB Device (Type C) - Выход для подключения отладчика - Пользовательская кнопка (можно использовать для перехода в режим загрузчика) ## Описание Совместимость по выходам с NUCLEO-L432KC, USB подключен к микроконтроллеру (GPIO: PA11/PA12) для работы в режиме USB Device или встроенного загрузчика DFU. Для перехода в режим DFU нужно включить питание платы либо активировать RESET с **нажатой кнопкой SW1**. Для быстрого перехода в режим загрузчика можно активировать прерывание по выводу PH3 (к нему подключена пользовательская кнопка) для этого нужно в функцию `void setup()` вставить код: ```cpp //Включение тактирования порта GPIOH __HAL_RCC_GPIOH_CLK_ENABLE(); //подключение прерывания для вывода PH3, для активации RESET по нажатию кнопки stm32_interrupt_enable(GPIOH, LL_GPIO_PIN_3, NVIC_SystemReset, GPIO_MODE_IT_RISING); ``` [Github - схемы и примеры](https://github.com/Kits-Lab-Dev/wood-chips-L432) Щепу L432 можно превратить в SWD/JTAG-отладчик: прошивка отладчика [Лобзик](/debugers/fretsaw/#прошивка-лобзика-на-щепе-l432) работает на ней без изменений. ## Arduino IDE Для работы с платой в [Arduino IDE](https://www.arduino.cc/en/software) нужно добавить ссылку для менеджера плат в меню `Файл -> Параметры` в строку: `Дополнительные ссылки для Менеджера плат`: ``` https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json ``` В менеджере плат установить библиотеку `STM32 MCU based boards`: Выбрать целевую плату Выбрать режим загрузки скетча При необходимости подключить поддержку `USB CDC` - виртуальный com-порт: Для прошивки контроллера понадобится [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html) [без VPN](https://disk.yandex.ru/d/Fjw2cZVs_fMvog) ### Пример ```cpp //Светодиод на D13 #define LED 13 void setup() { //Подключение пользовательской кнопки для быстрой перезагрузки и входа в режим загрузчика (DFU) //Включение тактирования порта GPIOH __HAL_RCC_GPIOH_CLK_ENABLE(); //переключение вывода PH3 в режим входа LL_GPIO_SetPinMode(GPIOH, LL_GPIO_PIN_3, LL_GPIO_MODE_INPUT); pinMode(LED, OUTPUT); // Запуск USB Device в режиме CDC (виртуальный COM-порт) SerialUSB.begin(); } bool led = false; int i = 0; void loop() { // проверка нажата ли кнопка if (LL_GPIO_IsInputPinSet(GPIOH, LL_GPIO_PIN_3)) { //перезагрузка микроконтроллера NVIC_SystemReset(); } if (led) { led = false; digitalWrite(LED, HIGH); } else { led = true; digitalWrite(LED, LOW); } delay(250); i++; Serial.print(i); } ``` ## PlatformIO VSCode Для работы с платой в среде [VSCode](https://code.visualstudio.com/) нужно установить расширение [PlatformIO](https://platformio.org/platformio-ide). Создать новый проект, выбрать целевую плату и фреймворк: В файле `platformio.ini` добавить строку `upload_protocol = dfu` для загрузки прошивки через USB, при необходимости подключить поддержку `USB CDC` - виртуальный com-порт добавив `build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC -D USBCON` : ```ini [env:nucleo_l432kc] platform = ststm32 board = nucleo_l432kc framework = arduino upload_protocol = dfu build_flags = -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC -D USBCON ``` ### Пример ```cpp #include //Светодиод на D13 #define LED 13 void setup() { //Подключение пользовательской кнопки для быстрой перезагрузки и входа в режим загрузчика (DFU) //Включение тактирования порта GPIOH __HAL_RCC_GPIOH_CLK_ENABLE(); //переключение вывода PH3 в режим входа LL_GPIO_SetPinMode(GPIOH, LL_GPIO_PIN_3, LL_GPIO_MODE_INPUT); pinMode(LED, OUTPUT); // Запуск USB Device в режиме CDC (виртуальный COM-порт) SerialUSB.begin(); } bool led = false; int i = 0; void loop() { // проверка нажата ли кнопка if (LL_GPIO_IsInputPinSet(GPIOH, LL_GPIO_PIN_3)) { //перезагрузка микроконтроллера NVIC_SystemReset(); } if (led) { led = false; digitalWrite(LED, HIGH); } else { led = true; digitalWrite(LED, LOW); } delay(250); i++; Serial.print(i); } ``` # Вагонка-ВГ015 > Вагонка-ВГ015 — плата на отечественном RISC-V микроконтроллере К1921ВГ015: характеристики, распиновка, быстрый старт в VSCode с SDK НИИЭТ. ## Характеристики - Микроконтроллер К1921ВГ015 (50 MHz) - Ядро: RISC-V 32bit CPU - система команд: RV32IMFCN_ZBA_ZBB_ZBC_ZBS; - от 32 КГц до 50 МГц; - 1.35 DMIPS/MHz (Dhrystone 2.1) - Ультра низкое потребление: - напряжение питания: 1,62 В – 3,60В - до 8 мкА в режиме POWERDOWN (GPR, RTC, внутренний RCосциллятор, 3 WAKEUP) - до 190 мкА в режиме STOP (GPR, RTC, внутренний RC-осциллятор, 3 WAKEUP, SRAM1, CMP) - до 500 мкА / МГц в режиме RUN - Память: - 256 Кб памяти ОЗУ0 - 64 Кб памяти ОЗУ1 в батарейном домене - 1 Мб Flash памяти ## Быстрый старт в VSCode Скачать и установить расширение NIIET [niiet-aspect-x.x.x.vsix](https://gitflic.ru/project/niiet/niiet_riscv_sdk/file?file=tools&branch=master). После установки вы попадете в диалоговое окно с выбором расширения, найдите скачанное расширение и выберете его, затем оно установится в VSCode. После успешной установки расширения в левой панели появится кнопка с логотипом `НИИЭТ`. Нажатие на кнопку откроет меню расширения. Из этого меню можно установить: - `SDK` , - `компилятор` , - `инструменты для отладки` , если они требуются. После настройки инструментов создать новый проект: настроить `launch.json` по инструкции: [Настройка launch.json для прошивки и отладки через отладчик Лобзик (Black Magic Debug)](/debugers/fretsaw/#-настройка-launchjson) *пример launch.json для Лобзика:* ```java { "version": "0.2.0", "configurations": [ { "name": "Debug via Black Magic Probe (RISC-V)", "type": "cortex-debug", "request": "launch", "servertype": "bmp", "BMPGDBSerialPort": "com1", "gdbPath": "riscv-none-elf-gdb", // указать свой путь к gdb или использовать из комплекта НИИЭТ // "gdbPath": ".niiet_aspect\\riscv_gcc_windows\\bin\\riscv64-unknown-elf-gdb.exe", "executable": "test.elf", // указать путь к исполняемому файлу "svdFile": ".niiet_aspect/niiet_aspect_sdk/svd/K1921VG015.svd", // указать путь к svd файлу "interface": "jtag", // "powerOverBMP": "enable", //если требуется питание от Лобзика "overrideLaunchCommands": [ // "mon freq 1000000", // частота jtag "load" ], "overrideResetCommands": [ "mon swreset" ], "overrideRestartCommands": [ "mon swreset", "load" ] } ] } ``` После создания проекта будет доступно меню проекта, где можно изменить настройки проекта и запустить сборку: #### Пример простого blink на библиотеке Plib: ```c #include #include #define __NOP() asm volatile("nop"); int main(void) { SystemInit(); SystemCoreClockUpdate(); RCU_AHBClkCmd(RCU_AHBClk_GPIOC, ENABLE); RCU_AHBRstCmd(RCU_AHBRst_GPIOC, ENABLE); GPIO_OutCmd(GPIOC, GPIO_Pin_0, ENABLE); GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET); int delay = SystemCoreClock / 50; for (;;) { GPIO_ToggleBits(GPIOC, GPIO_Pin_0); for (int i = 0; i < delay; i++) { __NOP(); } } return 0; } ``` [Оригинальный быстрый старт от НИИЭТ](https://niiet.ru/wp-content/uploads/2025/09/%D0%91%D1%8B%D1%81%D1%82%D1%80%D1%8B%D0%B9_%D1%81%D1%82%D0%B0%D1%80%D1%82_NIIET_RISCV-1.pdf) [Настройка launch.json для прошивки и отладки через отладчик Лобзик (Black Magic Debug)](/debugers/fretsaw/#-настройка-launchjson) [Репозиторий НИИЭТ](https://gitflic.ru/project/niiet/niiet_riscv_sdk) # Отладчики - [Лобзик](/debugers/fretsaw/) # Лобзик > Лобзик — SWD/JTAG отладчик на Black Magic Debug с поддержкой RISC-V и К1921ВГ015: распиновка, настройка VSCode и Cortex-Debug. ## SWD/JTAG отладчик на базе Black Magic Debug - Полная поддержка Black Magic Debug: отладка «из коробки» без необходимости в дополнительном ПО вроде OpenOCD. - Два режима подключения: SWD (Serial Wire Debug) и JTAG — для максимальной гибкости. - Встроенная GDB-серверная функциональность: подключайтесь напрямую через GDB — никаких промежуточных утилит. - Открытая прошивка и схемотехника: вы можете изучать, модифицировать и адаптировать под свои задачи. - Поддержка целей RISC-V: идеален для работы с современными микроконтроллерами. - Поддержка **К1921ВГ015** [Схема отладчика](https://kitslab.ru/debugers/sch.pdf) ## Навык для ИИ-агентов Лобзиком может управлять ИИ-агент (Claude Code и другие агенты с поддержкой навыков): прошить плату, снять лог UART с самой загрузки, прочитать регистры на работающей плате, разобрать зависание или HardFault, обновить прошивку Лобзика. Скажите агенту «прошей и покажи лог» — он сделает всё сам. Навык и инструкция по установке: [github.com/Kits-Lab-Dev/lobzik-skill](https://github.com/Kits-Lab-Dev/lobzik-skill). Скрипт из навыка работает и без агента — из терминала. ## Обновление прошивки Свежая прошивка — в [релизах на GitHub](https://github.com/Kits-Lab-Dev/blackmagic/releases/latest) (`fretsaw_bmp.bin`). Проще всего обновить скриптом из навыка: `python lobzik.py reflash` — он сам скачает прошивку и запишет её без нажатия кнопки. Вручную: зажмите кнопку на Лобзике, подключите USB, отпустите и запишите `fretsaw_bmp.bin` с адреса `0x08000000` через STM32CubeProgrammer или `dfu-util`. Подробно — в описании релиза. ## Прошивка Лобзика на Щепе L432 Прошивка Лобзика без изменений работает на [Щепе L432](/boards/sl432/): Щепа становится отладчиком Black Magic Probe с GDB-сервером и UART цели. Шьётся так же, через DFU (`fretsaw_bmp.bin` из [релизов](https://github.com/Kits-Lab-Dev/blackmagic/releases/latest)). Цель подключается напрямую к выводам Щепы. UART TX Щепы (PA2) — на RX цели, UART RX (PA3) — на TX цели.
Схема подключения Щепа L432 с прошивкой Лобзика: выводы SWD/JTAG, UART и VTREF
Чем Щепа отличается от Лобзика: - **Только 3,3 В** — трансляторов уровней нет, цель должна работать от 3,3 В. - **Нет ключа питания цели** — `mon tpwr` ничего не включает; цель питается сама или от +3.3 В Щепы. - Если VTREF (PA0) не подключён к питанию цели, `Target voltage` покажет около 0 В — сканировать это не мешает. - PA13/PA14 заняты светодиодами, поэтому SWD самой Щепы недоступен — перешивать её через DFU. - PB0 прошивка переключает при работе SWD — к нему на Щепе ничего не подключайте. Подробнее — в [описании форка](https://github.com/Kits-Lab-Dev/blackmagic/blob/main/KITSLAB.md). ## Настройка VSCode Отладчик «Лобзик», полностью совместим с расширением Cortex-Debug для Visual Studio Code. Ниже приведено пошаговое руководство по настройке отладки. #### 🔧 Предварительные требования 1. Установлено расширение Cortex-Debug в VS Code. 1. Установлен GDB, соответствующий архитектуре вашей цели: 1. Для ARM Cortex-M: arm-none-eabi-gdb 1. Для RISC-V: riscv32-unknown-elf-gdb или riscv64-unknown-elf-gdb (в зависимости от ядра) 1. Прошивка «Лобзика» обновлена до актуальной версии. 1. Целевая плата подключена к «Лобзику» через SWD или JTAG, и подано питание на цель,включая сигнал VTARGET (VCC). #### 📄 Настройка launch.json Откройте папку проекта в VS Code и создайте/отредактируйте файл `.vscode/launch.json`. *Пример конфигурации для ARM Cortex-M (например, STM32):* ```c { "version": "0.2.0", "configurations": [ { "name": "Debug via Лобзик (BMP)", "type": "cortex-debug", "request": "launch", "servertype": "bmp", "BMPGDBSerialPort": "COM4", // ← замените на ваш порт (Windows) // "BMPGDBSerialPort": "/dev/ttyACM0", // ← Linux/macOS "gdbPath": "arm-none-eabi-gdb", "executable": "${workspaceFolder}/build/firmware.elf", "svdFile": "${workspaceFolder}/STM32F407.svd", "interface": "swd", } ] } ``` *Пример конфигурации для RISC-V (K1921VG015):* ```c { "name": "Debug RISC-V via Лобзик", "type": "cortex-debug", "request": "launch", "servertype": "bmp", "BMPGDBSerialPort": "COM7", // ← ваш COM-порт "gdbPath": "riscv-none-elf-gdb", "executable": "${workspaceFolder}/build/app.elf", "svdFile": "${workspaceFolder}/K1921VG015.svd", "interface": "jtag", // "powerOverBMP": "enable", // ← Питание целевого устройства от отладчика (3.3V) "overrideLaunchCommands": [ //"mon freq 1000000", // ← Частота JTAG "load" ], "overrideResetCommands": [ "mon swreset" ], "overrideRestartCommands": [ "mon swreset", "load" ] } ``` #### 💡 Примечания: Порт `BMPGDBSerialPort` можно найти в диспетчере устройств (Windows) или через ls /dev/tty* (Linux/macOS). «Лобзик» создаёт два COM-порта: первый — для GDB, второй — для UART. Команда `mon swdp_scan` (для SWD) или `mon jtag_scan` (для JTAG) необходима для обнаружения целевого ядра. `att 1` — подключается к первому обнаруженному ядру (часто `targetId: 1`). Для `K1921VG015` добавлены кастомные команды сброса `mon swreset` и `mon hwreset` и команда стирания flash-памяти `mon erase_mass`. Лобзик сам считывает состояние сервисного режима `K1921VG015` и сам выбирает метод стирания. Для стирания flash `K1921VG015` в сервисном режиме: - Подключить вывод `SERVEN` к питанию 3.3V - Подключить питание `K1921VG015` - Открыть в терминале `riscv-none-elf-gdb` - Выполнить команды: - `tar ext com2` - указать com-порт отладчика - `mon jtag` - `att 1` - `mon erase_mass` При успешном стирании должны получить `Erasing device Flash: done` #### ▶️ Запуск отладки 1. Соберите проект и убедитесь, что .elf-файл содержит отладочную информацию (-g в флагах компиляции). 1. Нажмите F5 или выберите конфигурацию в панели отладки и нажмите «Start Debugging». 1. Cortex-Debug автоматически: - Подключится к «Лобзику» через указанный COM-порт, - Выполнит команды инициализации, - Загрузит прошивку (load) #### 📚 Полезные ссылки - [Официальная документация Cortex-Debug](https://github.com/Marus/cortex-debug) - [Black Magic Debug — оригинальный проект](https://codeberg.org/blackmagic-debug/blackmagic) - [Прошивка Лобзика — форк Black Magic Debug](https://github.com/Kits-Lab-Dev/blackmagic): исходники, релизы и чем отличается от оригинала - [Навык «Лобзик» для ИИ-агентов](https://github.com/Kits-Lab-Dev/lobzik-skill) # ПО для разработки - [Cube MX](/ide/cubemx/) - [Qt Creator](/ide/qt_qbs/) - [VSCode Qbs](/ide/vscode_qbs/) # Cube MX [Cube MX](https://www.st.com/en/development-tools/stm32cubemx.html) - генератор проектов для микроконтроллеров STM32 # Qt Creator [Qt Creator](https://github.com/qt-creator/qt-creator/releases/) # VSCode Qbs > Сборка и отладка проектов STM32 в VSCode с системой сборки Qbs и STM32CubeMX: пошаговая настройка. [Qbs](https://doc.qt.io/qbs/installing.html) - это инструмент автоматизации сборки, предназначенный для удобного управления процессом сборки программных проектов на нескольких платформах. Qbs основан на языке QML. QML — это краткий, простой в освоении и интуитивно понятный язык. Его ядро ​​является декларативным, но для большей гибкости его можно расширить с помощью фрагментов JavaScript. Qbs создает приложения на основе информации из файла проекта. Каждый файл проекта определяет один проект, который может содержать несколько продуктов. Вы указываете тип продукта, например приложение, и зависимости продукта от других продуктов. Тип продукта определяет набор правил, которые Qbs применяет для создания артефактов из входных файлов. Входные файлы можно разделить на группы, например, по их типу или назначению. Группу также можно использовать для присвоения свойств продуктам. Ниже приведен пример минимального файла проекта, в котором указаны тип продукта, имя приложения, исходный файл и зависимость от модуля cpp: ```javascript Application { name: "helloworld" files: "main.cpp" Depends { name: "cpp" } } ``` [Visual Studio Code](https://code.visualstudio.com/) предоставляет плагин [qbs-community](https://marketplace.visualstudio.com/items?itemName=qbs-community.qbs-tools), который предоставляет точную информацию о ходе сборки и отображает дерево проекта, отражающее логическую структуру проекта. Кроме того, он может предоставлять информацию низкого уровня, например структуру файловой системы. Для программирования микроконтроллеров STM32 в VSCode потребуется: - [Visual Studio Code](https://code.visualstudio.com/) - [Qbs](https://doc.qt.io/qbs/installing.html) - система сборки - [qbs-community](https://marketplace.visualstudio.com/items?itemName=qbs-community.qbs-tools) расширение для VSCode для поддержки Qbs - [STM32CubeCLT](https://www.st.com/en/development-tools/stm32cubeclt.html) - инструменты для сборки (компилятор, утилита для прошивки, отладчик, GDB - сервер) - [STM32CubeMX](https://www.st.com/en/development-tools/stm32cubemx.html) - генератор проектов для STM32 - [Шаблон проекта Qbs](https://github.com/Kits-Lab-Dev/qbs-template) [Скачать Qbs, STM32CubeCLT, STM32CubeMX](https://disk.yandex.ru/d/Fjw2cZVs_fMvog) В настройках VSCode в расширение Qbs настроить путь к исполняемому файлу `qbs.exe`: Создаем проект в `Cube MX`: `File -> New Project`, выбираем микроконтроллер: Активируем нужную периферию: Настраиваем цепь тактирования: Выбираем `Makefile`в `Toolchain/IDE`: Настраиваем генератор кода: Генерируем проект нажав кнопку `GENERATE CODE`. Открываем папку со сгенерированным проектом, копируем в нее содержимое `шаблона проекта` Открываем папку проекта в `VSCode` и выбираем компилятор: Во вкладке отладки выбрать тип загрузки прошивки: При первом открытии, возможно, понадобится сборка проекта, что бы не возникала ошибка при прошивке микроконтроллера. Для сборки нужно нажать кнопку `Сборка` в нижней панели `VSCode`. При последующих запусках прошивки, сборка будет производиться автоматически. Для подключения сторонних библиотек нужно добавить в файле проекта `хxx.qbs` пути к библиотекам, например: ```javascript property stringList myIncludes:[ "lib/SSD1306", "lib/microrl" ] ``` Для добавления своих определений их нужно поместить в список: ```javascript property stringList myDefines:[ "_USE_CTLR_C" ] ``` Список `files` содержит список файлов включенных в проект: ```javascript files:[ "*.ioc", "*_FLASH.ld", "**/*.c", "**/*.cpp", "**/*.h", "**/*.hpp", "**/*startup_**.s", ] ``` Строки `**/*.cpp` рекурсивно сканируют все папки проекта, в таком случае новые файлы добавляются в проект автоматически, достаточно перезапустить чтение `*.qbs` файла Для исключения файлов из проекта их нужно внести в список `excludeFiles`, например: ```javascript excludeFiles: [ "MAKEFILE" ] ```