308 lines
17 KiB
Markdown
308 lines
17 KiB
Markdown
# Новый проект на переносимых библиотеках
|
||
|
||
Этот репозиторий содержит два разных типа кода:
|
||
|
||
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
|
||
```
|