Высокопроизводительная модульная прошивка для 3D-принтера на ESP32-S3-N16R8,
написанная на Rust поверх стека ESP-IDF (esp-idf-sys / esp-idf-hal /
esp-idf-svc + FreeRTOS). esp-hal не используется.
Все 11 этапов реализованы. Прошивка компилируется (по построению, см.
оговорку о верификации ниже) в единое целое: App инициализирует плату,
собирает реальные драйверы моторов (Tmc2209Driver X/Y, Uln2003Driver Z)
из пинов Board, контуры температуры (термисторы на ADC1, нагреватели и
вентилятор на ШИМ через LEDC), планировщик движения и G-Code исполнитель
поверх USB CDC — и запускает главный цикл.
| Файл | Содержимое |
|---|---|
src/hal_adapters.rs |
EspAdcThermistor (классический драйвер adc1_*), EspLedcPwm (безопасная обёртка esp_idf_hal::ledc) — единственное место, где абстрактные трейты подсистем встречаются с конкретным железом |
src/hardware_build.rs |
build_printer_state/build_axes/build_temperature_controller/build_endstop_set — собирает Tmc2209Driver/Uln2003Driver/Heater/Fan/EndstopSet из пинов Board и конфигурации |
src/printer_state.rs |
PrinterState — конкретная реализация PrinterContext: маршрутизация к MotionPlanner/TemperatureController/SettingsManager, хоуминг, блокирующее ожидание температуры |
src/app.rs |
App — жизненный цикл прошивки и главный кооперативный цикл (USB G-Code → прокачка движения → регулирование температуры → watchdog/E-Stop) |
- Главный цикл — однопоточный и кооперативный, сознательно. Все
примитивы для полноценной многозадачности уже написаны и протестированы
(
scheduler::Task/TaskPriority,network::*,sdcard::PrintJob), но для первой интегрированной версии выбрана простая, предсказуемая и проверяемая схема: один поток обрабатывает USB, прокачивает очередь движения и регулирует температуру по очереди. Перенос на отдельные задачи FreeRTOS (TaskPriority::StepGeneratorдля генератора шагов,TaskPriority::GCodeдля приёма USB) — это последующее расширение, которое не потребует изменений вPrinterState/GcodeExecutor, только вApp::run. Board::init()вызывается ровно один раз и сразу разбирается на части:power/watchdog/rgbостаются уAppнапрямую для главного цикла, аpins/uart1/uart2/ledcуходят вbuild_printer_state. Попытка вызватьBoard::init()дважды была бы ошибкой (Peripherals::take()— не более одного раза за время жизни программы) — этот момент был сознательно проверен при проектированииApp::new().- SD-карта и сеть — не вписаны в главный цикл этой сборки.
sdcard/networkполностью реализованы, протестированы на хосте и готовы к подключению, но их проводка (SPI-шина уже частично занята SD-картой по распиновке, Wi-Fi требуетEspSystemEventLoop+раздел NVS, HTTP/WebSocket — отдельные задачи) — это следующий, самостоятельный шаг расширенияApp, а не часть этой финальной сборки, ограниченной базовым циклом печати через USB. - Резервный ток TMC2209 (800 мА / 300 мА) — разумное значение по
умолчанию, не из конфигурации.
motion.toml(этап 1) не содержит отдельного поля тока на ось; жёстко заданное вhardware_build.rsзначение подходит для типового NEMA17, но должно стать частьюAxisMotionConfigв одной из последующих итераций, если потребуется тонкая настройка под конкретные двигатели.
Прошивка написана и вычитана вручную по документации и памяти о реальных
сигнатурах esp-idf-hal/esp-idf-svc/esp-idf-sys для версий, указанных
в .cargo/config.toml (ESP_IDF_VERSION = v5.2.1) и Cargo.toml. В
песочнице, где эта прошивка была написана, нет ни сети, ни установленного
Xtensa-тулчейна ESP-IDF, поэтому ни разу не был выполнен реальный
cargo build для целевой платформы. Каждый файл спроектирован так,
чтобы бизнес-логика (планировщик, кинематика, ПИД, парсер G-Code,
интерполяция шагов, протокол USB) была полностью безопасна и покрыта
хостовыми unit-тестами независимо от конкретных HAL-обёрток — но сама
проводка конкретного железа в hardware_build.rs/hal_adapters.rs
(в первую очередь ADC1, LEDC, UART, SPI, TinyUSB, SDSPI, SPIFFS) должна
быть проверена первой реальной сборкой (cargo build --release, см.
раздел «Сборка» ниже) — несовпадения в именах полей/функций сгенерированных
bindgen-биндингов между версиями esp-idf-sys являются наиболее вероятным
источником ошибок компиляции, и они будут точечными (компилятор укажет на
конкретное поле/функцию), а не системными.
| Модуль | Готовность | Что нужно для подключения |
|---|---|---|
src/scheduler/* |
Полностью реализован и протестирован | Заменить App::run's кооперативный цикл на отдельные Task::spawn с TaskPriority |
src/sdcard/* |
Полностью реализован и протестирован | Отдельная инициализация SPI-шины SD-карты, вызов PrintJob::next_command() вместо/вместе с USB в главном цикле |
src/network/* |
Полностью реализован и протестирован | EspSystemEventLoop, раздел NVS, отдельные задачи для HTTP/WebSocket |
| Модуль | Содержимое |
|---|---|
Cargo.toml, build.rs, .cargo/config.toml, rust-toolchain.toml |
Сборочная конфигурация под xtensa-esp32s3-espidf |
sdkconfig.defaults, partitions.csv |
PSRAM (Octal, 8 MB), Flash 16 MB, TWDT, Wi-Fi, USB CDC, FATFS, settings (SPIFFS), ota_0/ota_1 |
src/error.rs, src/types.rs |
Единый AppError, общие типы |
src/board/* |
Распиновка (включая термисторы/нагреватели/вентилятор), питание/E-Stop, Task Watchdog, статусный WS2812 |
src/config/* |
printer.toml/motion.toml/network.toml/temperature.toml |
src/drivers/motor/* |
MotorDriver, Axis/AxisControl, Tmc2209Driver, Uln2003Driver |
src/motion/* |
Kinematics, MotionPlanner (look-ahead), TrapezoidProfile, StepGenerator |
src/scheduler/* |
Task (приоритеты FreeRTOS), PeriodicTimer |
src/gcode/*, src/endstops/* |
Парсер, PrinterContext, все команды из ТЗ, концевики |
src/temperature/* |
Термистор, ПИД с автонастройкой, Heater с thermal runaway, Fan |
src/storage/* |
SettingsManager — M500/M501 |
src/sdcard/* |
SdCard, PrintJob — печать с карты памяти |
src/usb/* |
SerialConsole — протокол ok/Error: ... поверх USB CDC |
src/network/* |
WifiManager, HttpApiServer, TelemetryBroadcaster, OtaUpdater |
src/system/* |
CPU/память, паника, причина сброса |
src/hal_adapters.rs, src/hardware_build.rs, src/printer_state.rs, src/app.rs |
Финальная сборка: конкретное железо → PrinterState → главный цикл |
- Абстракция от распиновки. Все номера GPIO собраны в
board::pins::PinMap. Драйверы (следующий этап) получают уже сконфигурированные периферийные объекты, а не читают номера пинов напрямую — замена платы не потребует правок в логике. unsafeизолирован. Единственные места сunsafe:board/watchdog.rs(прямые вызовыesp_task_wdt_*, которых нет в безопасных обёрткахesp-idf-hal/esp-idf-svc) и создание GPIO-пинов по номеру вboard/mod.rs(AnyOutputPin::new/AnyIOPin::new— сознательно небезопасная операция самогоesp-idf-hal, обходящая систему владенияPeripherals, чтобы не тащить вBoardдесятки индивидуально типизированных полей GPIO). Остальной код — safe Rust.- Периферия резервируется заранее.
Peripherals::take()вызывается ровно один раз, вBoard::init(). Ещё не задействованные ресурсы (UART1,UART2,SPI2— под TMC2209 и SD-карту) сохраняются как публичные поляBoard, чтобы модулиdriversиstorageна следующих этапах могли их получить, не переписывая инициализацию платы. - Конфигурация не знает про хранилище.
config::AppConfigумеет парситься из TOML-строк и сериализоваться обратно, но не знает, откуда берутся эти строки (SD-карта, NVS, SPIFFS-разделsettings) — это подключит модульstorageбез измененияconfig.
В текущей среде генерации кода недоступны сеть и установленный Xtensa-toolchain
ESP-IDF, поэтому запустить cargo build --release для реальной цели
xtensa-esp32s3-espidf здесь невозможно — код написан и вычитан вручную с
учётом актуальных сигнатур esp-idf-hal 0.44 / esp-idf-svc 0.49, но
перед прошивкой в железо обязательно выполните первую сборку локально
(см. ниже) и сообщите, если компилятор укажет на несоответствие версий API —
это будет исправлено в следующей итерации.
Требуется установленный espup (тулчейн
Xtensa Rust) и ldproxy/espflash:
espup install
. $HOME/export-esp.sh
cargo install ldproxy espflash
cd printer-fw
cargo build --release
cargo espflash flash --release --monitorПервая сборка вызовет embuild, который скачает и соберёт сам ESP-IDF
(версия закреплена в .cargo/config.toml, ESP_IDF_VERSION = "v5.2.1") —
это может занять продолжительное время.
Каркас проекта, board support, конфигурация✅ (этот коммит)- Абстракция
MotorDriver+ драйверыTmc2209DriverиUln2003Driver(регистры TMC2209 отдельными структурами, UART-протокол, микрошаг/ток/ StealthChop/SpreadCycle/CoolStep/StallGuard) motion: планировщик, очередь, ускорение/торможение, jerk, junction deviation, look-ahead, генератор шагов; кинематика Cartesiangcode: парсер и исполнитель (G0/G1/G4/G28/G90/G91/G92, M17/M18, M104/M105/M106/M107/M109/M114/M115/M119/M140/M190/M500/M501)temperature: термисторы, PID, thermal runaway, автонастройка PIDstorage: персистентные настройки (SPIFFS-разделsettings)sdcard: SPI + FAT32, печать с картыusb: CDC Serialnetwork: Wi-Fi, HTTP API, WebSocket, OTAsystem: диагностика CPU/памяти, обработчик паники, управление сбросом
Каждый этап будет содержать дерево проекта, полный код новых файлов и описание того, как он стыкуется с уже написанными модулями.