# Update documentation

This commit is contained in:
Dmitry Akimov 2026-05-14 00:04:36 +03:00
parent a9a207ab6c
commit be36d56170
11 changed files with 647 additions and 46 deletions

View file

@ -38,16 +38,26 @@
**Host-тесты** запускаются в devcontainer без железа. BSP-модули тестируются через fff-фейки и stub-хедеры. **Host-тесты** запускаются в devcontainer без железа. BSP-модули тестируются через fff-фейки и stub-хедеры.
**HIL-тесты** — каждый тест это пара: C-прошивка с UART CLI (`tests/target/<n>/`) и pytest-файл (`tools/hil/test_<n>.py`). pyOCD загружает ELF в RAM через MCU-Link. Тесты с внешними сигналами управляются через M5StampPLC (реле → оптовходы таргета). **HIL-тесты** — каждый тест это пара: C-прошивка с UART CLI (`tests/target/<n>/`) и pytest-файл (`tools/hil/NN_test_<n>.py`). pyOCD загружает ELF в RAM через MCU-Link. Тесты с внешними сигналами управляются через M5StampPLC (реле → оптовходы таргета).
Фактический набор HIL-тестов (`tools/hil/`):
| Файл | Назначение |
| -------------------- | ----------------------------------------- |
| `01_test_uart.py` | UART CLI / MCU-Link VCOM |
| `02_test_opto.py` | Оптовходы EXT_IN1, EXT_IN2, RS_RX |
| `03_test_can.py` | CAN-интерфейс |
| `04_test_button.py` | Пользовательские кнопки |
| `05_test_usb_cdc.py` | USB CDC ACM |
```bash ```bash
pytest → uart_cmd() → MCU-Link VCOM → RT1052 pytest → uart_cmd() → MCU-Link VCOM → RT1052
pytest → m5.opto_set() → M5StampPLC RLY → EXT_IN1/IN2/RS_RX → RT1052 pytest → m5.opto_set() → M5StampPLC RLY → EXT_IN1/IN2/RS_RX → RT1052
``` ```
- Как добавить host-тест — [tests/HOST_CREATE_TEST.md](tests/HOST_CREATE_TEST.md) - Как добавить host-тест — [docs/testing/host/HOST_CREATE_TEST.md](docs/testing/host/HOST_CREATE_TEST.md)
- Как добавить HIL-тест — [docs/testing/hil/HIL_CREATE_TEST.md](docs/testing/hil/HIL_CREATE_TEST.md) - Как добавить HIL-тест — [docs/testing/hil/HIL_CREATE_TEST.md](docs/testing/hil/HIL_CREATE_TEST.md)
- Как запустить HIL-тесты — [docs/testing/hil/HIL_HOWTO.md](docs/testing/hil/HIL_HOWTO.md) - Как запустить HIL-тесты — [docs/testing/hil/HIL_HOW_TO.md](docs/testing/hil/HIL_HOW_TO.md)
- HIL стенд и подключение — [docs/testing/hil/HIL_BENCH.md](docs/testing/hil/HIL_BENCH.md) - HIL стенд и подключение — [docs/testing/hil/HIL_BENCH.md](docs/testing/hil/HIL_BENCH.md)
--- ---

View file

@ -47,7 +47,13 @@ bsp/
├── uart_host/ # bsp_uart_host — LPUART1 (MCU-Link VCOM, J2) ├── uart_host/ # bsp_uart_host — LPUART1 (MCU-Link VCOM, J2)
│ └── mocks/ # fff-заглушки для host-тестов │ └── mocks/ # fff-заглушки для host-тестов
├── opto/ # bsp_opto — оптоизолированные входы PS2801-4 ├── opto/ # bsp_opto — оптоизолированные входы PS2801-4
└── usb_cdc/ # bsp_usb_cdc — USB CDC ACM ├── can/ # bsp_can — FlexCAN2 (трансивер SN65HVD230D)
├── button/ # bsp_button — тактовые кнопки SWT6x6 с debounce
├── display/ # bsp_display — TFT-дисплей
├── usb_cdc/ # bsp_usb_cdc — USB CDC ACM
├── sdram/ # bsp_sdram — внешний SDRAM через SEMC
├── qspi_flash/ # bsp_qspi_flash — QSPI Flash W25Q64/128/256/512
└── sd/ # bsp_sd — SD host-контроллер (USDHC1)
``` ```
--- ---
@ -87,7 +93,13 @@ target_link_libraries(test_hil_opto PRIVATE bsp_board bsp_boot_ram ...)
| `bsp_tick` | `tick/` | [tick/README.md](tick/README.md) | | `bsp_tick` | `tick/` | [tick/README.md](tick/README.md) |
| `bsp_uart_host` | `uart_host/` | [uart_host/README.md](uart_host/README.md) | | `bsp_uart_host` | `uart_host/` | [uart_host/README.md](uart_host/README.md) |
| `bsp_opto` | `opto/` | [opto/README.md](opto/README.md) | | `bsp_opto` | `opto/` | [opto/README.md](opto/README.md) |
| `bsp_can` | `can/` | [can/README.md](can/README.md) |
| `bsp_button` | `button/` | [button/README.md](button/README.md) |
| `bsp_display` | `display/` | [display/README.md](display/README.md) |
| `bsp_usb_cdc` | `usb_cdc/` | [usb_cdc/README.md](usb_cdc/README.md) | | `bsp_usb_cdc` | `usb_cdc/` | [usb_cdc/README.md](usb_cdc/README.md) |
| `bsp_sdram` | `sdram/` | [sdram/README.md](sdram/README.md) |
| `bsp_qspi_flash` | `qspi_flash/` | [qspi_flash/README.md](qspi_flash/README.md) |
| `bsp_sd` | `sd/` | [sd/README.md](sd/README.md) |
--- ---

View file

@ -0,0 +1,328 @@
# bsp_display — ELCDIF RGB-дисплей (TFT4 / TFT7 / TFT8 / TFT10)
> Расположение: `bsp/display/`
> Публичный заголовок: `bsp/display/include/bsp/display.h`
> Реализация: `bsp/display/src/display.c`
Модуль инициализирует ELCDIF в RGB-режиме, настраивает пиксельный клок,
управляет GPIO подсветки и пинами ориентации/режима LR, UD, MODE, DITHB.
Предоставляет минимальное API для смены фреймбуфера, поворота и оповещения
о завершении кадра через callback. Bare-metal совместим (без FreeRTOS).
---
## Аппаратный контекст
| Сигнал / параметр | Аппаратное назначение |
| ----------------- | ---------------------------------------------------------------- |
| ELCDIF | NXP ELCDIF, RGB-режим, формат пикселя `kELCDIF_PixelFormatXRGB8888`, шина `kELCDIF_DataBus24Bit` |
| Подсветка | `GPIO1[20]` — active-high |
| LR (горизонт.) | `GPIO1[28]` (`Lcdlr_value`) |
| MODE | `GPIO1[29]` — HIGH = DE mode (обязательно для ELCDIF) |
| UD (вертикаль) | `GPIO1[30]` |
| DITHB | `GPIO1[31]` — HIGH = dithering disable (IC default) |
| Пиксельный клок | PLL2 (`mux=0`) для TFT7/TFT8; Video PLL (`mux=2`) для TFT4 |
| IRQ | `LCDIF_IRQHandler` в ITCM, приоритет `DISPLAY_IRQ_PRIORITY = 2` |
`IOMUXC` конфигурируется в `BOARD_InitPins()` за пределами модуля — здесь
выполняется только `GPIO_PinWrite`.
Делители пиксельного клока (исходный код, PLL2 = 528 МГц):
| Дисплей | clk_mux | pre_div | div | Эффективная частота |
| ------- | ------------- | ------- | --- | ------------------- |
| TFT7 | PLL2 | 2 | 4 | `528/3/5 = 35.2 МГц`|
| TFT8 | PLL2 | 2 | 3 | `528/3/4 = 44.0 МГц`|
| TFT4 | Video PLL | — (TODO)| — | требует `CLOCK_InitVideoPll` |
| TFT10 | — | — | — | таблица не заполнена (`{ 0 }`) |
Тайминги HSW/HFP/HBP/VSW/VFP/VBP заданы константами в `display.c`
(`DISPLAY_TFT7_*`, `DISPLAY_TFT8_*`, `DISPLAY_TFT4_*`).
---
## Состав модуля
```
bsp/display/
├── include/bsp/display.h # публичный заголовок
├── src/display.c # реализация API + LCDIF_IRQHandler
└── CMakeLists.txt # цель bsp_display
```
`LCDIF_IRQHandler` размещён в ITCM (`AT_QUICKACCESS_SECTION_CODE`) и только
вызывает зарегистрированный callback; состояние модуля он не модифицирует.
---
## Публичные типы
```c
typedef enum bsp_display_type_e {
BSP_DISPLAY_TFT4 = 0U, /* 480 × 272, нет ножек ориентации/MODE/DITHB */
BSP_DISPLAY_TFT7, /* 1024 × 600, LR + UD + MODE + DITHB */
BSP_DISPLAY_TFT8, /* 800 × 600, LR + UD + MODE + DITHB */
BSP_DISPLAY_TFT10, /* зарезервировано, спецификации уточняются */
BSP_DISPLAY_COUNT,
} bsp_display_type_t;
typedef enum bsp_display_rotation_e {
BSP_DISPLAY_ROTATE_0 = 0U, /* LR=1 UD=0 */
BSP_DISPLAY_ROTATE_90, /* LR=1 UD=1 */
BSP_DISPLAY_ROTATE_180, /* LR=0 UD=1 */
BSP_DISPLAY_ROTATE_270, /* LR=0 UD=0 */
} bsp_display_rotation_t;
typedef struct bsp_display_size_s {
uint16_t width;
uint16_t height;
} bsp_display_size_t;
typedef void (*bsp_display_frame_cb_t)(void); /* ISR-safe */
```
Размеры максимального дисплея (для статического выделения буферов):
```c
#define BSP_DISPLAY_MAX_WIDTH 1024U
#define BSP_DISPLAY_MAX_HEIGHT 600U
```
---
## Публичный API
```c
bsp_status_t bsp_display_init(bsp_display_type_t type,
uint32_t framebuffer_addr,
bsp_display_frame_cb_t p_on_frame_done);
bsp_status_t bsp_display_deinit(void);
bsp_status_t bsp_display_set_rotation(bsp_display_rotation_t rotation);
void bsp_display_set_next_buffer(uint32_t framebuffer_addr);
const bsp_display_size_t *bsp_display_get_size(void);
bsp_display_type_t bsp_display_get_type(void);
```
### `bsp_display_init`
Настраивает пиксельный клок (через `CLOCK_SetMux` / `CLOCK_SetDiv`), включает
`kCLOCK_LcdPixel`, поднимает подсветку, для TFT7/TFT8 инициализирует ножки
ориентации (`ROTATE_0`: LR=1, UD=0) и режима (MODE=1: DE-mode, DITHB=1),
конфигурирует ELCDIF через `ELCDIF_RgbModeInit` и запускает его через
`ELCDIF_RgbModeStart`. Включает прерывание `kELCDIF_CurFrameDoneInterruptEnable`
с приоритетом `DISPLAY_IRQ_PRIORITY = 2`.
Требования к аргументам и поведение:
- `framebuffer_addr` — физический адрес первого фреймбуфера. Согласно
заголовку, ожидается выравнивание по 64 байтам и размещение в NonCacheable
SDRAM. (Само значение модуль не проверяет — это контракт потребителя.)
- `p_on_frame_done` — ISR-safe callback; `NULL` означает «без callback».
Сохраняется до включения IRQ, чтобы избежать гонки.
- Повторный вызов без `bsp_display_deinit()` — идемпотентен, возвращает
`BSP_OK` без побочных эффектов.
Коды возврата:
| Код | Когда |
| ---------------------- | ----------------------------------------------------------- |
| `BSP_OK` | Дисплей инициализирован (или уже был инициализирован). |
| `BSP_ERR_PARAM` | `type >= BSP_DISPLAY_COUNT`. |
| `BSP_ERR_NOT_SUPPORTED`| `type` требует Video PLL (TFT4) — `init_pixelclock` возвращает ошибку до реализации `CLOCK_InitVideoPll`. |
> Поведение для `BSP_DISPLAY_TFT10` целостно не описано в коде: запись в
> `K_HW_CFG[BSP_DISPLAY_TFT10]` сделана как `{ 0 }`. Использовать TFT10 как
> рабочий параметр сейчас не гарантируется — типу зарезервировано место в
> enum.
### `bsp_display_deinit`
Останавливает ELCDIF (`ELCDIF_RgbModeStop`), выключает IRQ, вызывает
`ELCDIF_Deinit`, отключает `kCLOCK_LcdPixel` и гасит подсветку. Безопасен
при вызове до `init` и повторно. Всегда возвращает `BSP_OK`.
### `bsp_display_set_rotation`
Переключает ориентацию через ножки LR/UD для дисплеев с
`has_orientation_pins = true` (TFT7/TFT8). Для TFT4 поддерживается только
`BSP_DISPLAY_ROTATE_0`; другие значения возвращают `BSP_ERR_NOT_SUPPORTED`.
До `bsp_display_init()` возвращает `BSP_ERR_INIT`. Неизвестная rotation —
`BSP_ERR_PARAM`.
Соответствие rotation → LR/UD (из `display.c`):
| Rotation | LR | UD |
| ---------------------- | -- | -- |
| `BSP_DISPLAY_ROTATE_0` | 1 | 0 |
| `BSP_DISPLAY_ROTATE_90`| 1 | 1 |
| `BSP_DISPLAY_ROTATE_180`| 0 | 1 |
| `BSP_DISPLAY_ROTATE_270`| 0 | 0 |
### `bsp_display_set_next_buffer`
Тонкая обёртка над `ELCDIF_SetNextBufferAddr`. Согласно заголовку, безопасна
из ISR и из задачи; переключение произойдёт аппаратно по окончании текущего
кадра. Возврата нет.
### `bsp_display_get_size` / `bsp_display_get_type`
Возвращают зафиксированные при `init` параметры активного дисплея.
`bsp_display_get_size()` возвращает `NULL` до `init`; `bsp_display_get_type()`
возвращает `BSP_DISPLAY_COUNT`, если дисплей не инициализирован.
### Callback `bsp_display_frame_cb_t`
Вызывается из `LCDIF_IRQHandler` при флаге `kELCDIF_CurFrameDone`. Должен
быть ISR-safe: запись в `volatile`, `xSemaphoreGiveFromISR()` и т.п.; любые
блокирующие операции запрещены (требование из заголовка).
---
## Порядок использования
```c
#include "bsp/display.h"
/* Фреймбуфер — статический, в NonCacheable SDRAM, выровнен по 64 байтам. */
static AT_NONCACHEABLE_SECTION_ALIGN(
uint32_t fb[BSP_DISPLAY_MAX_HEIGHT * BSP_DISPLAY_MAX_WIDTH], 64U);
static volatile bool g_frame_done;
static void on_frame_done(void) { g_frame_done = true; } /* ISR-safe */
void app_init(void)
{
/* board_hw_init() / CLOCK_*/
bsp_status_t s = bsp_display_init(BSP_DISPLAY_TFT8,
(uint32_t) fb,
on_frame_done);
if (s != BSP_OK) { /* обработать */ }
(void) bsp_display_set_rotation(BSP_DISPLAY_ROTATE_0);
/* Залить буфер и показать кадр */
g_frame_done = false;
bsp_display_set_next_buffer((uint32_t) fb);
while (!g_frame_done) { /* ждать */ }
}
```
---
## Зависимости и CMake
```cmake
# bsp/display/CMakeLists.txt
add_library(bsp_display STATIC src/display.c)
target_include_directories(bsp_display
PUBLIC include/
PRIVATE src/)
target_link_libraries(bsp_display
PUBLIC bsp_status
PRIVATE bsp_board sdk_elcdif)
```
- `bsp_status` (PUBLIC) — `bsp_status_t` в публичном API.
- `bsp_board` (PRIVATE) — общие board-уровневые символы (`BOARD_*`, IOMUXC).
- `sdk_elcdif` (PRIVATE) — `fsl_elcdif.h`, тип `elcdif_rgb_mode_config_t`,
функции `ELCDIF_*`, флаги полярности.
Дополнительно `display.c` подключает `fsl_clock.h` (`CLOCK_SetMux`,
`CLOCK_SetDiv`, `CLOCK_EnableClock`, `kCLOCK_LcdifPreMux/PreDiv/Div`,
`kCLOCK_LcdPixel`) и `fsl_gpio.h` (`GPIO_PinWrite`) — символы предоставляются
SDK через транзитивные зависимости.
Цель не собирается при `BUILD_TESTS_HOST=ON` (host-сборка) — ранний
`return()` в `CMakeLists.txt`.
Потребитель (`firmware/test/CMakeLists.txt`):
```cmake
target_link_libraries(firmware_test PRIVATE
...
bsp_display
...
)
target_compile_definitions(firmware_test PRIVATE
DISPLAY_TEST_TYPE=BSP_DISPLAY_TFT8
...
)
```
`DISPLAY_TEST_TYPE` — параметр **тест-модуля** (`test_display.c`), а не самого
`bsp_display`; см. ниже.
---
## Связь с firmware_test (`test_display.c`)
Тест-модуль `firmware/test/src/tests/test_display.c` использует это BSP так:
- Тип дисплея определяется макросом `DISPLAY_TEST_TYPE` (по умолчанию
`BSP_DISPLAY_TFT8`), задаётся через `target_compile_definitions` в
`firmware/test/CMakeLists.txt`.
- В `init` тест-модуль вызывает
`bsp_display_init((bsp_display_type_t) DISPLAY_TEST_TYPE, (uint32_t) g_s_framebuf, display_frame_cb)`,
затем `bsp_display_set_rotation(BSP_DISPLAY_ROTATE_0)`.
- Фреймбуфер — `g_s_framebuf[BSP_DISPLAY_MAX_HEIGHT * BSP_DISPLAY_MAX_WIDTH]`
типа `uint32_t`, выровнен по 64 байтам через `AT_NONCACHEABLE_SECTION_ALIGN`.
- Frame sync — `volatile bool g_s_frame_done`, выставляется в callback
`display_frame_cb` (записывает `true`); сбрасывается перед каждым
`bsp_display_set_next_buffer((uint32_t) g_s_framebuf)`.
- Два этапа теста (фактическое поведение из кода):
- **Этап 1 — Цвет**: четыре шага `step_color(RED, GREEN, BLUE, WHITE)`
с XRGB8888 цветами (`0x00FF0000`, `0x0000FF00`, `0x000000FF`, `0x00FFFFFF`).
Каждый шаг — заливка → ожидание кадра → confirm оператора
с таймаутом `DISPLAY_CONFIRM_TIMEOUT_MS = 15000 мс`.
- **Этап 2 — Ротация**: выполняется только если
`bsp_display_get_type() != BSP_DISPLAY_TFT4`. Заливка «левая половина RED,
правая BLUE», затем confirm для `ROTATE_0`, затем `ROTATE_90` через
`bsp_display_set_rotation()`, после чего восстанавливается `ROTATE_0`.
- В `deinit` вызывается `bsp_display_deinit()`.
Дескриптор тест-модуля:
```c
const test_module_t K_TEST_DISPLAY = {
.id = "display",
.name = "TFT Display RGB888",
.critical = false,
.requires_hil = false,
...
};
```
---
## Ограничения и замечания
- **TFT4 не поддерживается** до реализации Video PLL: `bsp_display_init`
возвращает `BSP_ERR_NOT_SUPPORTED`, в исходнике это явно отмечено как TODO
(`CLOCK_InitVideoPll`). Соответственно, и тест-модуль `display` пропускает
этап ротации для TFT4 и поддерживает только `ROTATE_0` через API.
- **TFT10** присутствует только как зарезервированное значение `enum`
(`K_HW_CFG[BSP_DISPLAY_TFT10] = { 0 }`). Реальные тайминги/делители не
заполнены; конкретное поведение `bsp_display_init(BSP_DISPLAY_TFT10, ...)`
не описано документацией модуля и не гарантируется.
- `bsp_display_init` идемпотентен: повторный вызов без `deinit` возвращает
`BSP_OK` и не перенастраивает аппаратуру. Чтобы переинициализировать с
другим типом или новым адресом фреймбуфера, нужно сначала вызвать
`bsp_display_deinit()`.
- Адрес фреймбуфера должен указывать на NonCacheable память (согласно
заголовку); модуль не делает cache maintenance над буфером.
- `bsp_display_set_next_buffer` возвращает `void` — отсутствие ошибки от
ELCDIF предполагается; верификация переключения буфера — задача
потребителя (например, через FRAME_DONE callback).
- IOMUXC ножек LR/UD/MODE/DITHB и пина подсветки конфигурируется в
`BOARD_InitPins()` за пределами модуля; неправильная конфигурация
IOMUXC проявится отсутствием реакции дисплея, а не возвратом ошибки из
API.

View file

@ -7,7 +7,7 @@
## Что такое Config Tools ## Что такое Config Tools
NXP Config Tools — набор утилит для визуальной настройки микроконтроллера. Включает несколько инструментов: Pins Tool, Clocks Tool, Peripherals Tool. Генерирует инициализационный код на основе конфигурации сохранённой в файле `TFT_BOARD.mex`. NXP Config Tools — набор утилит для визуальной настройки микроконтроллера. Включает несколько инструментов: Pins Tool, Clocks Tool, Peripherals Tool. Генерирует инициализационный код на основе конфигурации сохранённой в файле `TFT_Board.mex`.
--- ---
@ -27,15 +27,15 @@ NXP Config Tools — набор утилит для визуальной нас
```bash ```bash
bsp/ bsp/
└── board/ └── generated/
├── TFT_BOARD.mex # Исходник конфигурации — главный файл Config Tools ├── TFT_Board.mex # Исходник конфигурации — главный файл Config Tools
├── pin_mux.c # Сгенерировано из board.mex (Pins Tool) ├── pin_mux.c # Сгенерировано из TFT_Board.mex (Pins Tool)
├── pin_mux.h ├── pin_mux.h
├── clock_config.c # Сгенерировано из board.mex (Clocks Tool) ├── clock_config.c # Сгенерировано из TFT_Board.mex (Clocks Tool)
└── clock_config.h └── clock_config.h
``` ```
`board.mex` — источник истины. Все изменения вносятся только через него. `TFT_Board.mex` — источник истины. Все изменения вносятся только через него.
--- ---
@ -133,12 +133,12 @@ Config Tools открывается **только при изменении а
**Порядок внесения изменений:** **Порядок внесения изменений:**
1. Открыть `bsp/board/TFT_BOARD.mex` в Config Tools 1. Открыть `bsp/generated/TFT_Board.mex` в Config Tools
2. Внести изменения 2. Внести изменения
3. Сгенерировать код (Update Code) 3. Сгенерировать код (Update Code)
4. Закоммитить `TFT_BOARD.mex` и сгенерированные файлы **в одном коммите** 4. Закоммитить `TFT_Board.mex` и сгенерированные файлы **в одном коммите**
**Главное правило:** `pin_mux.c`, `pin_mux.h`, `clock_config.c`, `clock_config.h`**не редактировать вручную**. Только через Config Tools. Ручная правка приведёт к рассинхронизации с `board.mex` и потере воспроизводимости конфигурации. **Главное правило:** `pin_mux.c`, `pin_mux.h`, `clock_config.c`, `clock_config.h`**не редактировать вручную**. Только через Config Tools. Ручная правка приведёт к рассинхронизации с `TFT_Board.mex` и потере воспроизводимости конфигурации.
--- ---

View file

@ -0,0 +1,228 @@
# bsp_sdram — внешняя SDRAM MT48LC16M16A2 (32 МБ)
> Расположение: `bsp/sdram/`
> Публичный заголовок: `bsp/sdram/include/bsp/sdram.h`
> Реализация: `bsp/sdram/src/sdram.c`
Модуль обеспечивает минимальную верификацию доступности внешней SDRAM,
подключённой к SEMC. Подробное тестирование (паттерны, шина адреса/данных,
retention) выполняется не здесь, а в тест-модуле `firmware_test/test_sdram.c`,
который опирается на константы и API этого модуля.
---
## Аппаратный контекст
| Параметр | Значение |
| --------------------- | ------------------------------------------------ |
| Чип | MT48LC16M16A2 |
| Объём | 32 МБ |
| Ширина шины данных | 16 бит |
| Интерфейс MCU | SEMC, регион BR0 |
| Базовый адрес | `0x80000000` (`BSP_SDRAM_BASE_ADDR`) |
| Конец региона | `0x81FFFFFF` (`+ BSP_SDRAM_SIZE_BYTES = 32 МБ`) |
Карта тестового региона (из `sdram.h`):
| Адрес | Назначение |
| ------------ | ---------------------------------------------------------- |
| `0x80000000` | Начало SDRAM (SEMC BR0) |
| `0x80200000` | `BSP_SDRAM_TEST_BASE_ADDR` — база тестового региона |
| `0x81E00000` | Начало non-cacheable региона (USB DMA, 2 MB) |
| `0x81FFFFFF` | Конец SDRAM |
Тестовая база смещена на 2 МБ от начала SDRAM, что согласно комментариям в
заголовке гарантированно выше `.data`/`.bss` прошивки и ниже non-cacheable
региона.
---
## Архитектурное ограничение: SEMC инициализируется DCD до `main()`
Модуль **не настраивает** контроллер SEMC и не модифицирует его регистры.
Согласно комментарию в `bsp/sdram/CMakeLists.txt` и `sdram.h`, инициализация
SEMC выполнена через **DCD до вызова `main()`**. Регион SDRAM также описан в
MPU как Normal Write-Back cacheable — соответствующая настройка делается за
пределами этого модуля (исходники модуля её не выполняют).
Следствие для верификации: чтобы проверить именно физическую SDRAM, а не
кэш, при readback в реализации используется явный
`SCB_CleanDCache_by_Addr` + `SCB_InvalidateDCache_by_Addr` + `__DSB()`.
---
## Состав модуля
```
bsp/sdram/
├── include/bsp/sdram.h # публичный заголовок
├── src/sdram.c # реализация bsp_sdram_init()
└── CMakeLists.txt # цель bsp_sdram
```
В `sdram.c` определены только статические вспомогательные функции
(`wait_semc_idle`, `flush_cache_at_test_base`, `verify_word`) и одна публичная
функция `bsp_sdram_init()`. Других публичных операций (например, расширенных
тестов памяти) модуль не предоставляет.
---
## Публичные константы
```c
#define BSP_SDRAM_BASE_ADDR 0x80000000UL /* SEMC BR0 */
#define BSP_SDRAM_SIZE_BYTES 0x02000000UL /* 32 MB */
#define BSP_SDRAM_TEST_BASE_ADDR 0x80200000UL /* +2 MB от базы */
#define BSP_SDRAM_TEST_FAST_SIZE 0x00010000UL /* 64 KB */
#define BSP_SDRAM_TEST_FULL_SIZE 0x00100000UL /* 1 MB */
#define BSP_SDRAM_TEST_EXTENDED_SIZE 0x01B00000UL /* 27 MB */
```
Размеры тестов — это **константы для потребителей**; сам `bsp_sdram` не
запускает по ним внутренние проходы. Например, `BSP_SDRAM_TEST_FAST_SIZE`
используется в `firmware_test/test_sdram.c` (фаза «data bus»). Константы
`BSP_SDRAM_TEST_FULL_SIZE` и `BSP_SDRAM_TEST_EXTENDED_SIZE` определены в
заголовке, но их использование текущими потребителями в дереве не описано —
рассматривайте их как ориентиры из описания карты памяти.
---
## Публичный API
```c
bsp_status_t bsp_sdram_init(void);
```
Назначение: верифицировать, что SEMC завершил инициализацию (выполненную DCD)
и что SDRAM отвечает по тестовому адресу.
Поведение (из `sdram.c`):
1. Ждёт перехода SEMC в состояние IDLE по флагу `SEMC->STS0 & SEMC_STS0_IDLE_MASK`,
таймаут — `SDRAM_SEMC_IDLE_TIMEOUT_MS = 10 мс` (через `bsp_tick_get_ms()`).
2. Записывает по `BSP_SDRAM_TEST_BASE_ADDR` паттерн `0xA5A5A5A5`,
делает `SCB_CleanDCache_by_Addr` + `SCB_InvalidateDCache_by_Addr` + `__DSB()`,
читает обратно и сверяет.
3. Повторяет то же для инверсного паттерна `0x5A5A5A5A`.
4. При успехе устанавливает внутренний флаг готовности и возвращает `BSP_OK`.
Коды возврата:
| Код | Когда |
| ----------------- | --------------------------------------------------------------------- |
| `BSP_OK` | SDRAM доступна, оба паттерна успешно прочитаны обратно. |
| `BSP_ERR_TIMEOUT` | SEMC не перешёл в IDLE за `SDRAM_SEMC_IDLE_TIMEOUT_MS` (10 мс). |
| `BSP_ERR_INIT` | Хотя бы один паттерн не совпал при readback (DCD/SDRAM не готовы). |
`bsp_sdram_init()` затрагивает только 4 байта по адресу
`BSP_SDRAM_TEST_BASE_ADDR` (две записи 32-битных слов) и не пересекается с
`.data`/`.bss` прошивки благодаря смещению на 2 МБ от базы.
---
## Порядок использования
```c
#include "bsp/sdram.h"
if (bsp_sdram_init() != BSP_OK) {
/* SEMC/SDRAM недоступны — это критическая ошибка для прошивки,
которая использует SDRAM под фреймбуферы и тестовые регионы. */
handle_critical_error();
}
/* Дальше — обычная работа с памятью по адресам внутри
[BSP_SDRAM_BASE_ADDR, BSP_SDRAM_BASE_ADDR + BSP_SDRAM_SIZE_BYTES). */
```
Полноценные тесты памяти (шина адреса, шина данных, sequential, retention)
запускаются отдельным тест-модулем — см. раздел «Связь с firmware_test».
---
## Зависимости и CMake
```cmake
# bsp/sdram/CMakeLists.txt
add_library(bsp_sdram STATIC src/sdram.c)
target_include_directories(bsp_sdram
PUBLIC include/
PRIVATE src/)
target_link_libraries(bsp_sdram
PUBLIC bsp_status
PRIVATE bsp_board bsp_tick sdk_semc)
```
- `bsp_status` (PUBLIC) — `bsp_status_t` в публичном API.
- `bsp_tick` (PRIVATE) — `bsp_tick_get_ms()` для таймаута SEMC IDLE.
- `sdk_semc` (PRIVATE) — `fsl_semc.h`, нужен для `SEMC->STS0` и
`SEMC_STS0_IDLE_MASK` при проверке готовности контроллера.
- `bsp_board` (PRIVATE) — общие board-уровневые символы.
Цель не собирается при `BUILD_TESTS_HOST=ON` (host-сборка), `CMakeLists.txt`
содержит ранний `return()`.
Потребитель (пример из `firmware/test/CMakeLists.txt`):
```cmake
target_link_libraries(firmware_test PRIVATE
...
bsp_sdram
...
)
```
---
## Связь с firmware_test (`test_sdram.c`)
Тест-модуль `firmware/test/src/tests/test_sdram.c` использует этот BSP как
основу:
- В `init`-фазе модуль вызывает `bsp_sdram_init()` и сохраняет результат
в `g_s_ready`. При неуспехе `run` сразу возвращает FAIL с
`detail = "SEMC not ready — DCD failed?"`.
- Базовый адрес тестового региона берётся из `BSP_SDRAM_TEST_BASE_ADDR`.
- Размер фазы «data bus» — `BSP_SDRAM_TEST_FAST_SIZE` (64 KB).
- Остальные фазы (`address bus`, `sequential`, `retention`) используют
свои локальные константы (`SDRAM_ADDR_BUS_BITS`, `SDRAM_SEQUENTIAL_SIZE`,
`SDRAM_RETENTION_SIZE`), определённые в `test_sdram.c`, не в BSP.
- Cache maintenance в тестовом модуле повторяет ту же схему, что в BSP:
`SCB_CleanDCache_by_Addr` + `SCB_InvalidateDCache_by_Addr` + `__DSB()`.
Дескриптор тест-модуля:
```c
const test_module_t K_TEST_SDRAM = {
.id = "sdram",
.name = "SDRAM 32 MB",
.critical = true,
.requires_hil = false,
...
};
```
---
## Ограничения и замечания
- Модуль **не выполняет** инициализацию SEMC, DCD или MPU. Если соответствующие
механизмы не отработали до `main()`, `bsp_sdram_init()` вернёт ошибку, но
починить ситуацию из этого модуля нельзя — корень проблемы в DCD / startup
/ clock-config.
- Реентрантность `bsp_sdram_init()` не описана и не гарантируется: в прошивке
вызов выполняется однократно на этапе инициализации.
- Тайм-аут IDLE (`10 мс`) рассчитан на здоровый контроллер; в случае реального
отказа SEMC именно эта величина определяет, через сколько `BSP_ERR_TIMEOUT`
будет возвращён.
- Cache maintenance в `verify_word()` работает только по одной кэш-линии
(32 байта), и `BSP_SDRAM_TEST_BASE_ADDR = 0x80200000` подобран кратным
размеру кэш-линии Cortex-M7 — иначе вызовы `SCB_*_by_Addr` потребовали бы
выравнивания.
- Связь между константами размеров (`BSP_SDRAM_TEST_FULL_SIZE`,
`BSP_SDRAM_TEST_EXTENDED_SIZE`) и конкретными сценариями тестирования не
гарантируется этим BSP — это значения из карты памяти, которые потребитель
может использовать или игнорировать. Точная стратегия тестов SDRAM
определена в `firmware_test/test_sdram.c`.

View file

@ -183,8 +183,11 @@ HIL_USB_CDC_TIMEOUT=5.0
│ ├── pyocd_utils.py ← FLEXRAM init, ELF loader, run_from_vectors │ ├── pyocd_utils.py ← FLEXRAM init, ELF loader, run_from_vectors
│ ├── env_config.py ← конфигурация из os.environ / .env │ ├── env_config.py ← конфигурация из os.environ / .env
│ ├── load_and_run.py ← CLI-утилита загрузки ELF в RAM вручную │ ├── load_and_run.py ← CLI-утилита загрузки ELF в RAM вручную
│ ├── test_uart.py ← HIL тест bsp_uart_host (без M5) │ ├── 01_test_uart.py ← HIL тест bsp_uart_host (без M5)
│ ├── test_opto.py ← HIL тест bsp_opto (через M5StampPLC) │ ├── 02_test_opto.py ← HIL тест bsp_opto (через M5StampPLC)
│ ├── 03_test_can.py ← HIL тест bsp_can
│ ├── 04_test_button.py ← HIL тест bsp_button
│ ├── 05_test_usb_cdc.py ← HIL тест USB CDC
│ ├── m5/ │ ├── m5/
│ │ ├── agent.py ← MicroPython агент на M5StampPLC │ │ ├── agent.py ← MicroPython агент на M5StampPLC
│ │ ├── cli.py ← интерактивный CLI для ручного тестирования стенда │ │ ├── cli.py ← интерактивный CLI для ручного тестирования стенда
@ -196,14 +199,24 @@ HIL_USB_CDC_TIMEOUT=5.0
├── tests/ ├── tests/
│ ├── host/ ← host unit-тесты (Unity + fff) │ ├── host/ ← host unit-тесты (Unity + fff)
│ │ ├── mocks/ ← stub-хедеры NXP SDK для компиляции на хосте │ │ ├── mocks/ ← stub-хедеры NXP SDK для компиляции на хосте
│ │ ├── button/
│ │ ├── can/
│ │ ├── cli/
│ │ ├── led/ │ │ ├── led/
│ │ ├── log/
│ │ ├── opto/ │ │ ├── opto/
│ │ ├── prio_queue/
│ │ ├── protocol/
│ │ ├── ring_buffer/ │ │ ├── ring_buffer/
│ │ ├── runner/
│ │ ├── timeout/ │ │ ├── timeout/
│ │ └── uart_host/ │ │ └── uart_host/
│ └── target/ ← HIL target-прошивки (RAM, pyOCD) │ └── target/ ← HIL target-прошивки (RAM, pyOCD)
│ ├── host_uart/ ← CLI для тестирования bsp_uart_host │ ├── host_uart/ ← CLI для тестирования bsp_uart_host
│ └── hil_opto/ ← CLI для тестирования bsp_opto │ ├── hil_button/ ← CLI для тестирования bsp_button
│ ├── hil_can/ ← CLI для тестирования bsp_can
│ ├── hil_opto/ ← CLI для тестирования bsp_opto
│ └── hil_usb_cdc/ ← CLI для тестирования USB CDC
└── docs/ └── docs/
├── DEV_ARCH.md ← этот документ ├── DEV_ARCH.md ← этот документ
@ -213,7 +226,7 @@ HIL_USB_CDC_TIMEOUT=5.0
├── mimxrt1052/ ← MCU: BOOT_FLAGS, reference manual ├── mimxrt1052/ ← MCU: BOOT_FLAGS, reference manual
└── testing/ └── testing/
├── hil/ ├── hil/
│ ├── HIL_HOWTO.md ← как проводить HIL-тесты │ ├── HIL_HOW_TO.md ← как проводить HIL-тесты
│ ├── HIL_BENCH.md ← стенд: оборудование, подключение │ ├── HIL_BENCH.md ← стенд: оборудование, подключение
│ └── HIL_CREATE_TEST.md ← как добавить новый HIL-тест │ └── HIL_CREATE_TEST.md ← как добавить новый HIL-тест
└── host/ └── host/
@ -300,12 +313,17 @@ buildPresets (ARM firmware):
all-debug / all-release all-debug / all-release
buildPresets (host-тесты): buildPresets (host-тесты):
host-debug-build: test_bsp_led, test_log, test_bsp_opto, host-debug-build: test_bsp_led, test_log, test_bsp_opto, test_bsp_button,
test_ring_buffer, test_timeout_pattern, uart_host_mock_example test_bsp_can, test_cli, test_protocol, test_firmware_runner,
test_prio_queue, uart_host_mock_example, test_ring_buffer,
test_timeout_pattern
host-release-build: то же host-release-build: то же
buildPresets (HIL): buildPresets (HIL):
target-debug-build: test_host_uart, test_hil_opto target-debug-build: test_host_uart, test_hil_button, test_hil_can,
test_hil_usb_cdc, test_hil_opto
Источник истины по списку целей — [CMakePresets.json](../CMakePresets.json).
``` ```
### 6.3 Boot-стратегии ### 6.3 Boot-стратегии
@ -409,7 +427,7 @@ just host::flash-swd-test-release
HIL-тесты проверяют периферию на реальном железе. Два типа: HIL-тесты проверяют периферию на реальном железе. Два типа:
### Базовые (без стенда) — `test_uart.py` ### Базовые (без стенда) — `01_test_uart.py`
Только MCU-Link: SWD загружает ELF в RAM, VCOM обеспечивает UART CLI. Только MCU-Link: SWD загружает ELF в RAM, VCOM обеспечивает UART CLI.
@ -421,7 +439,7 @@ MCU-Link
RT1052 → "PONG" RT1052 → "PONG"
``` ```
### С M5StampPLC — `test_opto.py` и другие ### С M5StampPLC — `02_test_opto.py` и другие
`M5StampPLC` управляет входными сигналами таргета через реле. pytest оркестрирует оба канала одновременно. `M5StampPLC` управляет входными сигналами таргета через реле. pytest оркестрирует оба канала одновременно.
@ -438,11 +456,11 @@ pytest
```bash ```bash
just build::build-hil # (devcontainer) собрать HIL ELF just build::build-hil # (devcontainer) собрать HIL ELF
just host::hil-run # прогнать все HIL тесты just host::hil-run # прогнать все HIL тесты
just host::hil-uart # только test_uart.py just host::hil-uart # только 01_test_uart.py
just host::hil-opto # только test_opto.py just host::hil-opto # только 02_test_opto.py
``` ```
Подробно — [docs/testing/hil/HIL_HOWTO.md](testing/hil/HIL_HOWTO.md). Подробно — [docs/testing/hil/HIL_HOW_TO.md](testing/hil/HIL_HOW_TO.md).
Добавление нового теста — [docs/testing/hil/HIL_CREATE_TEST.md](testing/hil/HIL_CREATE_TEST.md). Добавление нового теста — [docs/testing/hil/HIL_CREATE_TEST.md](testing/hil/HIL_CREATE_TEST.md).
Стенд и подключение — [docs/testing/hil/HIL_BENCH.md](testing/hil/HIL_BENCH.md). Стенд и подключение — [docs/testing/hil/HIL_BENCH.md](testing/hil/HIL_BENCH.md).
@ -462,8 +480,10 @@ just host::hil-opto # только test_opto.py
BSP-модули тестируются через fff-фейки и stub-хедеры в `tests/host/mocks/`. BSP-модули тестируются через fff-фейки и stub-хедеры в `tests/host/mocks/`.
`BUILD_TESTS_HOST=ON` отключает ARM-специфику и SDK-заголовки. `BUILD_TESTS_HOST=ON` отключает ARM-специфику и SDK-заголовки.
Покрытие: `bsp_led`, `bsp_opto`, `bsp_uart_host`, `ring_buffer`, timeout-паттерн. Покрытие: `bsp_led`, `bsp_opto`, `bsp_button`, `bsp_can`, `bsp_uart_host`,
Гайд — [tests/HOST_CREATE_TEST.md](../tests/HOST_CREATE_TEST.md). `cli`, `protocol`, `firmware_runner`, `prio_queue`, `ring_buffer`, `log`,
timeout-паттерн.
Гайд — [testing/host/HOST_CREATE_TEST.md](testing/host/HOST_CREATE_TEST.md).
### 10.2 HIL target-тесты ### 10.2 HIL target-тесты
@ -473,7 +493,9 @@ BSP-модули тестируются через fff-фейки и stub-хед
Запуск: just host::hil-run (на хосте) Запуск: just host::hil-run (на хосте)
``` ```
Текущие тесты: `test_uart.py` (PING/ECHO/BUF_SIZE), `test_opto.py` (оптовходы IN1/IN2/RS через M5). Текущие тесты: `01_test_uart.py` (PING/ECHO/BUF_SIZE), `02_test_opto.py`
(оптовходы IN1/IN2/RS через M5), `03_test_can.py` (CAN-шина), `04_test_button.py`
(кнопочные входы), `05_test_usb_cdc.py` (USB CDC).
--- ---
@ -500,7 +522,8 @@ Devcontainer
- `🐛 Debug: bootloader` — bare-metal, A/B обновление - `🐛 Debug: bootloader` — bare-metal, A/B обновление
- `🐛 Debug: tft_app (FreeRTOS)` — FreeRTOS task view - `🐛 Debug: tft_app (FreeRTOS)` — FreeRTOS task view
RTT-логи (`SEGGER_RTT_ENABLED=ON`) пока что не используются вместо этого можно использовать `port/log`. RTT-логи доступны в Debug-сборках (`SEGGER_RTT_ENABLED=ON`); подробности — в
[docs/HOW_TO_DEBUG.md](HOW_TO_DEBUG.md).
--- ---

View file

@ -407,9 +407,9 @@ test_foo()
### Порядок при запуске нескольких файлов ### Порядок при запуске нескольких файлов
```bash ```bash
pytest test_uart.py test_<name>.py pytest 01_test_uart.py test_<name>.py
test_uart.py test_<name>.py 01_test_uart.py test_<name>.py
───────────────────── ───────────────────── ───────────────────── ─────────────────────
loaded_host_uart m5 ← создаётся loaded_host_uart m5 ← создаётся
uart ← создаётся loaded_<name> uart ← создаётся loaded_<name>

View file

@ -65,7 +65,7 @@ Scope определяет **как долго живёт** экземпляр
### Почему для HIL основной scope — `module` ### Почему для HIL основной scope — `module`
Каждый тест-файл (`test_uart.py`, `test_opto.py`) работает со **своей прошивкой**. Каждый тест-файл (`01_test_uart.py`, `02_test_opto.py`) работает со **своей прошивкой**.
Загружать ELF перед каждой `test_*()` — слишком дорого (~2 с на загрузку через pyOCD). Загружать ELF перед каждой `test_*()` — слишком дорого (~2 с на загрузку через pyOCD).
`scope="module"` означает: загрузил один раз, прогнал все тесты файла, закрыл. `scope="module"` означает: загрузил один раз, прогнал все тесты файла, закрыл.
@ -194,8 +194,8 @@ test_opto_ch1()
```bash ```bash
tools/hil/ tools/hil/
├── conftest.py ← фикстуры: _load_elf, uart, m5, loaded_* ├── conftest.py ← фикстуры: _load_elf, uart, m5, loaded_*
├── test_uart.py ← видит всё из conftest.py ├── 01_test_uart.py ← видит всё из conftest.py
├── test_opto.py ← видит всё из conftest.py ├── 02_test_opto.py ← видит всё из conftest.py
└── m5/ └── m5/
└── conftest.py ← (если бы был) виден только в m5/ └── conftest.py ← (если бы был) виден только в m5/
``` ```
@ -244,11 +244,11 @@ Teardown выполняется в **обратном** порядке созд
При запуске нескольких файлов каждый получает **свой** набор module-фикстур: При запуске нескольких файлов каждый получает **свой** набор module-фикстур:
```bash ```bash
pytest test_uart.py test_opto.py pytest 01_test_uart.py 02_test_opto.py
``` ```
```bash ```bash
test_uart.py test_opto.py 01_test_uart.py 02_test_opto.py
───────────────────────── ───────────────────────── ───────────────────────── ─────────────────────────
loaded_host_uart ← создаётся m5 ← создаётся loaded_host_uart ← создаётся m5 ← создаётся
uart ← создаётся loaded_hil_opto uart ← создаётся loaded_hil_opto
@ -538,7 +538,7 @@ class Test<n>:
## 12. Визуальная схема жизненного цикла ## 12. Визуальная схема жизненного цикла
```bash ```bash
pytest test_opto.py pytest 02_test_opto.py
────────────── module scope (один раз на файл) ────────────── ────────────── module scope (один раз на файл) ──────────────

View file

@ -136,21 +136,21 @@ just host::hil-button # конкретный интерактивны
### Конкретный автоматический тест ### Конкретный автоматический тест
```bash ```bash
just host::hil-uart # только test_uart.py just host::hil-uart # только 01_test_uart.py
just host::hil-opto # только test_opto.py just host::hil-opto # только 02_test_opto.py
just host::hil-can # только test_can.py just host::hil-can # только 03_test_can.py
``` ```
### Один тест-кейс (для отладки) ### Один тест-кейс (для отладки)
```bash ```bash
uv run --directory tools/hil pytest test_opto.py::TestOptoConnectivity::test_target_ping -v uv run --directory tools/hil pytest 02_test_opto.py::TestOptoConnectivity::test_target_ping -v
``` ```
### Без перезагрузки ELF (если прошивка уже запущена) ### Без перезагрузки ELF (если прошивка уже запущена)
```bash ```bash
uv run --directory tools/hil pytest test_opto.py -v --no-load uv run --directory tools/hil pytest 02_test_opto.py -v --no-load
``` ```
Удобно при отладке тестов когда прошивка уже в RAM и не нужно каждый раз Удобно при отладке тестов когда прошивка уже в RAM и не нужно каждый раз

View file

@ -15,8 +15,8 @@ tools/hil/
├── env_config.py — конфигурация из os.environ / .env ├── env_config.py — конфигурация из os.environ / .env
├── pyocd_utils.py — FLEXRAM init, ELF loader, run_from_vectors ├── pyocd_utils.py — FLEXRAM init, ELF loader, run_from_vectors
├── load_and_run.py — CLI-утилита: загрузить ELF в RAM вручную ├── load_and_run.py — CLI-утилита: загрузить ELF в RAM вручную
├── test_uart.py — HIL тест bsp_uart_host (без стенда) ├── 01_test_uart.py — HIL тест bsp_uart_host (без стенда)
├── test_opto.py — HIL тест bsp_opto (через M5StampPLC) ├── 02_test_opto.py — HIL тест bsp_opto (через M5StampPLC)
├── m5/ ├── m5/
│ ├── agent.py — MicroPython агент на M5StampPLC (реле, входы, CAN) │ ├── agent.py — MicroPython агент на M5StampPLC (реле, входы, CAN)
│ ├── cli.py — интерактивный CLI для ручного тестирования стенда и таргета │ ├── cli.py — интерактивный CLI для ручного тестирования стенда и таргета
@ -40,7 +40,7 @@ tools/hil/
| Документ | Содержимое | | Документ | Содержимое |
| --------------------------------------------------------------- | ---------------------------------------------- | | --------------------------------------------------------------- | ---------------------------------------------- |
| [HIL_HOWTO.md](../../docs/testing/hil/HIL_HOWTO.md) | Как запускать HIL-тесты (пошагово) | | [HIL_HOW_TO.md](../../docs/testing/hil/HIL_HOW_TO.md) | Как запускать HIL-тесты (пошагово) |
| [HIL_BENCH.md](../../docs/testing/hil/HIL_BENCH.md) | Стенд: оборудование, подключение, маппинг реле | | [HIL_BENCH.md](../../docs/testing/hil/HIL_BENCH.md) | Стенд: оборудование, подключение, маппинг реле |
| [HIL_CREATE_TEST.md](../../docs/testing/hil/HIL_CREATE_TEST.md) | Как добавить новый HIL-тест | | [HIL_CREATE_TEST.md](../../docs/testing/hil/HIL_CREATE_TEST.md) | Как добавить новый HIL-тест |

View file

@ -20,7 +20,7 @@ tools/host/
│ ├── w25q128_fdcb.bin — FCB для W25Q128 Quad SPI ← используется │ ├── w25q128_fdcb.bin — FCB для W25Q128 Quad SPI ← используется
│ ├── w25q64_fdcb.bin — FCB для W25Q64 Quad SPI │ ├── w25q64_fdcb.bin — FCB для W25Q64 Quad SPI
│ └── w25q512_fdcb.bin — FCB для W25Q512 Quad SPI │ └── w25q512_fdcb.bin — FCB для W25Q512 Quad SPI
├── HAB_GUIDE.md — подробно про HAB-образы и процесс подписи ├── ../../docs/mimxrt1052/HAB_GUIDE.md — подробно про HAB-образы и процесс подписи
├── pyproject.toml ├── pyproject.toml
└── uv.lock └── uv.lock
``` ```