Files
templates/NEW_PROJECT.md

308 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Новый проект на переносимых библиотеках
Этот репозиторий содержит два разных типа кода:
1. `c/<library>/include` и `c/<library>/src` — переносимое ядро;
2. `c/<library>/ports/<family>` — небольшой аппаратный порт конкретного
семейства микроконтроллеров.
Привязка выводов, частоты шин и выбранной периферии принадлежит плате и всегда
остаётся в проекте в `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/<family>/onewire_<family>.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 <url-основного-проекта>
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/<имя> <sha-одной-стороны>
git -C lib/templates merge <sha-другой-стороны>
# исправить конфликты и запустить тесты 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
```