# Новый проект на переносимых библиотеках Этот репозиторий содержит два разных типа кода: 1. `c//include` и `c//src` — переносимое ядро; 2. `c//ports/` — небольшой аппаратный порт конкретного семейства микроконтроллеров. Привязка выводов, частоты шин и выбранной периферии принадлежит плате и всегда остаётся в проекте в `app_config.h` либо в узком конфигурационном заголовке библиотеки, например `onewire_config.h`. ## Рекомендуемая структура прошивки ```text my-device/ app/ логика изделия include/ src/ board/ одна конкретная плата app_config.h выводы, частоты, адреса, возможности платы port/ связь библиотек с SDK выбранного МК display_port.c keypad_port.c eeprom_port.c can_port.c vendor/ CMSIS, startup, linker script или Cube-generated код lib/templates/ git submodule этого репозитория ``` Не следует помещать `stm32xxxx.h`, `HAL_*`, регистры, IRQ handlers и номера выводов в `app/` или в ядро библиотеки. Тогда при переходе на другой МК заменяются только `board/`, `port/`, startup и linker script. ## Выбор готового порта DS18B20 | Целевой МК | Файл порта | Шаблон конфигурации | |---|---|---| | STM32F103 | `c/ds18b20/ports/stm32f1/onewire_stm32f1.c` | `onewire_config.f103.template.h` | | STM32G431 | `c/ds18b20/ports/stm32g4/onewire_stm32g4.c` | `onewire_config.g431.template.h` | | STM32G474 | `c/ds18b20/ports/stm32g4/onewire_stm32g4.c` | `onewire_config.g474.template.h` | В сборку добавляются ровно три файла: ```text c/ds18b20/src/onewire.c c/ds18b20/src/ds18b20.c c/ds18b20/ports//onewire_.c ``` Пути включения: ```text c/ds18b20/include board ``` Нужный шаблон копируется в `board/onewire_config.h`; после этого в нём меняются только порт, номер вывода и бит тактирования GPIO. G431 и G474 намеренно используют один исходник порта: GPIO, RCC и DWT для этой задачи совместимы. Раздельными остаются конфигурация платы, startup, linker script и выбранный CMSIS device define. ## Выбор готового порта parallel NAND | Целевой МК | Реализация шины | Каталог порта | |---|---|---| | TMS320F2812 | XINTF Zone 6 | `c/parallel-nand/ports/tms320f2812` | | STM32F103RCT6 | GPIO bit-bang, поскольку FSMC недоступен в LQFP64 | `c/parallel-nand/ports/stm32f103rc` | | STM32F103ZET6 | FSMC NAND Bank 3 | `c/parallel-nand/ports/stm32f103ze` | | STM32F407VET6 | FSMC NAND Bank 2 | `c/parallel-nand/ports/stm32f407ve` | | STM32G474CEU6 | GPIO bit-bang для UFQFPN48 | `c/parallel-nand/ports/stm32g474ce` | Ядро поддерживает профили Micron `MT29F1G08ABADA` и Hynix `HY27UF084G2M`. В сборку добавляются `src/parallel_nand.c`, при необходимости `src/parallel_nand_gas.c` или `src/parallel_nand_pcan_gas.c`, и ровно один аппаратный порт. Конкретная распиновка, требуемые модули HAL и пример инициализации приведены в README выбранного порта. Для `PROGRAM`/`ERASE` линия `WP#` должна управляться портом. Готовые порты STM32F103RC, STM32F103ZE и STM32G474CE объявляют поддержку записи. Базовые схемы TMS320F2812 и STM32F407VE фиксируют `WP#` аппаратно и безопасно возвращают `PNAND_ERROR_WRITE_PROTECTED`, пока плата и порт не доработаны. Рабочий пример полноценного G474-порта находится в соседнем проекте `candleLight_fw`: `src/device/device_g4.c` отвечает за clock/GPIO, `src/can/m_can.c` — за FDCAN, а `include/config.h` — за привязку платы STM32G474VET6. Эти файлы остаются в прошивке, поскольку зависят от STM32 HAL, USB gs_usb и конкретной разводки адаптера; переносимая логика протоколов остаётся в `templates`. ## Какие части KONOR уже общие | Возможность | Переносимое ядро | Что остаётся в `port/` проекта | |---|---|---| | DS18B20/1-Wire | `c/ds18b20` | готовый порт выбранного семейства и вывод | | дисплей ST7789 | `c/st7789` | SPI, DC, CS, RESET, подсветка и задержка | | кнопки | `c/keypad` | настройка GPIO и чтение уровней | | меню | `c/menu` | только привязка painter к дисплею | | индикация состояний | `c/led-indicator` | готовый STM32 HAL-порт или callbacks GPIO и выбранного таймера | | EEPROM FT24C256 | `c/eeprom-ft24c256` | I2C write/write-read и задержка | | CAN SETTINGS | `c/can-sensor` | bxCAN для F103 либо FDCAN для G431/G474 | Порт дисплея, EEPROM и CAN нельзя честно сделать только по названию МК: нужно знать экземпляр периферии, альтернативную функцию и выводы конкретной платы. Поэтому библиотеки принимают таблицы обратных вызовов, а короткие адаптеры лежат в проекте рядом с `app_config.h`. ## Порядок создания проекта 1. Создать проект в CubeMX/Keil либо добавить CMSIS, startup и linker script. 2. Подключить `templates` сабмодулем. 3. Добавить только ядра нужных библиотек. 4. Выбрать готовый 1-Wire порт по таблице выше. 5. Создать `board/app_config.h` с выводами и частотами. 6. Реализовать короткие адаптеры SPI/GPIO/I2C/CAN в `port/`. 7. Сначала прогнать host-тесты библиотек, затем проверить аппаратные порты логическим анализатором или осциллографом. Так новый проект не является копией старого: он использует общие ядра одной версии, а аппаратные отличия видны в одном небольшом каталоге `port/`. ## Слияние и обновление `templates` как Git submodule ### Что именно хранит основной проект Основной проект не хранит содержимое `lib/templates` в своей истории. Вместо этого он хранит **gitlink** — ссылку на один конкретный commit репозитория `templates`. Поэтому при работе есть два независимых уровня истории: 1. изменения библиотек сливаются и публикуются в репозитории `templates`; 2. основной проект отдельным коммитом переводит gitlink на проверенную ревизию `templates`. Обычный `git merge` в основном проекте не переносит исходники между ветками `templates` и не создаёт merge-коммит внутри сабмодуля. Он может только выбрать одну из уже существующих ссылок на commit. Если ссылки разошлись, сначала нужно получить общий commit в самом `templates`, а затем зафиксировать его в основном проекте. Текущую зафиксированную ревизию удобно смотреть из корня основного проекта: ```bash git submodule status lib/templates git diff --submodule=log ``` Символ `-` перед SHA в `git submodule status` означает, что сабмодуль ещё не инициализирован; `+` — что рабочая копия сабмодуля находится не на том commit, который записан в основном проекте; `U` — конфликт gitlink. ### Клонирование проекта и переключение его веток Новый клон лучше сразу создавать вместе с сабмодулями: ```bash git clone --recurse-submodules cd <основной-проект> ``` Если проект уже клонирован: ```bash git submodule update --init --recursive ``` После `git switch`, `git checkout`, `git pull` или завершения слияния основной проект может начать ссылаться на другую ревизию `templates`. Рабочее дерево сабмодуля следует явно привести к записанному состоянию: ```bash git submodule update --init --recursive ``` Это нормальный и воспроизводимый режим: внутри `lib/templates` обычно будет detached HEAD, потому что проект фиксирует commit, а не ветку. Не следует делать там `git pull`, пока не выбрана рабочая ветка и не понятно, какую ревизию должен получить основной проект. ### Обычное обновление проекта на новую версию `templates` Сначала изменение должно быть проверено, закоммичено, отправлено и слито в целевую ветку самого репозитория `templates`. После этого из корня основного проекта выполняется: ```bash git -C lib/templates fetch origin git -C lib/templates switch --detach origin/master git add lib/templates git diff --cached --submodule=log git commit -m "build(templates): обновить общие библиотеки" ``` Перед коммитом нужно собрать основной проект и прогнать его тесты: успешные тесты в `templates` подтверждают работу библиотеки, но не проверяют конкретный порт, настройки платы и интеграцию приложения. Коммит основного проекта содержит только переход со старого SHA сабмодуля на новый. Случайные незакоммиченные файлы внутри `lib/templates` в него не входят. Проверить оба уровня перед фиксацией можно так: ```bash git status git -C lib/templates status git diff --submodule=log ``` Не нужно обновлять сабмодуль на последний `master` автоматически при каждой сборке. Зафиксированный SHA нужен именно для того, чтобы одна и та же версия проекта всегда собиралась с одной и той же версией библиотек. ### Если библиотеку правят из рабочего дерева основного проекта Нельзя коммитить изменение, оставаясь на detached HEAD: такой commit легко потерять при следующем `git submodule update`. Сначала внутри сабмодуля создаётся обычная ветка: ```bash git -C lib/templates fetch origin git -C lib/templates switch -c feat/<имя> origin/master ``` Затем изменения коммитятся и отправляются именно в репозиторий `templates`: ```bash git -C lib/templates add <файлы> git -C lib/templates commit -m "feat(<библиотека>): <описание>" git -C lib/templates push -u origin feat/<имя> ``` После проверки ветка сливается в `master` репозитория `templates`. Только после публикации итогового commit основной проект обновляет свой gitlink по процедуре из предыдущего раздела. Не следует отправлять в общий основной проект ссылку на commit сабмодуля, которого ещё нет на сервере: остальные разработчики и CI не смогут его получить. ### Что происходит при слиянии веток основного проекта Возможны три ситуации: 1. Gitlink изменён только в одной ветке. Git обычно принимает эту ревизию автоматически. После merge нужно выполнить `git submodule update` и тесты. 2. Обе ветки указывают на разные commits, но один commit `templates` является предком другого. Следует выбрать более новый проверенный commit, выполнить `git add lib/templates` и продолжить merge. 3. Обе ветки указывают на расходящиеся commits `templates`. Это настоящий конфликт истории сабмодуля: выбирать один SHA наугад нельзя, потому что так потеряются изменения второй ветки. При конфликте сначала смотрят, какие ссылки пришли с обеих сторон: ```bash git ls-files -u lib/templates git -C lib/templates fetch origin git -C lib/templates log --oneline --graph --decorate --all ``` Затем в отдельной ветке **репозитория `templates`** объединяют оба commit, устраняют конфликты исходников, запускают тесты и публикуют результат: ```bash git -C lib/templates switch -c merge/<имя> git -C lib/templates merge # исправить конфликты и запустить тесты templates git -C lib/templates add <исправленные-файлы> git -C lib/templates commit git -C lib/templates push -u origin merge/<имя> ``` Если общий merge-коммит уже существует в `origin/master`, создавать ещё один не нужно: достаточно выбрать существующий SHA. После получения итогового commit конфликт завершается на уровне основного проекта: ```bash git -C lib/templates switch --detach <итоговый-sha> git add lib/templates git diff --cached --submodule=log git merge --continue git submodule update --init --recursive ``` `git add lib/templates` здесь отмечает разрешённым именно gitlink. Не нужно удалять каталог, копировать библиотеку поверх него или разрешать конфликт как обычный текстовый файл. ### Что должно попасть в merge request основного проекта Перед отправкой результата следует проверить: 1. итоговый commit `templates` доступен в удалённом репозитории; 2. `git -C lib/templates status` не показывает локальных изменений; 3. `git submodule status` не начинается с `+`, `-` или `U`; 4. `git diff --submodule=log <целевая-ветка>...HEAD` показывает ожидаемый набор commits библиотек; 5. тесты `templates`, сборка основного проекта и проверки на целевой плате прошли; 6. в основном проекте закоммичены необходимые изменения адаптеров, конфигурации и сам новый gitlink. После получения ветки другой разработчик восстанавливает ровно выбранное состояние одной командой: ```bash git pull git submodule update --init --recursive ```