# Update documentation
This commit is contained in:
parent
a9a207ab6c
commit
be36d56170
11 changed files with 647 additions and 46 deletions
16
README.md
16
README.md
|
|
@ -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)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -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) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
@ -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` и потере воспроизводимости конфигурации.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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`.
|
||||||
|
|
@ -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).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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 (один раз на файл) ──────────────
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 и не нужно каждый раз
|
||||||
|
|
|
||||||
|
|
@ -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-тест |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue