# STM32: общий слой ProtoCAN Boot v1 Порты [F103C8](../stm32f103/README.md), [F407VE](../stm32f407/README.md) и [G474VE](../stm32g474/README.md) подключают bxCAN/FDCAN и Flash к текущему `pcan_boot`. F103/F407 предоставляют как лёгкий CMSIS boot main для существующих проектов, так и независимый HAL-порт. G474 использует HAL FDCAN/Flash. `pcan_boot_stm32.inc` включается семейным `.c`; отдельно его компилировать не надо. Сохраните рядом каталоги `stm32-common` и нужного семейства. Reusable `pcan_boot_stm32*.c` не содержит `main` или startup. Готовые `boot_main.c` и вход из приложения находятся в семейных каталогах. Для F103/F407 общая CMSIS-реализация транспорта, callbacks и безопасного handoff — `boot_native.inc`; G474 также содержит `boot_startup.c` для исходных Keil/GCC-сборок. Тактирование платы, linker и привязка USB/CAN-приложения остаются в проектах. KONOR, climate и CANdle G474 уже подключены через свои submodule: локальные boot main/control заменены include-обёртками, состав Keil/CMake обновлён. UART использует общий `rs485-boot` с сохранением SETGUI v1 wire-протокола. [Схема подключённых проектов и проверки сборок](../../projects/STM32.md). ## Подключение reusable HAL-портов F103/F407 1. Добавьте в сборку `src/pcan_boot.c` и семейный `pcan_boot_stm32f103.c` либо `pcan_boot_stm32f407.c`; в include paths — `include`, каталог порта, CMSIS, HAL и каталог вашего `stm32f1xx_hal_conf.h` / `stm32f4xx_hal_conf.h`. 2. В HAL включите CAN, FLASH, RCC, GPIO и CORTEX. Выполните `HAL_Init`, настройте тактирование, SysTick и GPIO, вызовите `HAL_CAN_Init` для CAN1. Настройка скорости шины принадлежит проекту; исходные устройства используют 500 кбит/с. 3. Выделите CAN1, FIFO0 и банки фильтров 0/1 загрузчику. Перед вызовом init CAN должен находиться в состоянии READY, без чужих активных фильтров. Init настраивает адресный фильтр и broadcast discovery, затем вызывает `HAL_CAN_Start`. Оба приоритета ProtoCAN разрешены, standard и remote кадры отвергаются. 4. Не включайте CAN TX/RX IRQ для этого handle и не отправляйте через него кадры из других контекстов: порт использует опрос и сам читает TXOK до reset. 5. Вызывайте семейный `poll` из основного цикла только после успешного init. Стирание Flash выполняется синхронно; вызов из IRQ не допускается. 6. Linker приложения, VTOR и переход после reset должны соответствовать карте выбранного профиля. Изменение адресов требует отдельного согласования геометрии стирания, linker и host-клиента. Пример для F103; `hcan` уже инициализирован проектом: ```c #include "pcan_boot_stm32f103.h" /* Подключает HAL-порт и текущий API общего автомата. */ static pcan_boot_stm32_t updater; /* Сохраняет состояние между итерациями главного цикла. */ static bool start_updater(CAN_HandleTypeDef *hcan) /* Вызывается после настройки CAN1, clock tree, GPIO и SysTick. */ { /* Настройка идентичности прибора не зависит от аппаратной геометрии Flash. */ pcan_boot_config_t config = {0}; /* Не зависит от порядка полей расширяемого API. */ config.device_type = 7U; /* Пример: тип 7 должен совпадать с выбранным адресом в клиенте прошивки. */ config.device_id = 13U; /* Пример: номер 13 повторяет исходный адрес загрузчика KONOR. */ config.ack_window = 16U; /* Подтверждает каждые 16 CAN-блоков по восемь байт. */ config.session_timeout_ms = 30000U; /* Пример: 30 секунд без активности прерывают RAM-сессию. */ return pcan_boot_stm32f103_init(&updater, hcan, &config); /* Настраивает single-slot геометрию, фильтры 0/1 и запускает CAN. */ } /* После успеха основной цикл регулярно вызывает pcan_boot_stm32f103_poll(&updater). */ ``` Product/HW/FW в примере равны нулю; для изделия задайте их явно и согласуйте с manifest клиента. Порт сохраняет `ack_window` и `session_timeout_ms`, но сам задаёт `active_slot=0`, `slot_count=1`, `max_image_size` по физическому профилю. Конфигурацию `config` можно создавать на стеке; состояние `updater` и `hcan` должно существовать всё время работы загрузчика. ## Flash, подтверждения и reset - Запись последовательная, блоки по восемь байт; неполная аппаратная единица допустима только в конце образа и дополняется `FF`. CRC учитывает полезную длину. - HAL-ошибки и readback каждого слова проверяются; после erase/program Flash снова блокируется, включая обработанные отказы. На F407 перед readback вызывается `FLASH_FlushCaches`, чтобы соседние записанные слова не читались из устаревшей строки Flash-кэша; состояние включения кэшей сохраняется HAL. - VERIFY перечитывает Flash, сравнивает её CRC и проверяет MSP/Thumb reset vector. Точка входа должна принадлежать фактическому образу, MSP — основной SRAM, с выравниванием восемь байт. CCM F407 в данном профиле для стека не используется. - COMMIT повторно проверяет образ и устанавливает признак в RAM. REBOOT разрешён только в состоянии COMMITTED. Ответ перед reset должен завершиться с TXOK; отсутствие mailbox, ошибка шины или тайм-аут 100 мс не вызывают reset. Для этого HAL tick должен работать при ожидании TX. - BUSY перед стиранием, между секторами F407 и после erase сохраняет активность сессии. На однобанковой Flash код не исполняется во время аппаратного стирания; непрерывные ответы в этот интервал не гарантируются. Настройте тайм-аут клиента больше максимального времени стирания одной аппаратной операции. ## Запуск приложения и потеря питания Порт не меняет Option Bytes, защиту секторов и VDD; F407 требует 2,7..3,6 В для программирования x32. Переход из работающего приложения в загрузчик, backup/SRAM-флаг запроса, отключение периферии и безопасная замена MSP остаются в `main` и startup устройства. `*_vectors_valid()` проверяет только векторы и диапазоны. После внешнего reset этого недостаточно для доказательства целостности образа: RAM-признак COMMIT потерян, а частично записанное приложение уже может иметь корректные векторы. Эти профили сохраняют исходную single-slot модель без постоянных метаданных, rollback, resume после питания и аутентификации. Для защищённого запуска проекту нужен отдельный постоянный manifest с полной проверкой образа. ## Проверка `python tests/run_tests.py` из корня `protocan-boot` запускает три production-порта с моделью HAL и Flash, наряду с существующими проверками ядра и TI-портов. Можно также использовать обычные CMake/CTest: цели `test_stm32f103`, `test_stm32f407`, `test_stm32g474` работают на Windows и POSIX. Проверяются все хвосты CAN-блока, полный ERASE/DATA/VERIFY/COMMIT/REBOOT, повреждение readback, отказы HAL/TX, фильтрация RX и сохранность памяти перед приложением и за верхней границей; для G474 проверяются оба DBANK-режима, переход между банками, запрет swap, ёмкость Flash и старое shifted-DLC HAL. Эти тесты не заменяют проверку на реальной плате с её linker, питанием, трансивером и SysTick.