# 6
Кастомный скрипт в tools/host для прошивки bare-metal платы
This commit is contained in:
parent
853eda2d08
commit
3940947963
19 changed files with 640 additions and 952 deletions
|
|
@ -16,8 +16,9 @@ set_source_files_properties(board/board.c board/pin_mux.c
|
||||||
PROPERTIES COMPILE_OPTIONS "-w")
|
PROPERTIES COMPILE_OPTIONS "-w")
|
||||||
# Дефайны PUBLIC — транзитивно подтянутся во все firmware таргеты TODO: для
|
# Дефайны PUBLIC — транзитивно подтянутся во все firmware таргеты TODO: для
|
||||||
# каждого приложения свои дефайны
|
# каждого приложения свои дефайны
|
||||||
target_compile_definitions(bsp_board PUBLIC CPU_MIMXRT1052CVJ5B
|
target_compile_definitions(
|
||||||
SKIP_SYSCLK_INIT)
|
bsp_board PUBLIC CPU_MIMXRT1052CVJ5B SKIP_SYSCLK_INIT XIP_EXTERNAL_FLASH=1
|
||||||
|
XIP_BOOT_HEADER_ENABLE=1 XIP_BOOT_HEADER_DCD_ENABLE=1)
|
||||||
|
|
||||||
# Сценарий A: XIP — код исполняется прямо из Flash
|
# Сценарий A: XIP — код исполняется прямо из Flash
|
||||||
add_library(bsp_boot_xip INTERFACE)
|
add_library(bsp_boot_xip INTERFACE)
|
||||||
|
|
|
||||||
223
docs/HAB_GUIDE.md
Normal file
223
docs/HAB_GUIDE.md
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
# High Assurance Boot (HAB) — Принцип работы и применение на MIMXRT1052
|
||||||
|
|
||||||
|
## 1. Что такое HAB
|
||||||
|
|
||||||
|
**High Assurance Boot (HAB)** — механизм безопасной загрузки, встроенный в BootROM микроконтроллеров семейства NXP i.MX/RT. Его цель — криптографически гарантировать, что на чипе запустится только авторизованный код.
|
||||||
|
|
||||||
|
HAB работает на уровне кремния: BootROM прошит на заводе и не может быть изменён. Вся цепочка доверия строится от него.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Угрозы без HAB
|
||||||
|
|
||||||
|
Без механизма защищённой загрузки любой, имеющий физический доступ к устройству, может:
|
||||||
|
|
||||||
|
- подключить программатор и залить произвольную прошивку
|
||||||
|
- загрузить вредоносный код через USB в режиме Serial Download Protocol (SDP)
|
||||||
|
- модифицировать прошивку во Flash между производством и эксплуатацией
|
||||||
|
|
||||||
|
HAB устраняет эти угрозы на аппаратном уровне.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Структура HAB-образа
|
||||||
|
|
||||||
|
HAB-образ — это не просто бинарник прошивки, а обёртка с метаданными вокруг него. BootрOM ищет обязательные структуры по фиксированным смещениям.
|
||||||
|
|
||||||
|
### Карта памяти Flash (FlexSPI NOR, XIP)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
0x60000000 ┌──────────────────────────────────┐
|
||||||
|
│ FCB — Flash Configuration Block │ 512 байт
|
||||||
|
│ (конфигурация FlexSPI контроллера│
|
||||||
|
│ записывается Flashloader'ом) │
|
||||||
|
0x60001000 ├──────────────────────────────────┤
|
||||||
|
│ IVT — Image Vector Table │ 32 байта
|
||||||
|
0x60001020 ├──────────────────────────────────┤
|
||||||
|
│ BDT — Boot Data Table │ 12 байт
|
||||||
|
0x60001030 ├──────────────────────────────────┤
|
||||||
|
│ DCD — Device Config Data │ опционально
|
||||||
|
│ (инициализация SDRAM и др.) │
|
||||||
|
├──────────────────────────────────┤
|
||||||
|
0x60003000 │ Код прошивки (.text, .data, ...) │
|
||||||
|
│ │
|
||||||
|
├──────────────────────────────────┤
|
||||||
|
│ CSF — Command Sequence File │ только в signed-образе
|
||||||
|
│ (подпись, ключи, хэши) │
|
||||||
|
└──────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.1 IVT — Image Vector Table
|
||||||
|
|
||||||
|
Главная точка входа для BootROM. Структура фиксирована, 32 байта, тег `0xD1`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
uint32_t header; // тег 0xD1, длина, версия
|
||||||
|
uint32_t entry; // адрес Reset_Handler прошивки
|
||||||
|
uint32_t reserved1;
|
||||||
|
uint32_t dcd; // адрес DCD (0 если не нужен)
|
||||||
|
uint32_t boot_data; // адрес BDT
|
||||||
|
uint32_t self; // адрес самого IVT
|
||||||
|
uint32_t csf; // адрес CSF (0 если unsigned)
|
||||||
|
uint32_t reserved2;
|
||||||
|
} ivt_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
BootROM находит IVT по фиксированному смещению от начала Flash (`ivtOffset = 0x1000` для FlexSPI NOR), читает его и получает адреса всех остальных структур.
|
||||||
|
|
||||||
|
### 3.2 BDT — Boot Data Table
|
||||||
|
|
||||||
|
Сообщает BootROM, где начинается образ и каков его полный размер:
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
uint32_t start; // 0x60000000 — начало образа во Flash
|
||||||
|
uint32_t length; // полный размер в байтах
|
||||||
|
uint32_t plugin; // 0 для обычного образа
|
||||||
|
} boot_data_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 DCD — Device Configuration Data
|
||||||
|
|
||||||
|
Опциональная секция с командами инициализации периферии, которые BootROM выполняет **до** передачи управления прошивке. Типичное применение — инициализация SDRAM (SEMC), чтобы к моменту старта первой инструкции прошивки память уже была доступна.
|
||||||
|
|
||||||
|
DCD содержит последовательность команд двух типов:
|
||||||
|
|
||||||
|
| Команда | Тег | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| `Write Data` | `0xCC` | Записать значение по адресу |
|
||||||
|
| `Check Bits Set` | `0xCF` | Ждать пока бит станет `1` (poll) |
|
||||||
|
|
||||||
|
Формат бинарника: `Tag(1) | Length(2 BE) | Parameter(1) | данные`.
|
||||||
|
|
||||||
|
### 3.4 CSF — Command Sequence File
|
||||||
|
|
||||||
|
Криптографическая секция. Присутствует только в подписанных образах. Содержит:
|
||||||
|
|
||||||
|
- таблицу публичных ключей (SRK table)
|
||||||
|
- хэши защищённых регионов образа (IVT, BDT, код)
|
||||||
|
- подпись RSA 2048/4096 или ECDSA
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Режимы HAB
|
||||||
|
|
||||||
|
### 4.1 По типу образа
|
||||||
|
|
||||||
|
| Режим | `flags` | CSF | Применение |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Unsigned | `0x00` | отсутствует | разработка, отладка |
|
||||||
|
| Signed | `0x08` | RSA/ECDSA подпись | производство |
|
||||||
|
| Signed + Encrypted | `0x0C` | подпись + шифрование кода | максимальная защита |
|
||||||
|
|
||||||
|
### 4.2 По состоянию чипа (OTP fuse)
|
||||||
|
|
||||||
|
Независимо от типа образа, чип может находиться в одном из двух состояний:
|
||||||
|
|
||||||
|
**HAB Open** (fuse `SEC_CONFIG = 0`, заводское состояние):
|
||||||
|
BootROM проверяет подпись, но **игнорирует ошибки** — запуск происходит в любом случае. Это позволяет работать с unsigned образами на этапе разработки.
|
||||||
|
|
||||||
|
**HAB Closed** (fuse `SEC_CONFIG = 1`):
|
||||||
|
При ошибке проверки подписи BootROM **отказывает в запуске** безвозвратно. Запись fuse необратима — чип нельзя вернуть в Open состояние.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Цепочка доверия (Trust Chain)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Производитель устройства
|
||||||
|
│
|
||||||
|
├── Генерирует пару ключей RSA 4096
|
||||||
|
│ private.pem → хранится в защищённом месте (HSM / vault)
|
||||||
|
│ public.pem → включается в образ (SRK table)
|
||||||
|
│
|
||||||
|
├── SHA256(public.pem) записывается в OTP fuses (SRK_HASH)
|
||||||
|
│ ↑ необратимо, выполняется один раз при производстве
|
||||||
|
│
|
||||||
|
└── При сборке каждого релиза:
|
||||||
|
nxpimage hab export (flags=0x08)
|
||||||
|
→ хэшируются IVT + BDT + код
|
||||||
|
→ подписывается private.pem
|
||||||
|
→ CSF встраивается в образ
|
||||||
|
|
||||||
|
При загрузке на чипе:
|
||||||
|
BootROM
|
||||||
|
→ читает IVT → находит CSF
|
||||||
|
→ извлекает public key из CSF
|
||||||
|
→ SHA256(public key) == SRK_HASH из fuses? → ДА
|
||||||
|
→ проверяет подпись хэшей регионов → ОК
|
||||||
|
→ прыгает на entry point
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Почему Unsigned-образ требует HAB-контейнер
|
||||||
|
|
||||||
|
Распространённое заблуждение: "раз образ без подписи, зачем вообще HAB?". Ответ прост:
|
||||||
|
|
||||||
|
**BootROM всегда ищет IVT по фиксированному смещению.** Это не опциональная безопасность — это формат загрузки. Без IVT и BDT BootROM не знает:
|
||||||
|
|
||||||
|
- куда прыгать (entry point)
|
||||||
|
- где находится DCD для инициализации SDRAM
|
||||||
|
- каков размер образа
|
||||||
|
|
||||||
|
`nxpimage hab export` для unsigned образа выполняет именно эту работу — добавляет IVT, BDT, встраивает DCD — без какой-либо криптографии. CSF при этом равен нулю.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Процесс прошивки MIMXRT1052 (USB, без JTAG)
|
||||||
|
|
||||||
|
BootROM в режиме SDP умеет только писать в RAM и прыгать. Для записи во Flash необходим **Flashloader** — специальная программа от NXP.
|
||||||
|
|
||||||
|
```
|
||||||
|
Плата в SDP режиме (BOOT_MOD_1 = 3V3)
|
||||||
|
│
|
||||||
|
│ sdphost -u 0x1FC9,0x0130
|
||||||
|
├─ write-file 0x20001C00 ivt_flashloader.bin
|
||||||
|
└─ jump-address 0x20001C00
|
||||||
|
│
|
||||||
|
│ (ожидание ~3с инициализации)
|
||||||
|
│
|
||||||
|
Flashloader запущен
|
||||||
|
│ blhost -u 0x15A2,0x0073
|
||||||
|
├─ fill-memory 0x2000 4 0xC0000007 ← option word для FlexSPI NOR
|
||||||
|
├─ configure-memory 9 0x2000 ← Flashloader пишет FCB в Flash
|
||||||
|
├─ flash-erase-region 0x60000000 …
|
||||||
|
├─ write-memory 0x60002000 firmware_hab.bin ← HAB образ
|
||||||
|
└─ reset
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Жизненный цикл для проекта TFT
|
||||||
|
|
||||||
|
| Стадия | Режим HAB | Подпись | Fuse |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Разработка | Open | Unsigned (`0x00`) | не трогаем |
|
||||||
|
| Входной контроль | Open | Unsigned (`0x00`) | не трогаем |
|
||||||
|
| Предсерийные образцы | Open | Signed (`0x08`) | не трогаем |
|
||||||
|
| Серийное производство | **Closed** | Signed (`0x08`) | `SEC_CONFIG = 1` |
|
||||||
|
|
||||||
|
> ⚠️ Запись `SEC_CONFIG = 1` необратима. Перед закрытием HAB необходимо убедиться, что подписанный образ успешно проходит верификацию на реальном железе.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Инструменты
|
||||||
|
|
||||||
|
| Инструмент | Назначение |
|
||||||
|
|---|---|
|
||||||
|
| `nxpimage hab export` | Сборка HAB-образа (IVT + BDT + DCD + опционально CSF) |
|
||||||
|
| `nxpimage hab parse` | Разбор готового образа для проверки |
|
||||||
|
| `sdphost` | Связь с BootROM в SDP режиме (запись в RAM, прыжок) |
|
||||||
|
| `blhost` | Связь с Flashloader (запись во Flash, конфигурация памяти) |
|
||||||
|
| `nxpdevscan` | Обнаружение подключённых NXP устройств |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Литература
|
||||||
|
|
||||||
|
- **NXP AN12263** — "HAB Code Signing for i.MX RT" — пошаговая инструкция по подписи образов
|
||||||
|
- **MIMXRT1052 Reference Manual** — Chapter 9: System Boot (структуры IVT, BDT, DCD, CSF)
|
||||||
|
- [**SPSDK Documentation**](https://spsdk.readthedocs.io) — документация по nxpimage, blhost, sdphost
|
||||||
|
- **NXP Application Note AN4581** — "Secure Boot on i.MX50, i.MX53, and i.MX 6 Series"
|
||||||
|
|
@ -13,7 +13,6 @@ target_sources(firmware_test PRIVATE main.c
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
firmware_test
|
firmware_test
|
||||||
PRIVATE bsp_board
|
PRIVATE bsp_board
|
||||||
bsp_boot_xip
|
|
||||||
# SDK драйверы периферии — добавляй по мере написания тестов
|
# SDK драйверы периферии — добавляй по мере написания тестов
|
||||||
sdk_lpuart # UART тест
|
sdk_lpuart # UART тест
|
||||||
sdk_flexcan # CAN тест
|
sdk_flexcan # CAN тест
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
#include "fsl_gpio.h"
|
#include "fsl_gpio.h"
|
||||||
#include "pin_mux.h"
|
#include "pin_mux.h"
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Definitions
|
* Definitions
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
|
||||||
253
tools/README.md
253
tools/README.md
|
|
@ -1,164 +1,257 @@
|
||||||
# Host Tools — окружение для прошивки
|
# tools/host — Окружение прошивки MIMXRT1052CVJ5B
|
||||||
|
|
||||||
Изолированное Python-окружение на базе [uv](https://docs.astral.sh/uv/).
|
Изолированное Python-окружение на базе [uv](https://docs.astral.sh/uv/) для сборки
|
||||||
Устанавливается на хост-машине разработчика — **не внутри devcontainer**.
|
HAB-образов и прошивки платы через USB. Запускается на хост-машине разработчика —
|
||||||
|
**не внутри devcontainer**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Структура
|
## Структура
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tools/host/
|
tools/host/
|
||||||
├── dcd/
|
├── dcd/
|
||||||
│ ├── dcd_mt48lc16m16a2.cfg ← источник истины для DCD (коммитить)
|
│ ├── dcd.bin ← DCD бинарник (инициализация SDRAM, коммитить как есть)
|
||||||
│ ├── dcd_compiler.py ← скрипт: .cfg → .bin
|
│ └── ivt_flashloader.bin ← NXP Flashloader (коммитить)
|
||||||
│ └── dcd.bin ← артефакт (пересобирается из .cfg)
|
|
||||||
│
|
|
||||||
├── fdcb/
|
|
||||||
│ ├── fcb_w25q64_quad.yaml ← конфиг FCB: W25Q64, Quad I/O, 133 MHz
|
|
||||||
│ └── fcb.bin ← артефакт (пересобирается из .yaml)
|
|
||||||
│
|
|
||||||
├── hab/
|
├── hab/
|
||||||
│ ├── hab_firmware_test.yaml ← HAB: Debug + DCD (входной контроль)
|
│ ├── hab_firmware_test.yaml ← HAB: Debug + DCD (входной контроль)
|
||||||
│ ├── hab_bootloader.yaml ← HAB: Release, без DCD
|
│ ├── hab_bootloader.yaml ← HAB: Release, без DCD
|
||||||
│ └── hab_app.yaml ← HAB: Release + DCD (боевая прошивка)
|
│ └── hab_app.yaml ← HAB: Release + DCD (боевая прошивка)
|
||||||
│
|
├── flash_usb.py ← скрипт прошивки через USB
|
||||||
├── image/
|
├── pyproject.toml ← зависимости (spsdk==3.7.x)
|
||||||
│ ├── bootimg_firmware_test.yaml
|
|
||||||
│ ├── bootimg_bootloader.yaml
|
|
||||||
│ └── bootimg_app.yaml
|
|
||||||
│
|
|
||||||
├── pyproject.toml ← зависимости (spsdk, версия зафиксирована)
|
|
||||||
├── uv.lock ← lockfile (коммитить)
|
├── uv.lock ← lockfile (коммитить)
|
||||||
├── .python-version
|
|
||||||
└── README.md
|
└── README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
## Установка uv (один раз на машину)
|
## Предварительные требования
|
||||||
|
|
||||||
|
### 1. uv — один раз на машину
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Linux/macOS
|
# macOS / Linux
|
||||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
|
||||||
# Windows
|
# Windows
|
||||||
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Первый запуск (один раз на репозиторий)
|
### 2. Зависимости проекта — один раз на репозиторий
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd tools/host
|
cd tools/host
|
||||||
uv sync
|
uv sync
|
||||||
```
|
```
|
||||||
|
|
||||||
### udev правило для USB SDP — только Linux, один раз на машину
|
### 3. udev правила — только Linux, один раз на машину
|
||||||
|
|
||||||
Без этого правила `blhost` требует `sudo`:
|
Без этого для работы с USB нужен `sudo`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="1fc9", ATTR{idProduct}=="0135", MODE="0666", GROUP="plugdev"' \
|
sudo tee /etc/udev/rules.d/99-nxp-mimxrt.rules << 'EOF'
|
||||||
| sudo tee /etc/udev/rules.d/99-nxp-sdp.rules
|
# NXP BootROM — SDP режим (BOOT_MOD_1 = 3V3)
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="1fc9", ATTR{idProduct}=="0130", MODE="0666", GROUP="plugdev"
|
||||||
|
# NXP Flashloader — после jump-address
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="15a2", ATTR{idProduct}=="0073", MODE="0666", GROUP="plugdev"
|
||||||
|
EOF
|
||||||
|
|
||||||
sudo udevadm control --reload-rules && sudo udevadm trigger
|
sudo udevadm control --reload-rules && sudo udevadm trigger
|
||||||
sudo usermod -a -G plugdev $USER
|
sudo usermod -a -G plugdev $USER
|
||||||
# Перелогиниться после usermod!
|
# После usermod — перелогиниться!
|
||||||
```
|
```
|
||||||
|
|
||||||
## Пайплайн сборки загрузочного образа
|
---
|
||||||
|
|
||||||
### Шаг 1 — DCD (пересобирать при изменении dcd_mt48lc16m16a2.cfg)
|
## Карта Flash (W25Q64FVSSIG, 8 MB)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd tools/host/dcd
|
0x60000000 ┌─────────────────────────────┐
|
||||||
uv run python3 dcd_compiler.py dcd_mt48lc16m16a2.cfg dcd.bin
|
│ FCB — Flash Config Block │ 512 байт
|
||||||
|
│ (пишет Flashloader, │
|
||||||
|
│ не входит в HAB образ) │
|
||||||
|
0x60001000 ├─────────────────────────────┤
|
||||||
|
│ IVT — Image Vector Table │ ← начало HAB образа
|
||||||
|
│ BDT — Boot Data Table │
|
||||||
|
0x60001040 ├─────────────────────────────┤
|
||||||
|
│ DCD — SDRAM init │ ~1088 байт (для fw_test и app)
|
||||||
|
0x60003000 ├─────────────────────────────┤
|
||||||
|
│ Код прошивки │
|
||||||
|
│ (.text, .data, ...) │
|
||||||
|
└─────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
### Шаг 2 — FCB (пересобирать при изменении fcb_w25q64_quad.yaml)
|
---
|
||||||
|
|
||||||
|
## Пайплайн: сборка HAB образа
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd tools/host/fdcb
|
cd tools/host/hab
|
||||||
uv run nxpimage bootable-image fcb export -c fcb_w25q64_quad.yaml -o fcb.bin
|
|
||||||
```
|
|
||||||
|
|
||||||
### Шаг 3 — Загрузочный образ
|
# firmware_test (Debug) — входной контроль платы
|
||||||
|
uv run nxpimage hab export --force \
|
||||||
```bash
|
-c hab_firmware_test.yaml \
|
||||||
cd tools/host/image
|
-o ../../../../build/Debug/firmware_test_hab.bin
|
||||||
|
|
||||||
# firmware_test (Debug, входной контроль)
|
|
||||||
uv run nxpimage bootable-image export -c bootimg_firmware_test.yaml
|
|
||||||
|
|
||||||
# bootloader (Release)
|
# bootloader (Release)
|
||||||
uv run nxpimage bootable-image export -c bootimg_bootloader.yaml
|
uv run nxpimage hab export --force \
|
||||||
|
-c hab_bootloader.yaml \
|
||||||
|
-o ../../../../build/Release/bootloader_hab.bin
|
||||||
|
|
||||||
# app (Release, боевая прошивка)
|
# app (Release) — боевая прошивка
|
||||||
uv run nxpimage bootable-image export -c bootimg_app.yaml
|
uv run nxpimage hab export --force \
|
||||||
|
-c hab_app.yaml \
|
||||||
|
-o ../../../../build/Release/app_hab.bin
|
||||||
```
|
```
|
||||||
|
|
||||||
Артефакты попадают в `build/Debug/` и `build/Release/` соответственно.
|
### Проверка образа после сборки
|
||||||
|
|
||||||
### Проверка образа
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd tools/host/image
|
uv run nxpimage hab parse -b ../../../../build/Debug/firmware_test_hab.bin
|
||||||
uv run nxpimage bootable-image parse \
|
|
||||||
-b ../../../../build/Debug/firmware_test_bootable.bin \
|
|
||||||
-f mimxrt1050
|
|
||||||
```
|
```
|
||||||
|
|
||||||
В выводе должны присутствовать секции `FCB`, `IVT`, `BDT`, `DCD`, `App`.
|
Ожидаемый результат: IVT с корректным `entry`, DCD с тегом `0xD2`,
|
||||||
|
`csf = 0x00000000` (unsigned).
|
||||||
|
|
||||||
## Прошивка через USB (BootROM SDP режим)
|
---
|
||||||
|
|
||||||
Перевести плату в SDP режим: `BOOT_MOD_1 = 1` (подтянуть к 3V3), затем подать питание или нажать Reset.
|
## Пайплайн: прошивка через USB
|
||||||
|
|
||||||
|
### Подготовка платы
|
||||||
|
|
||||||
|
Перевести плату в режим SDP (Serial Download Protocol):
|
||||||
|
|
||||||
|
1. Подтянуть `BOOT_MOD_1` к `3V3`
|
||||||
|
2. Reset
|
||||||
|
3. Подключить USB к ПК
|
||||||
|
|
||||||
|
В этом режиме плата определяется как `VID:PID = 1FC9:0130`.
|
||||||
|
|
||||||
|
### Запуск скрипта
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd tools/host
|
cd tools/host
|
||||||
|
|
||||||
# Проверить что устройство определилось (VID:PID 1FC9:0135)
|
# firmware_test
|
||||||
export VID_PID=0x1fc9:0x0130
|
uv run python3 flash_usb.py --firmware firmware_test --build-type Debug
|
||||||
uv run nxpdevscan
|
|
||||||
|
|
||||||
# Версия BootROM на таргете
|
# app
|
||||||
uv run blhost -u $VID_PID get-property 1
|
uv run python3 flash_usb.py --firmware app --build-type Release
|
||||||
# Доступные BootROM области памяти
|
|
||||||
uv run blhost -u $VID_PID list-memory
|
|
||||||
|
|
||||||
# Прошить firmware_test
|
# bootloader
|
||||||
uv run blhost -u $VID_PID flash-erase-all
|
uv run python3 flash_usb.py --firmware bootloader --build-type Release
|
||||||
uv run blhost -u $VID_PID write-memory 0x60000000 \
|
|
||||||
../../build/Debug/firmware_test_bootable.bin
|
|
||||||
uv run blhost -u $VID_PID reset
|
|
||||||
|
|
||||||
# Загрузить в RAM без записи во Flash (для быстрой отладки)
|
|
||||||
uv run blhost -u $VID_PID load-image ../../build/Debug/firmware_test_bootable.bin
|
|
||||||
```
|
```
|
||||||
|
|
||||||
После прошивки вернуть `BOOT_MOD_1 = 0` (подтянуть к GND) для нормального старта из Flash.
|
После прошивки: вернуть `BOOT_MOD_1` к `GND`, Reset — плата стартует из Flash.
|
||||||
|
|
||||||
## Удалённая прошивка (сервер)
|
### Последовательность команд внутри скрипта
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Из devcontainer или локально — копируем образ на сервер и прошиваем
|
Плата в SDP режиме (1FC9:0130)
|
||||||
./tools/host/flash_remote.sh firmware_test Debug
|
│
|
||||||
|
├─ sdphost write-file 0x20001C00 ivt_flashloader.bin
|
||||||
|
└─ sdphost jump-address 0x20001C00
|
||||||
|
│
|
||||||
|
│ (ожидание до 10с пока Flashloader поднимется на 15A2:0073)
|
||||||
|
│
|
||||||
|
Flashloader (15A2:0073)
|
||||||
|
│
|
||||||
|
│ Шаг 1 — инициализация FlexSPI NOR контроллера
|
||||||
|
├─ blhost fill-memory 0x2000 4 0xC0000007 word
|
||||||
|
├─ blhost configure-memory 9 0x2000
|
||||||
|
│
|
||||||
|
│ Шаг 2 — стирание Flash
|
||||||
|
├─ blhost flash-erase-region 0x60000000 <size> 0 (memoryId=0, XIP)
|
||||||
|
│
|
||||||
|
│ Шаг 3 — запись FCB в 0x60000000
|
||||||
|
│ (ПОСЛЕ стирания! Flashloader генерирует FCB из параметров шага 1)
|
||||||
|
├─ blhost fill-memory 0x2000 4 0xF000000F word
|
||||||
|
├─ blhost configure-memory 9 0x2000
|
||||||
|
│
|
||||||
|
│ Шаг 4 — запись HAB образа начиная с 0x60001000
|
||||||
|
├─ blhost write-memory 0x60001000 *_hab.bin 0 (memoryId=0, XIP)
|
||||||
|
└─ blhost reset
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Почему FCB не в образе?**
|
||||||
|
> Flashloader генерирует FCB автоматически из параметров FlexSPI (option word
|
||||||
|
> `0xC0000007`). Запись FCB через `0xF000000F` — это отдельная команда,
|
||||||
|
> выполняемая строго после `flash-erase-region`, иначе FCB будет затёрт следующим
|
||||||
|
> стиранием.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## DCD — инициализация SDRAM
|
||||||
|
|
||||||
|
`dcd/dcd.bin` — бинарный блоб команд, который BootROM выполняет до передачи
|
||||||
|
управления прошивке. Инициализирует PLL, CCM clock gates, SEMC контроллер
|
||||||
|
и микросхему SDRAM (MT48LCxxM4).
|
||||||
|
|
||||||
|
Файл хранится в репозитории в бинарном виде и **не требует пересборки** — он
|
||||||
|
меняется только при изменении схемотехники.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Цель: MT48LC16M16A2P-6A, 32 MB, шина 16 бит, CS0
|
||||||
|
SEMC BR0: base=0x80000000, size=32MB, VLD=1
|
||||||
|
SEMC BR1–BR3: VLD=0 (один чип, один CS)
|
||||||
|
```
|
||||||
|
|
||||||
|
Использование DCD по прошивкам:
|
||||||
|
|
||||||
|
| Прошивка | DCD | Причина |
|
||||||
|
|---|---|---|
|
||||||
|
| `firmware_test` | ✓ | тесты работают с SDRAM |
|
||||||
|
| `app` | ✓ | FreeRTOS heap и буферы LCDIF размещены в SDRAM |
|
||||||
|
| `bootloader` | ✗ | загрузчик не использует SDRAM, инициализация в app |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Flashloader
|
||||||
|
|
||||||
|
`dcd/ivt_flashloader.bin` — NXP-программа, загружаемая в RAM через SDP.
|
||||||
|
Предоставляет `blhost` доступ к Flash, которого нет через BootROM напрямую.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Entry point: 0x20002401
|
||||||
|
Загрузка по: 0x20001C00
|
||||||
|
VID:PID после старта: 15A2:0073
|
||||||
|
Источник: MCUXpresso Secure Provisioning Tool 25.12
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Диагностика
|
## Диагностика
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Список поддерживаемых семейств (проверка установки)
|
# Найти подключённые NXP устройства
|
||||||
uv run nxpimage bootable-image get-families
|
uv run nxpdevscan
|
||||||
|
|
||||||
# Список доступных шаблонов для mimxrt1050
|
# Проверить связь с BootROM через SDP
|
||||||
uv run nxpimage bootable-image list-templates -f mimxrt1050
|
sdphost -u 0x1FC9,0x0130 -- error-status
|
||||||
|
|
||||||
# Версия SPSDK
|
# Проверить что Flashloader отвечает (после jump-address)
|
||||||
|
blhost -u 0x15A2,0x0073 -- get-property 1 0
|
||||||
|
|
||||||
|
# Версии инструментов
|
||||||
uv run nxpimage --version
|
uv run nxpimage --version
|
||||||
uv run blhost --version
|
uv run blhost --version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Типичные ошибки
|
||||||
|
|
||||||
|
| Симптом | Причина | Решение |
|
||||||
|
|---|---|---|
|
||||||
|
| `USB HID device not found: 1FC9:0130` | Плата не в SDP режиме | Проверить `BOOT_MOD_1` → 3V3 и Reset |
|
||||||
|
| Flashloader timeout после jump | `ivt_flashloader.bin` повреждён или не тот | Взять из SPT 25.12 |
|
||||||
|
| Плата не стартует после прошивки | `BOOT_MOD_1` не переключён обратно | Вернуть `BOOT_MOD_1` → GND, Reset |
|
||||||
|
| Плата зависает сразу после старта | DCD завис (неверный `dcd.bin`) | Использовать только верифицированный `dcd.bin` |
|
||||||
|
| Плата стартует, периферия не работает | CCM clock gates в DCD отключают нужные клоки | Проверить `dcd.bin` — только верифицированный вариант |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Обновление зависимостей
|
## Обновление зависимостей
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd tools/host
|
cd tools/host
|
||||||
uv add "spsdk==X.Y.Z"
|
uv add "spsdk==X.Y.Z"
|
||||||
uv sync
|
uv sync
|
||||||
git add uv.lock
|
git add uv.lock pyproject.toml
|
||||||
```
|
```
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -1,216 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
dcd_cfg_to_bin.py — конвертация DCD .cfg (NXP Config Tools) в .bin (BootROM формат)
|
|
||||||
|
|
||||||
Формат DCD бинарника (IMX RT RM, Chapter 9.7):
|
|
||||||
[Header]
|
|
||||||
0xD2 — DCD tag
|
|
||||||
length[1:0] — общая длина в байтах (big-endian, 2 байта)
|
|
||||||
0x41 — version
|
|
||||||
|
|
||||||
[Commands] — последовательно:
|
|
||||||
Write Data (0xCC):
|
|
||||||
0xCC tag, length BE16, parameter (ширина: 4=word)
|
|
||||||
[addr BE32, value BE32] × N — группируются подряд идущие записи
|
|
||||||
|
|
||||||
Check Bits Set (0xCF) — wait_until (expr & mask) != 0:
|
|
||||||
0xCF tag, 0x000C length, parameter (4=word)
|
|
||||||
addr BE32, mask BE32, count BE32 (0 = бесконечно)
|
|
||||||
|
|
||||||
Использование:
|
|
||||||
python3 dcd_cfg_to_bin.py dcd.cfg dcd.bin
|
|
||||||
python3 dcd_cfg_to_bin.py dcd.cfg # выведет dcd.bin рядом с cfg
|
|
||||||
"""
|
|
||||||
|
|
||||||
import re
|
|
||||||
import struct
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import Union
|
|
||||||
|
|
||||||
# ─── Константы DCD ────────────────────────────────────────────────────────────
|
|
||||||
DCD_TAG = 0xD2
|
|
||||||
DCD_VERSION = 0x41
|
|
||||||
CMD_WRITE = 0xCC
|
|
||||||
CMD_CHECK_SET = 0xCF # wait_until (reg & mask) != 0
|
|
||||||
CMD_CHECK_CLEAR = 0xD0 # wait_until (reg & mask) == 0
|
|
||||||
WIDTH_WORD = 0x04 # 32-bit
|
|
||||||
|
|
||||||
|
|
||||||
# ─── Типы команд ──────────────────────────────────────────────────────────────
|
|
||||||
@dataclass
|
|
||||||
class WriteEntry:
|
|
||||||
addr: int
|
|
||||||
value: int
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class WriteCmd:
|
|
||||||
entries: list[WriteEntry] = field(default_factory=list)
|
|
||||||
|
|
||||||
def to_bytes(self) -> bytes:
|
|
||||||
length = 4 + len(self.entries) * 8
|
|
||||||
# NXP RM format: Tag(1) | Length(2 BE) | Parameter(1)
|
|
||||||
hdr = struct.pack(">BHB", CMD_WRITE, length, WIDTH_WORD)
|
|
||||||
data = b"".join(
|
|
||||||
struct.pack(">II", e.addr, e.value) for e in self.entries
|
|
||||||
)
|
|
||||||
return hdr + data
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CheckCmd:
|
|
||||||
addr: int
|
|
||||||
mask: int
|
|
||||||
check_set: bool = True # True = wait != 0, False = wait == 0
|
|
||||||
|
|
||||||
def to_bytes(self) -> bytes:
|
|
||||||
tag = CMD_CHECK_SET if self.check_set else CMD_CHECK_CLEAR
|
|
||||||
# NXP RM format: Tag(1) | Length(2 BE=12) | Parameter(1) | Addr(4) | Mask(4)
|
|
||||||
# Parameter: bits[2:0]=width(4=32bit), bit[3]=check_set → 0x1C / check_clear → 0x14
|
|
||||||
# No count field — poll indefinitely is the default (length=12, not 16)
|
|
||||||
param = 0x1C if self.check_set else 0x14
|
|
||||||
length = 12 # 4 header + 4 addr + 4 mask
|
|
||||||
return struct.pack(">BHBII", tag, length, param, self.addr, self.mask)
|
|
||||||
|
|
||||||
|
|
||||||
# ─── Парсер .cfg ─────────────────────────────────────────────────────────────
|
|
||||||
def parse_hex(s: str) -> int:
|
|
||||||
return int(s, 16) if s.startswith("0x") or s.startswith("0X") else int(s)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_cfg(text: str) -> list[Union[WriteCmd, CheckCmd]]:
|
|
||||||
"""
|
|
||||||
Парсит .cfg и возвращает список команд DCD.
|
|
||||||
Соседние write-записи группируются в одну WriteCmd.
|
|
||||||
"""
|
|
||||||
# Убираем блочные комментарии /* ... */
|
|
||||||
text = re.sub(r"/\*.*?\*/", "", text, flags=re.DOTALL)
|
|
||||||
# Убираем строчные комментарии // ...
|
|
||||||
text = re.sub(r"//[^\n]*", "", text)
|
|
||||||
|
|
||||||
commands: list[Union[WriteCmd, CheckCmd]] = []
|
|
||||||
current_write: WriteCmd | None = None
|
|
||||||
|
|
||||||
# Паттерн: *(uint32_t*)0xADDR = 0xVALUE;
|
|
||||||
re_write = re.compile(
|
|
||||||
r"\*\s*\(\s*uint32_t\s*\*\s*\)\s*(0x[0-9A-Fa-f]+)\s*=\s*(0x[0-9A-Fa-f]+)\s*;"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Паттерн: (*(uint32_t*)0xADDR & 0xMASK) != 0;
|
|
||||||
re_check_set = re.compile(
|
|
||||||
r"\(\s*\*\s*\(\s*uint32_t\s*\*\s*\)\s*(0x[0-9A-Fa-f]+)\s*&\s*(0x[0-9A-Fa-f]+)\s*\)\s*!=\s*0\s*;"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Паттерн: (*(uint32_t*)0xADDR & 0xMASK) == 0;
|
|
||||||
re_check_clear = re.compile(
|
|
||||||
r"\(\s*\*\s*\(\s*uint32_t\s*\*\s*\)\s*(0x[0-9A-Fa-f]+)\s*&\s*(0x[0-9A-Fa-f]+)\s*\)\s*==\s*0\s*;"
|
|
||||||
)
|
|
||||||
|
|
||||||
for line in text.splitlines():
|
|
||||||
line = line.strip()
|
|
||||||
if not line:
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = re_write.search(line)
|
|
||||||
if m:
|
|
||||||
addr = parse_hex(m.group(1))
|
|
||||||
value = parse_hex(m.group(2))
|
|
||||||
if current_write is None:
|
|
||||||
current_write = WriteCmd()
|
|
||||||
commands.append(current_write)
|
|
||||||
current_write.entries.append(WriteEntry(addr, value))
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = re_check_set.search(line)
|
|
||||||
if m:
|
|
||||||
if current_write is not None:
|
|
||||||
current_write = None # разрываем группу write
|
|
||||||
addr = parse_hex(m.group(1))
|
|
||||||
mask = parse_hex(m.group(2))
|
|
||||||
commands.append(CheckCmd(addr, mask, check_set=True))
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = re_check_clear.search(line)
|
|
||||||
if m:
|
|
||||||
if current_write is not None:
|
|
||||||
current_write = None
|
|
||||||
addr = parse_hex(m.group(1))
|
|
||||||
mask = parse_hex(m.group(2))
|
|
||||||
commands.append(CheckCmd(addr, mask, check_set=False))
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Не write и не check — разрываем текущую write-группу
|
|
||||||
# (на случай если между записями есть другой синтаксис)
|
|
||||||
if current_write is not None:
|
|
||||||
current_write = None
|
|
||||||
|
|
||||||
return commands
|
|
||||||
|
|
||||||
|
|
||||||
# ─── Сборка бинарника ─────────────────────────────────────────────────────────
|
|
||||||
def build_dcd_binary(commands: list[Union[WriteCmd, CheckCmd]]) -> bytes:
|
|
||||||
body = b"".join(cmd.to_bytes() for cmd in commands)
|
|
||||||
total_length = 4 + len(body) # 4 байта header
|
|
||||||
# NXP RM format: Tag(1) | Length(2 BE) | Version(1)
|
|
||||||
header = struct.pack(">BHB", DCD_TAG, total_length, DCD_VERSION)
|
|
||||||
return header + body
|
|
||||||
|
|
||||||
|
|
||||||
# ─── Отчёт ────────────────────────────────────────────────────────────────────
|
|
||||||
def print_report(commands: list[Union[WriteCmd, CheckCmd]], out_size: int) -> None:
|
|
||||||
writes = sum(1 for c in commands if isinstance(c, WriteCmd))
|
|
||||||
checks = sum(1 for c in commands if isinstance(c, CheckCmd))
|
|
||||||
entries = sum(len(c.entries) for c in commands if isinstance(c, WriteCmd))
|
|
||||||
|
|
||||||
print(f"\n{'─'*52}")
|
|
||||||
print(f" DCD конвертация завершена")
|
|
||||||
print(f"{'─'*52}")
|
|
||||||
print(f" Write команд (групп) : {writes}")
|
|
||||||
print(f" Write записей всего : {entries}")
|
|
||||||
print(f" Check команд : {checks}")
|
|
||||||
print(f" Размер бинарника : {out_size} байт (0x{out_size:04X})")
|
|
||||||
print(f"{'─'*52}")
|
|
||||||
|
|
||||||
print("\n Команды:")
|
|
||||||
for i, cmd in enumerate(commands):
|
|
||||||
if isinstance(cmd, WriteCmd):
|
|
||||||
print(f" [{i:02d}] WRITE × {len(cmd.entries):3d} entries"
|
|
||||||
f" (0x{cmd.entries[0].addr:08X} … 0x{cmd.entries[-1].addr:08X})")
|
|
||||||
else:
|
|
||||||
kind = "CHECK_SET (!= 0)" if cmd.check_set else "CHECK_CLR (== 0)"
|
|
||||||
print(f" [{i:02d}] {kind} addr=0x{cmd.addr:08X} mask=0x{cmd.mask:08X}")
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
# ─── main ─────────────────────────────────────────────────────────────────────
|
|
||||||
def main():
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print(__doc__)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
cfg_path = Path(sys.argv[1])
|
|
||||||
if not cfg_path.exists():
|
|
||||||
print(f"[ERROR] Файл не найден: {cfg_path}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
out_path = Path(sys.argv[2]) if len(sys.argv) >= 3 else cfg_path.with_suffix(".bin")
|
|
||||||
|
|
||||||
text = cfg_path.read_text(encoding="utf-8", errors="replace")
|
|
||||||
commands = parse_cfg(text)
|
|
||||||
|
|
||||||
if not commands:
|
|
||||||
print("[ERROR] Ни одной команды не найдено. Проверь формат .cfg файла.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
binary = build_dcd_binary(commands)
|
|
||||||
out_path.write_bytes(binary)
|
|
||||||
|
|
||||||
print(f"[OK] Входной файл : {cfg_path}")
|
|
||||||
print(f"[OK] Выходной файл: {out_path}")
|
|
||||||
print_report(commands, len(binary))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
|
|
@ -1,232 +0,0 @@
|
||||||
[DCD Descriptor]
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Clock Init
|
|
||||||
// MT48LC16M16A2 SDRAM on MIMXRT1052CVJ5B
|
|
||||||
//
|
|
||||||
// Включаем только необходимые тактовые домены (fix 6):
|
|
||||||
// CCM_CCGR0: биты [1:0]=11 (aips_tz1), биты [3:2]=11 (aips_tz2) — доступ к периферии
|
|
||||||
// CCM_CCGR2: биты [29:28]=11 (iomuxc) — конфигурация пинов
|
|
||||||
// CCM_CCGR3: биты [5:4]=11 (semc) — контроллер SDRAM
|
|
||||||
// CCM_CCGR4: биты [3:2]=11 (iomuxc_gpr) — GPR регистры
|
|
||||||
// CCM_CCGR5: биты [1:0]=11 (rom) — BootROM
|
|
||||||
//
|
|
||||||
// ВАЖНО: если после изменения плата не стартует — проверь по RM Table 18-5
|
|
||||||
// (CCM Clock Gating Register) и вернись к 0xFFFFFFFF для отладки.
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
*(uint32_t*)0x400FC068 = 0x0000000F; // CCM_CCGR0: aips_tz1 + aips_tz2
|
|
||||||
*(uint32_t*)0x400FC06C = 0x00000000; // CCM_CCGR1: не нужен для DCD
|
|
||||||
*(uint32_t*)0x400FC070 = 0x30000000; // CCM_CCGR2: iomuxc (CG14, bits[29:28])
|
|
||||||
*(uint32_t*)0x400FC074 = 0x00000030; // CCM_CCGR3: semc (CG2, bits[5:4])
|
|
||||||
*(uint32_t*)0x400FC078 = 0x0000000C; // CCM_CCGR4: iomuxc_gpr (CG1, bits[3:2])
|
|
||||||
*(uint32_t*)0x400FC07C = 0x00000003; // CCM_CCGR5: rom (CG0, bits[1:0])
|
|
||||||
*(uint32_t*)0x400FC080 = 0x00000000; // CCM_CCGR6: не нужен для DCD
|
|
||||||
|
|
||||||
// PLL_SYS: 528 MHz (24 MHz * 22), DIV_SELECT=1 → Fvco=528MHz
|
|
||||||
*(uint32_t*)0x400D8030 = 0x00002001;
|
|
||||||
|
|
||||||
// Ждём lock PLL_SYS (bit 31 = LOCK) перед переключением источника тактирования (fix 3)
|
|
||||||
(*(uint32_t*)0x400D8030 & 0x80000000) != 0;
|
|
||||||
|
|
||||||
// PFD2 = 528 * 18 / 0x23(35) = ~271 MHz... нет.
|
|
||||||
// PFD528[PFD2_FRAC] = 0x23 = 35 → Fout = 528 * 18 / 35 = ~271?
|
|
||||||
// Фактически 0x00230000 → PFD2_FRAC = 0x23 = 35 → F = 528*18/35 ≈ 271 МГц
|
|
||||||
// Но для SEMC @ 133 МГц нужен делитель CCM_CBCDR[SEMC_PODF].
|
|
||||||
// Проверь соответствие с clock_config.c!
|
|
||||||
*(uint32_t*)0x400D8100 = 0x00230000; // CCM_ANALOG_PFD_528: PFD2 = 133 MHz
|
|
||||||
|
|
||||||
// CCM_CBCDR: SEMC_CLK_SEL=1 (PLL2_PFD2), SEMC_ALT_CLK_SEL=0, SEMC_PODF=1 (делитель /2)
|
|
||||||
// → SEMC clock = 133 / 2 = 66.5 МГц
|
|
||||||
// Если нужно 133 МГц — SEMC_PODF=0 (делитель /1), но убедись что SDRAM выдержит
|
|
||||||
*(uint32_t*)0x400FC014 = 0x00010D40; // CCM_CBCDR
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// SDRAM Init — Configure IOMUXC for SEMC pins
|
|
||||||
// MT48LC16M16A2: 16Mx16bit, 4 Banks, LVTTL
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// IOMUXC — MUX mode: все пины SEMC в режиме ALT0 (SEMC функция)
|
|
||||||
*(uint32_t*)0x401F8014 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8018 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F801C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8020 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8024 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8028 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F802C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8030 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8034 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8038 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F803C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8040 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8044 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8048 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F804C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8050 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8054 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8058 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F805C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8060 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8064 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8068 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F806C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8070 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8074 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8078 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F807C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8080 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8084 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8088 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F808C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8090 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8094 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F8098 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F809C = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F80A0 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F80A4 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F80A8 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F80AC = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F80B0 = 0x00000010; // SEMC_DATA15: SION=1 (software input on)
|
|
||||||
*(uint32_t*)0x401F80B4 = 0x00000000;
|
|
||||||
*(uint32_t*)0x401F80B8 = 0x00000000;
|
|
||||||
|
|
||||||
// IOMUXC — PAD ctrl: 0x000110F9
|
|
||||||
// SRE=1 (Fast Slew Rate)
|
|
||||||
// DSE=7 (Drive Strength: R0/7 — максимальный)
|
|
||||||
// SPEED=3 (200 MHz)
|
|
||||||
// ODE=0 (Open Drain disabled)
|
|
||||||
// PKE=1 (Pull/Keeper enabled)
|
|
||||||
// PUE=1 (Pull — не Keeper)
|
|
||||||
// PUS=0 (100K pull-down)
|
|
||||||
// HYS=0 (Hysteresis disabled)
|
|
||||||
*(uint32_t*)0x401F8204 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8208 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F820C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8210 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8214 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8218 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F821C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8220 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8224 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8228 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F822C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8230 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8234 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8238 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F823C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8240 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8244 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8248 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F824C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8250 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8254 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8258 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F825C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8260 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8264 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8268 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F826C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8270 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8274 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8278 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F827C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8280 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8284 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8288 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F828C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8290 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8294 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F8298 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F829C = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F82A0 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F82A4 = 0x000110F9;
|
|
||||||
*(uint32_t*)0x401F82A8 = 0x000110F9;
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// SEMC Controller — конфигурация для MT48LC16M16A2
|
|
||||||
// Базовый адрес SDRAM: 0x80000000
|
|
||||||
// Размер: 32 MB (MT48LC16M16A2: 16M × 16bit = 32 MB)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// SEMC_MCR: MDIS=0, BTO=0x1F (timeout), DQSMD=1 (DQS internal loop)
|
|
||||||
*(uint32_t*)0x402F0000 = 0x10000004;
|
|
||||||
|
|
||||||
// SEMC_BMCR0 & BMCR1: burst весовые коэффициенты
|
|
||||||
// 0x00000081: WQOS=1, RQOS=0, AGE=0, BSTLEN=0x10 (16 burst)
|
|
||||||
*(uint32_t*)0x402F0008 = 0x00000081; // SEMC_BMCR0
|
|
||||||
*(uint32_t*)0x402F000C = 0x00000081; // SEMC_BMCR1
|
|
||||||
|
|
||||||
// SEMC_BR0..BR7 — Base Register для каждого region
|
|
||||||
// BR0: SDRAM @ 0x80000000, размер 32MB (MR=0x1B → 32MB), VLD=1
|
|
||||||
*(uint32_t*)0x402F0010 = 0x8000001B; // BR0: SDRAM CS0, 0x80000000, 32MB
|
|
||||||
*(uint32_t*)0x402F0014 = 0x82000000; // BR1: SDRAM CS1 (если есть)
|
|
||||||
*(uint32_t*)0x402F0018 = 0x84000000; // BR2
|
|
||||||
*(uint32_t*)0x402F001C = 0x86000000; // BR3
|
|
||||||
*(uint32_t*)0x402F0020 = 0x90000021; // BR4: NAND
|
|
||||||
*(uint32_t*)0x402F0024 = 0xA0000019; // BR5: NOR/SRAM
|
|
||||||
*(uint32_t*)0x402F0028 = 0xA8000017; // BR6
|
|
||||||
*(uint32_t*)0x402F002C = 0xA900001B; // BR7
|
|
||||||
*(uint32_t*)0x402F0030 = 0x00000021; // BR8
|
|
||||||
|
|
||||||
// SEMC_INTEN: прерывания отключены
|
|
||||||
*(uint32_t*)0x402F0004 = 0x000079A8;
|
|
||||||
|
|
||||||
// SEMC_SDRAMCR0: тайминги MT48LC16M16A2 @ 133MHz
|
|
||||||
// PS=1 (16-bit data bus), BL=3 (Burst Length 8), COL=2 (9-bit col addr),
|
|
||||||
// CL=3 (CAS Latency 3)
|
|
||||||
*(uint32_t*)0x402F0040 = 0x00000F31;
|
|
||||||
|
|
||||||
// SEMC_SDRAMCR1
|
|
||||||
// PRE2ACT=2, ACT2RW=2, RFRC=9 (tRFC), WRC=2, CKEOFF=2, ACT2PRE=6
|
|
||||||
*(uint32_t*)0x402F0044 = 0x00652922;
|
|
||||||
|
|
||||||
// SEMC_SDRAMCR2: Refresh rate
|
|
||||||
// MT48LC16M16A2: 4096 refresh cycles / 64ms → ~15.6 мкс @ 133MHz
|
|
||||||
// SRRC=0x02 (самообновление), REF2REF=0x02, ACT2ACT=0x01
|
|
||||||
*(uint32_t*)0x402F0048 = 0x00020201;
|
|
||||||
|
|
||||||
// SEMC_SDRAMCR3
|
|
||||||
// REBL=1, PRESCALE=0x21, RT=0x3D, UT=0x0F
|
|
||||||
*(uint32_t*)0x402F004C = 0x08193D0F;
|
|
||||||
|
|
||||||
// SEMC_IOCR
|
|
||||||
*(uint32_t*)0x402F0080 = 0x00000021;
|
|
||||||
*(uint32_t*)0x402F0084 = 0x00888888;
|
|
||||||
|
|
||||||
// SEMC_IPTXDAT / IPRXDAT placeholder
|
|
||||||
*(uint32_t*)0x402F0094 = 0x00000002;
|
|
||||||
*(uint32_t*)0x402F0098 = 0x00000000;
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// SDRAM Init Sequence (JEDEC: Precharge All → Auto-Refresh × 2 → Mode Register Set)
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
// SEMC_IPCR0: IP command target адрес = начало SDRAM
|
|
||||||
*(uint32_t*)0x402F0090 = 0x80000000;
|
|
||||||
|
|
||||||
// IPCMD: Precharge All (команда 0xF)
|
|
||||||
*(uint32_t*)0x402F009C = 0xA55A000F;
|
|
||||||
// Ждём завершения: SEMC_INTR[IPCMDDONE] (bit 0)
|
|
||||||
(*(uint32_t*)0x402F003C & 0x01) != 0;
|
|
||||||
|
|
||||||
// IPCMD: Auto-Refresh #1 (команда 0xC)
|
|
||||||
*(uint32_t*)0x402F0090 = 0x80000000;
|
|
||||||
*(uint32_t*)0x402F009C = 0xA55A000C;
|
|
||||||
(*(uint32_t*)0x402F003C & 0x01) != 0;
|
|
||||||
|
|
||||||
// IPCMD: Auto-Refresh #2
|
|
||||||
*(uint32_t*)0x402F0090 = 0x80000000;
|
|
||||||
*(uint32_t*)0x402F009C = 0xA55A000C;
|
|
||||||
(*(uint32_t*)0x402F003C & 0x01) != 0;
|
|
||||||
|
|
||||||
// Mode Register Set:
|
|
||||||
// MRS = 0x33: Burst Length=8 (BL=3), Burst Type=Sequential, CAS Latency=3
|
|
||||||
*(uint32_t*)0x402F00A0 = 0x00000033;
|
|
||||||
*(uint32_t*)0x402F0090 = 0x80000000;
|
|
||||||
// IPCMD: Mode Register Set (команда 0xA)
|
|
||||||
*(uint32_t*)0x402F009C = 0xA55A000A;
|
|
||||||
(*(uint32_t*)0x402F003C & 0x01) != 0;
|
|
||||||
|
|
||||||
// SEMC_SDRAMCR3: финальное значение Refresh Rate после инит-последовательности
|
|
||||||
// Переключаемся с медленного (init) refresh на рабочий
|
|
||||||
*(uint32_t*)0x402F004C = 0x50210A09;
|
|
||||||
BIN
tools/host/dcd/ivt_flashloader.bin
Normal file
BIN
tools/host/dcd/ivt_flashloader.bin
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -1,152 +0,0 @@
|
||||||
# =============================================================================
|
|
||||||
# FCB — Flash Configuration Block
|
|
||||||
# Чип: Winbond W25Q128FVSSIG (64 Mbit = 8 MB), Quad SPI
|
|
||||||
# Режим: Fast Read Quad I/O (0xEB), 133 MHz, 4-line
|
|
||||||
# Цель: MIMXRT1052CVJ5B (family: mimxrt1050 в SPSDK 3.7)
|
|
||||||
#
|
|
||||||
# LUT-последовательности:
|
|
||||||
# Seq 0: Fast Read Quad I/O (0xEB) — основное XIP-чтение
|
|
||||||
# Seq 1: Read Status Reg 1 (0x05) — опрос WIP бита
|
|
||||||
# Seq 2: Write Enable (0x06) — перед любой записью/стиранием
|
|
||||||
# Seq 3: Erase Sector 4KB (0x20) — стирание сектора
|
|
||||||
# Seq 4: Write SR2 (0x31) — установка QE бита (вызов при старте)
|
|
||||||
# Seq 5: Page Program Quad (0x32) — запись страницы в Quad режиме
|
|
||||||
# Seq 11: Chip Erase (0x60) — полное стирание чипа
|
|
||||||
# Seq 12: Read Status Reg 1 (0x05) — дублирует seq1, для blhost
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
family: mimxrt1050
|
|
||||||
revision: latest
|
|
||||||
type: flexspi_nor
|
|
||||||
|
|
||||||
fcb_settings:
|
|
||||||
tag: '0x42464346' # 'FCFB' — magic, фиксировано
|
|
||||||
version: '0x56010400' # Version 1.4 (актуально для SPSDK 3.7)
|
|
||||||
|
|
||||||
readSampleClkSrc: '0x01' # loopback from DQS pad
|
|
||||||
csHoldTime: '0x03'
|
|
||||||
csSetupTime: '0x03'
|
|
||||||
columnAddressWidth: '0x03'
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# QE bit enable — W25Q128 Status Register 2, bit 1
|
|
||||||
# BootROM выполнит Write Enable (seq 2) + Write SR2 (seq 4) при старте.
|
|
||||||
# deviceModeArg = 0x02 → SR2 = 0b00000010 (QE=1)
|
|
||||||
# waitTimeCfgCommands = 30 × 100us = 3ms (достаточно для записи SR)
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
deviceModeCfgEnable: '0x01'
|
|
||||||
deviceModeType: '0x01'
|
|
||||||
waitTimeCfgCommands: '0x001E'
|
|
||||||
deviceModeSeq:
|
|
||||||
seqNum: 1
|
|
||||||
seqId: 4 # → Seq 4: Write SR2 (0x31)
|
|
||||||
deviceModeArg: '0x00000002' # SR2 = 0x02 → QE=1
|
|
||||||
|
|
||||||
deviceType: '0x01' # Serial NOR
|
|
||||||
sflashPadType: '0x04' # Quad — 4 линии данных (IO0..IO3)
|
|
||||||
serialClkFreq: '0x07' # 133 MHz
|
|
||||||
sflashA1Size: '0x01000000' # 16 MB — W25Q128FVSSIG (128 Mbit / 8)
|
|
||||||
|
|
||||||
pageSize: '0x00000100' # 256 байт — стандарт для W25Q128
|
|
||||||
sectorSize: '0x00001000' # 4 KB — минимальная единица стирания
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# LUT — Look-Up Table
|
|
||||||
# Каждая последовательность: 8 инструкций (instr0..instr7)
|
|
||||||
# Неиспользуемые инструкции = STOP (значение по умолчанию, можно не писать)
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ── Seq 0: Fast Read Quad I/O (0xEB) ───────────────────────────────────────
|
|
||||||
# CMD(×1) 0xEB → RADDR(×4) 24bit → DUMMY(×4) 6cycles → READ(×4)
|
|
||||||
lookupTable_seq0_instr0:
|
|
||||||
OPERAND: 0xEB
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq0_instr1:
|
|
||||||
OPERAND: 0x18 # 24-bit address
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: RADDR_SDR
|
|
||||||
lookupTable_seq0_instr2:
|
|
||||||
OPERAND: 0x06 # 6 dummy cycles @ 133MHz (4 mode + 2 dummy)
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: DUMMY_SDR
|
|
||||||
lookupTable_seq0_instr3:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: READ_SDR
|
|
||||||
|
|
||||||
# ── Seq 1: Read Status Register 1 (0x05) ───────────────────────────────────
|
|
||||||
# CMD(×1) 0x05 → READ(×1) 1byte
|
|
||||||
lookupTable_seq1_instr0:
|
|
||||||
OPERAND: 0x05
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq1_instr1:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: READ_SDR
|
|
||||||
|
|
||||||
# ── Seq 2: Write Enable (0x06) ──────────────────────────────────────────────
|
|
||||||
# CMD(×1) 0x06
|
|
||||||
lookupTable_seq2_instr0:
|
|
||||||
OPERAND: 0x06
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
|
|
||||||
# ── Seq 3: Erase Sector 4KB (0x20) ─────────────────────────────────────────
|
|
||||||
# CMD(×1) 0x20 → RADDR(×4) 24bit
|
|
||||||
lookupTable_seq3_instr0:
|
|
||||||
OPERAND: 0x20
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq3_instr1:
|
|
||||||
OPERAND: 0x18
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: RADDR_SDR
|
|
||||||
|
|
||||||
# ── Seq 4: Write Status Register 2 (0x31) — установка QE бита ──────────────
|
|
||||||
# CMD(×1) 0x31 → WRITE(×1) 1byte
|
|
||||||
# Вызывается через deviceModeSeq при инициализации BootROM.
|
|
||||||
# deviceModeArg (0x02) записывается как аргумент.
|
|
||||||
lookupTable_seq4_instr0:
|
|
||||||
OPERAND: 0x31
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq4_instr1:
|
|
||||||
OPERAND: 0x01 # записать 1 байт
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: WRITE_SDR
|
|
||||||
|
|
||||||
# ── Seq 5: Page Program Quad Input (0x32) ──────────────────────────────────
|
|
||||||
# CMD(×1) 0x32 → RADDR(×1) 24bit → WRITE(×4)
|
|
||||||
lookupTable_seq5_instr0:
|
|
||||||
OPERAND: 0x32
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq5_instr1:
|
|
||||||
OPERAND: 0x18
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: RADDR_SDR
|
|
||||||
lookupTable_seq5_instr2:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: WRITE_SDR
|
|
||||||
|
|
||||||
# Seq 6..10: не используются (STOP по умолчанию)
|
|
||||||
|
|
||||||
# ── Seq 11: Chip Erase (0x60) ───────────────────────────────────────────────
|
|
||||||
# CMD(×1) 0x60
|
|
||||||
lookupTable_seq11_instr0:
|
|
||||||
OPERAND: 0x60
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
|
|
||||||
# ── Seq 12: Read Status Register 1 (дубль для blhost) ──────────────────────
|
|
||||||
lookupTable_seq12_instr0:
|
|
||||||
OPERAND: 0x05
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq12_instr1:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: READ_SDR
|
|
||||||
|
|
@ -1,152 +0,0 @@
|
||||||
# =============================================================================
|
|
||||||
# FCB — Flash Configuration Block
|
|
||||||
# Чип: Winbond W25Q64FVSSIG (64 Mbit = 8 MB), Quad SPI
|
|
||||||
# Режим: Fast Read Quad I/O (0xEB), 133 MHz, 4-line
|
|
||||||
# Цель: MIMXRT1052CVJ5B (family: mimxrt1050 в SPSDK 3.7)
|
|
||||||
#
|
|
||||||
# LUT-последовательности:
|
|
||||||
# Seq 0: Fast Read Quad I/O (0xEB) — основное XIP-чтение
|
|
||||||
# Seq 1: Read Status Reg 1 (0x05) — опрос WIP бита
|
|
||||||
# Seq 2: Write Enable (0x06) — перед любой записью/стиранием
|
|
||||||
# Seq 3: Erase Sector 4KB (0x20) — стирание сектора
|
|
||||||
# Seq 4: Write SR2 (0x31) — установка QE бита (вызов при старте)
|
|
||||||
# Seq 5: Page Program Quad (0x32) — запись страницы в Quad режиме
|
|
||||||
# Seq 11: Chip Erase (0x60) — полное стирание чипа
|
|
||||||
# Seq 12: Read Status Reg 1 (0x05) — дублирует seq1, для blhost
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
family: mimxrt1050
|
|
||||||
revision: latest
|
|
||||||
type: flexspi_nor
|
|
||||||
|
|
||||||
fcb_settings:
|
|
||||||
tag: '0x42464346' # 'FCFB' — magic, фиксировано
|
|
||||||
version: '0x56010400' # Version 1.4 (актуально для SPSDK 3.7)
|
|
||||||
|
|
||||||
readSampleClkSrc: '0x01' # loopback from DQS pad
|
|
||||||
csHoldTime: '0x03'
|
|
||||||
csSetupTime: '0x03'
|
|
||||||
columnAddressWidth: '0x03'
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# QE bit enable — W25Q64 Status Register 2, bit 1
|
|
||||||
# BootROM выполнит Write Enable (seq 2) + Write SR2 (seq 4) при старте.
|
|
||||||
# deviceModeArg = 0x02 → SR2 = 0b00000010 (QE=1)
|
|
||||||
# waitTimeCfgCommands = 30 × 100us = 3ms (достаточно для записи SR)
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
deviceModeCfgEnable: '0x01'
|
|
||||||
deviceModeType: '0x01'
|
|
||||||
waitTimeCfgCommands: '0x001E'
|
|
||||||
deviceModeSeq:
|
|
||||||
seqNum: 1
|
|
||||||
seqId: 4 # → Seq 4: Write SR2 (0x31)
|
|
||||||
deviceModeArg: '0x00000002' # SR2 = 0x02 → QE=1
|
|
||||||
|
|
||||||
deviceType: '0x01' # Serial NOR
|
|
||||||
sflashPadType: '0x04' # Quad — 4 линии данных (IO0..IO3)
|
|
||||||
serialClkFreq: '0x07' # 133 MHz
|
|
||||||
sflashA1Size: '0x00800000' # 8 MB — W25Q64FVSSIG (64 Mbit / 8)
|
|
||||||
|
|
||||||
pageSize: '0x00000100' # 256 байт — стандарт для W25Q64
|
|
||||||
sectorSize: '0x00001000' # 4 KB — минимальная единица стирания
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# LUT — Look-Up Table
|
|
||||||
# Каждая последовательность: 8 инструкций (instr0..instr7)
|
|
||||||
# Неиспользуемые инструкции = STOP (значение по умолчанию, можно не писать)
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# ── Seq 0: Fast Read Quad I/O (0xEB) ───────────────────────────────────────
|
|
||||||
# CMD(×1) 0xEB → RADDR(×4) 24bit → DUMMY(×4) 6cycles → READ(×4)
|
|
||||||
lookupTable_seq0_instr0:
|
|
||||||
OPERAND: 0xEB
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq0_instr1:
|
|
||||||
OPERAND: 0x18 # 24-bit address
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: RADDR_SDR
|
|
||||||
lookupTable_seq0_instr2:
|
|
||||||
OPERAND: 0x06 # 6 dummy cycles @ 133MHz (4 mode + 2 dummy)
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: DUMMY_SDR
|
|
||||||
lookupTable_seq0_instr3:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: READ_SDR
|
|
||||||
|
|
||||||
# ── Seq 1: Read Status Register 1 (0x05) ───────────────────────────────────
|
|
||||||
# CMD(×1) 0x05 → READ(×1) 1byte
|
|
||||||
lookupTable_seq1_instr0:
|
|
||||||
OPERAND: 0x05
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq1_instr1:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: READ_SDR
|
|
||||||
|
|
||||||
# ── Seq 2: Write Enable (0x06) ──────────────────────────────────────────────
|
|
||||||
# CMD(×1) 0x06
|
|
||||||
lookupTable_seq2_instr0:
|
|
||||||
OPERAND: 0x06
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
|
|
||||||
# ── Seq 3: Erase Sector 4KB (0x20) ─────────────────────────────────────────
|
|
||||||
# CMD(×1) 0x20 → RADDR(×4) 24bit
|
|
||||||
lookupTable_seq3_instr0:
|
|
||||||
OPERAND: 0x20
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq3_instr1:
|
|
||||||
OPERAND: 0x18
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: RADDR_SDR
|
|
||||||
|
|
||||||
# ── Seq 4: Write Status Register 2 (0x31) — установка QE бита ──────────────
|
|
||||||
# CMD(×1) 0x31 → WRITE(×1) 1byte
|
|
||||||
# Вызывается через deviceModeSeq при инициализации BootROM.
|
|
||||||
# deviceModeArg (0x02) записывается как аргумент.
|
|
||||||
lookupTable_seq4_instr0:
|
|
||||||
OPERAND: 0x31
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq4_instr1:
|
|
||||||
OPERAND: 0x01 # записать 1 байт
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: WRITE_SDR
|
|
||||||
|
|
||||||
# ── Seq 5: Page Program Quad Input (0x32) ──────────────────────────────────
|
|
||||||
# CMD(×1) 0x32 → RADDR(×1) 24bit → WRITE(×4)
|
|
||||||
lookupTable_seq5_instr0:
|
|
||||||
OPERAND: 0x32
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq5_instr1:
|
|
||||||
OPERAND: 0x18
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: RADDR_SDR
|
|
||||||
lookupTable_seq5_instr2:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 4PAD
|
|
||||||
OPERATION_CODE: WRITE_SDR
|
|
||||||
|
|
||||||
# Seq 6..10: не используются (STOP по умолчанию)
|
|
||||||
|
|
||||||
# ── Seq 11: Chip Erase (0x60) ───────────────────────────────────────────────
|
|
||||||
# CMD(×1) 0x60
|
|
||||||
lookupTable_seq11_instr0:
|
|
||||||
OPERAND: 0x60
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
|
|
||||||
# ── Seq 12: Read Status Register 1 (дубль для blhost) ──────────────────────
|
|
||||||
lookupTable_seq12_instr0:
|
|
||||||
OPERAND: 0x05
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: CMD_SDR
|
|
||||||
lookupTable_seq12_instr1:
|
|
||||||
OPERAND: 0x04
|
|
||||||
NUM_PADS: 1PAD
|
|
||||||
OPERATION_CODE: READ_SDR
|
|
||||||
209
tools/host/flash_usb.py
Normal file
209
tools/host/flash_usb.py
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
flash_usb.py — прошивка MIMXRT1052 через USB (BootROM SDP → Flashloader → blhost)
|
||||||
|
|
||||||
|
Использование:
|
||||||
|
python3 flash_usb.py --firmware firmware_test --build-type Debug
|
||||||
|
python3 flash_usb.py --firmware app --build-type Release
|
||||||
|
python3 flash_usb.py --firmware bootloader --build-type Release
|
||||||
|
python3 flash_usb.py --firmware firmware_test --build-type Debug --ram-only
|
||||||
|
|
||||||
|
Шаги:
|
||||||
|
1. Устройство в SDP режиме (VID:PID 1FC9:0130)
|
||||||
|
→ sdphost загружает ivt_flashloader.bin в RAM
|
||||||
|
→ sdphost прыгает на flashloader
|
||||||
|
2. Flashloader запущен (VID:PID 15A2:0073)
|
||||||
|
→ blhost конфигурирует FlexSPI NOR (пишет FCB)
|
||||||
|
→ blhost стирает нужный регион Flash
|
||||||
|
→ blhost пишет HAB образ начиная с 0x60002000
|
||||||
|
→ blhost reset
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# ─── Константы ────────────────────────────────────────────────────────────────
|
||||||
|
SCRIPT_DIR = Path(__file__).parent.resolve()
|
||||||
|
REPO_ROOT = SCRIPT_DIR.parent.parent
|
||||||
|
BUILD_DIR = REPO_ROOT / "build"
|
||||||
|
FLASHLOADER = SCRIPT_DIR / "dcd" / "ivt_flashloader.bin"
|
||||||
|
|
||||||
|
# USB VID:PID
|
||||||
|
SDP_USB = "0x1FC9,0x0130" # BootROM Serial Download Protocol
|
||||||
|
BLHOST_USB = "0x15A2,0x0073" # Flashloader запущен
|
||||||
|
|
||||||
|
# FlexSPI NOR config option word: 0xC0000007
|
||||||
|
# bits[31:28]=0xC — tag (QuadSPI NOR)
|
||||||
|
# bits[3:0]=0x7 — option size
|
||||||
|
FLEXSPI_OPTION_ADDR = "0x2000"
|
||||||
|
FLEXSPI_OPTION_VALUE = "0xC0000007"
|
||||||
|
FLEXSPI_MEMORY_ID = "9" # FlexSPI NOR memory interface ID
|
||||||
|
|
||||||
|
# Flash layout
|
||||||
|
FLASH_BASE = 0x60000000
|
||||||
|
HAB_OFFSET = 0x1000 # IVT offset: HAB binary starts with IVT at byte 0
|
||||||
|
# write address = FLASH_BASE + ivtOffset = 0x60001000
|
||||||
|
|
||||||
|
|
||||||
|
def run(cmd: list[str], check: bool = True) -> subprocess.CompletedProcess:
|
||||||
|
print(f" $ {' '.join(cmd)}")
|
||||||
|
result = subprocess.run(cmd, capture_output=False)
|
||||||
|
if check and result.returncode != 0:
|
||||||
|
print(f"\n[ERROR] Команда завершилась с кодом {result.returncode}")
|
||||||
|
sys.exit(1)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def step(msg: str) -> None:
|
||||||
|
print(f"\n{'─'*60}")
|
||||||
|
print(f" {msg}")
|
||||||
|
print(f"{'─'*60}")
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_flashloader(timeout: int = 10) -> bool:
|
||||||
|
"""Ждём пока Flashloader поднимется (VID:PID 15A2:0073)"""
|
||||||
|
print(f"\n Ожидание Flashloader (до {timeout}с)...", end="", flush=True)
|
||||||
|
for i in range(timeout):
|
||||||
|
time.sleep(1)
|
||||||
|
result = subprocess.run(
|
||||||
|
["blhost", "-u", BLHOST_USB, "-j", "--", "get-property", "1", "0"],
|
||||||
|
capture_output=True
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(f" OK ({i+1}с)")
|
||||||
|
return True
|
||||||
|
print(".", end="", flush=True)
|
||||||
|
print(" TIMEOUT")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def load_flashloader() -> None:
|
||||||
|
"""Загружает Flashloader через SDP если ещё не запущен"""
|
||||||
|
# Проверяем — вдруг уже запущен
|
||||||
|
result = subprocess.run(
|
||||||
|
["blhost", "-u", BLHOST_USB, "-j", "--", "get-property", "1", "0"],
|
||||||
|
capture_output=True
|
||||||
|
)
|
||||||
|
if result.returncode == 0:
|
||||||
|
print(" Flashloader уже запущен — пропускаем загрузку")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not FLASHLOADER.exists():
|
||||||
|
print(f"[ERROR] Не найден: {FLASHLOADER}")
|
||||||
|
print(" Скачай ivt_flashloader.bin из MCUXpresso Secure Provisioning Tool")
|
||||||
|
print(" и положи в tools/host/dcd/ivt_flashloader.bin")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
step("Загрузка Flashloader через SDP (1FC9:0130)")
|
||||||
|
run(["sdphost", "-u", SDP_USB, "-j", "--",
|
||||||
|
"write-file", "0x20001C00", str(FLASHLOADER)])
|
||||||
|
run(["sdphost", "-u", SDP_USB, "-j", "--",
|
||||||
|
"jump-address", "0x20001C00"])
|
||||||
|
|
||||||
|
if not wait_for_flashloader():
|
||||||
|
print("[ERROR] Flashloader не ответил. Проверь BOOT_MOD пины и подключение.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Option word для записи FCB в Flash[0x60000000]
|
||||||
|
# 0xF000000F: tag=0xF → Write FCB command (Flashloader пишет готовый FCB в начало Flash)
|
||||||
|
FLEXSPI_FCB_VALUE = "0xF000000F"
|
||||||
|
|
||||||
|
|
||||||
|
def configure_flexspi() -> None:
|
||||||
|
"""Инициализирует FlexSPI NOR контроллер через Flashloader"""
|
||||||
|
step("Конфигурация FlexSPI NOR (инициализация контроллера)")
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--",
|
||||||
|
"fill-memory", FLEXSPI_OPTION_ADDR, "4", FLEXSPI_OPTION_VALUE, "word"])
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--",
|
||||||
|
"configure-memory", FLEXSPI_MEMORY_ID, FLEXSPI_OPTION_ADDR])
|
||||||
|
|
||||||
|
|
||||||
|
def write_fcb() -> None:
|
||||||
|
"""Записывает Flash Configuration Block в 0x60000000
|
||||||
|
|
||||||
|
Отдельный шаг после erase! Flashloader генерирует FCB из параметров FlexSPI
|
||||||
|
и пишет его по адресу 0x60000000. Без FCB BootROM не знает как читать Flash.
|
||||||
|
Option word 0xF000000F: tag=0xF → Write FCB command.
|
||||||
|
"""
|
||||||
|
step("Запись FCB в Flash[0x60000000]")
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--",
|
||||||
|
"fill-memory", FLEXSPI_OPTION_ADDR, "4", FLEXSPI_FCB_VALUE, "word"])
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--",
|
||||||
|
"configure-memory", FLEXSPI_MEMORY_ID, FLEXSPI_OPTION_ADDR])
|
||||||
|
|
||||||
|
|
||||||
|
def flash(hab_bin: Path, ram_only: bool = False) -> None:
|
||||||
|
if not hab_bin.exists():
|
||||||
|
print(f"[ERROR] Файл не найден: {hab_bin}")
|
||||||
|
print(" Сначала собери образ: uv run nxpimage hab export -c ...")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if ram_only:
|
||||||
|
step(f"Загрузка в RAM (без записи во Flash): {hab_bin.name}")
|
||||||
|
# RAM-only: грузим в RAM прямо через SDP без flashloader
|
||||||
|
run(["sdphost", "-u", SDP_USB, "-j", "--",
|
||||||
|
"write-file", f"0x{FLASH_BASE + HAB_OFFSET:08X}", str(hab_bin)])
|
||||||
|
run(["sdphost", "-u", SDP_USB, "-j", "--",
|
||||||
|
"jump-address", f"0x{FLASH_BASE + HAB_OFFSET:08X}"])
|
||||||
|
return
|
||||||
|
|
||||||
|
load_flashloader()
|
||||||
|
configure_flexspi() # 0xC0000007 — инициализация FlexSPI контроллера
|
||||||
|
|
||||||
|
write_addr = f"0x{FLASH_BASE + HAB_OFFSET:08X}"
|
||||||
|
# Размер стирания: HAB_OFFSET (0x1000) + размер образа, выровнено вверх до 4KB
|
||||||
|
erase_size = ((HAB_OFFSET + hab_bin.stat().st_size + 0xFFF) // 0x1000) * 0x1000
|
||||||
|
|
||||||
|
step(f"Прошивка Flash: {hab_bin.name}")
|
||||||
|
print(f" Образ: {hab_bin}")
|
||||||
|
print(f" Размер: {hab_bin.stat().st_size} байт")
|
||||||
|
print(f" Адрес: {write_addr}")
|
||||||
|
print(f" Стирание: 0x{FLASH_BASE:08X} .. +{erase_size} байт")
|
||||||
|
|
||||||
|
# memoryId=0 — mapped (XIP) адресное пространство
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--",
|
||||||
|
"flash-erase-region", f"0x{FLASH_BASE:08X}",
|
||||||
|
str(erase_size), "0"])
|
||||||
|
|
||||||
|
write_fcb() # 0xF000000F — запись FCB в 0x60000000 (после erase!)
|
||||||
|
|
||||||
|
# memoryId=0 — mapped (XIP) адресное пространство
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--",
|
||||||
|
"write-memory", write_addr, str(hab_bin), "0"])
|
||||||
|
|
||||||
|
step("Reset")
|
||||||
|
run(["blhost", "-u", BLHOST_USB, "--", "reset"])
|
||||||
|
print("\n ✓ Прошивка завершена успешно")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
parser = argparse.ArgumentParser(description="Прошивка MIMXRT1052 через USB")
|
||||||
|
parser.add_argument("--firmware", required=True,
|
||||||
|
choices=["firmware_test", "bootloader", "app"],
|
||||||
|
help="Имя прошивки")
|
||||||
|
parser.add_argument("--build-type", required=True,
|
||||||
|
choices=["Debug", "Release"],
|
||||||
|
help="Тип сборки")
|
||||||
|
parser.add_argument("--ram-only", action="store_true",
|
||||||
|
help="Загрузить в RAM без записи во Flash")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# HAB образ собирается командой: nxpimage hab export -c hab_<firmware>.yaml
|
||||||
|
# Выходной файл: build/<BuildType>/<firmware>_hab.bin
|
||||||
|
hab_bin = BUILD_DIR / args.build_type / f"{args.firmware}_hab.bin"
|
||||||
|
|
||||||
|
print(f"\n{'═'*60}")
|
||||||
|
print(f" MIMXRT1052 Flash Tool")
|
||||||
|
print(f" Прошивка: {args.firmware} [{args.build_type}]")
|
||||||
|
print(f" Образ: {hab_bin}")
|
||||||
|
print(f"{'═'*60}")
|
||||||
|
|
||||||
|
flash(hab_bin, ram_only=args.ram_only)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -1,18 +1,20 @@
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# HAB Container — firmware/app (боевая прошивка)
|
# HAB Container — firmware/app (боевая прошивка)
|
||||||
|
# Расположение: tools/host/hab/hab_app.yaml
|
||||||
#
|
#
|
||||||
# flags: 0x0 — образ НЕ подписан
|
# Сборка:
|
||||||
# DCD: обязателен — линкер размещает FreeRTOS heap и буферы LCDIF
|
# cd tools/host/hab
|
||||||
# в SDRAM (0x80000000), которая должна быть инициализирована
|
# uv run nxpimage hab export --force -c hab_app.yaml \
|
||||||
# до первой инструкции прошивки.
|
# -o ../../../build/Release/app_hab.bin
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
options:
|
options:
|
||||||
flags: 0x0
|
flags: 0x00
|
||||||
|
startAddress: 0x60000000
|
||||||
|
ivtOffset: 0x1000
|
||||||
|
initialLoadSize: 0x2000
|
||||||
family: mimxrt1050
|
family: mimxrt1050
|
||||||
bootDevice: flexspi_nor
|
DCDFilePath: ../dcd/dcd.bin # обязателен — heap FreeRTOS и LCDIF в SDRAM
|
||||||
startAddress: 0x60000000 # FlexSPI NOR base address (XIP)
|
|
||||||
DCDFilePath: ../dcd/dcd.bin
|
|
||||||
|
|
||||||
inputImageFile: "../../../build/Release/app.bin"
|
inputImageFile: "../../../build/Release/app.bin"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# HAB Container — firmware/bootloader
|
# HAB Container — firmware/bootloader
|
||||||
|
# Расположение: tools/host/hab/hab_bootloader.yaml
|
||||||
#
|
#
|
||||||
# flags: 0x0 — образ НЕ подписан
|
# Сборка:
|
||||||
# DCD: отсутствует намеренно — загрузчик не использует SDRAM,
|
# cd tools/host/hab
|
||||||
# минимальная зависимость от железа = максимальная надёжность.
|
# uv run nxpimage hab export --force -c hab_bootloader.yaml \
|
||||||
# SDRAM инициализируется позже, уже внутри app через её DCD.
|
# -o ../../../build/Release/bootloader_hab.bin
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
options:
|
options:
|
||||||
flags: 0x0
|
flags: 0x00
|
||||||
|
startAddress: 0x60000000
|
||||||
|
ivtOffset: 0x1000
|
||||||
|
initialLoadSize: 0x2000
|
||||||
family: mimxrt1050
|
family: mimxrt1050
|
||||||
bootDevice: flexspi_nor
|
# DCD намеренно отсутствует — загрузчик не использует SDRAM
|
||||||
startAddress: 0x60000000 # FlexSPI NOR base address (XIP)
|
|
||||||
|
|
||||||
inputImageFile: "../../../build/Release/bootloader.bin"
|
inputImageFile: "../../../build/Release/bootloader.bin"
|
||||||
|
|
||||||
sections: []
|
sections: []
|
||||||
|
|
@ -1,23 +1,22 @@
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# HAB Container — firmware/test (входной контроль производства)
|
# HAB Container — firmware/test (входной контроль производства)
|
||||||
|
# Расположение: tools/host/hab/hab_firmware_test.yaml
|
||||||
#
|
#
|
||||||
# flags: 0x0 — образ НЕ подписан (HAB в open/unsigned режиме)
|
# Сборка:
|
||||||
# DCD: присутствует — инициализация SDRAM обязательна для тестов
|
# cd tools/host/hab
|
||||||
#
|
# uv run nxpimage hab export --force -c hab_firmware_test.yaml \
|
||||||
# Важно: sections пустой — для unsigned образа CSF не нужен.
|
# -o ../../../build/Debug/firmware_test.bin
|
||||||
# BootROM примет образ без проверки подписи пока HAB не залочен (fuses).
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
options:
|
options:
|
||||||
flags: 0x0 # unsigned — без подписи
|
flags: 0x00 # unsigned — без подписи
|
||||||
|
startAddress: 0x60000000 # FlexSPI NOR base (XIP)
|
||||||
|
ivtOffset: 0x1000 # IVT offset for FlexSPI NOR boot
|
||||||
|
initialLoadSize: 0x2000 # размер области IVT+BDT+DCD до кода
|
||||||
family: mimxrt1050
|
family: mimxrt1050
|
||||||
bootDevice: flexspi_nor # ivtOffset=0x1000, initialLoadSize=0x2000 — автоматически
|
DCDFilePath: ../dcd/dcd.bin # инициализация SDRAM
|
||||||
startAddress: 0x60000000 # FlexSPI NOR base address (XIP)
|
|
||||||
|
|
||||||
# DCD — инициализация SDRAM до передачи управления прошивке.
|
|
||||||
# Сгенерирован из dcd.cfg скриптом tools/dcd_cfg_to_bin.py
|
|
||||||
DCDFilePath: ../dcd/dcd.bin
|
|
||||||
|
|
||||||
|
# .bin или .srec — оба принимаются
|
||||||
inputImageFile: "../../../build/Debug/firmware_test.bin"
|
inputImageFile: "../../../build/Debug/firmware_test.bin"
|
||||||
|
|
||||||
sections: []
|
sections: []
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
# =============================================================================
|
|
||||||
# Bootable Image — firmware/app (боевая прошивка)
|
|
||||||
# Расположение: tools/host/image/bootimg_app.yaml
|
|
||||||
#
|
|
||||||
# Пайплайн сборки:
|
|
||||||
#
|
|
||||||
# 1. FCB (один раз, из tools/host/fdcb/):
|
|
||||||
# nxpimage bootable-image fcb export -c fcb_w25q64_quad.yaml -o fcb.bin
|
|
||||||
#
|
|
||||||
# 2. Образ (из tools/host/image/):
|
|
||||||
# nxpimage bootable-image export -c bootimg_app.yaml
|
|
||||||
#
|
|
||||||
# 3. Проверка:
|
|
||||||
# nxpimage bootable-image parse -b ../../../../build/Release/app_bootable.bin -f mimxrt1050
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
family: mimxrt1050
|
|
||||||
revision: latest
|
|
||||||
memory_type: flexspi_nor
|
|
||||||
|
|
||||||
output: "../../../build/Release/app_bootable.bin"
|
|
||||||
output_format: bin
|
|
||||||
|
|
||||||
fcb: ../fdcb/fcb.bin
|
|
||||||
|
|
||||||
hab_container: ../hab/hab_app.yaml
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
# =============================================================================
|
|
||||||
# Bootable Image — firmware/bootloader
|
|
||||||
# Расположение: tools/host/image/bootimg_bootloader.yaml
|
|
||||||
#
|
|
||||||
# Пайплайн сборки:
|
|
||||||
#
|
|
||||||
# 1. FCB (один раз, из tools/host/fdcb/):
|
|
||||||
# nxpimage bootable-image fcb export -c fcb_w25q64_quad.yaml -o fcb.bin
|
|
||||||
#
|
|
||||||
# 2. Образ (из tools/host/image/):
|
|
||||||
# nxpimage bootable-image export -c bootimg_bootloader.yaml
|
|
||||||
#
|
|
||||||
# 3. Проверка:
|
|
||||||
# nxpimage bootable-image parse -b ../../../../build/Release/bootloader_bootable.bin -f mimxrt1050
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
family: mimxrt1050
|
|
||||||
revision: latest
|
|
||||||
memory_type: flexspi_nor
|
|
||||||
|
|
||||||
output: "../../../build/Release/bootloader_bootable.bin"
|
|
||||||
output_format: bin
|
|
||||||
|
|
||||||
fcb: ../fdcb/fcb.bin
|
|
||||||
|
|
||||||
hab_container: ../hab/hab_bootloader.yaml
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
# =============================================================================
|
|
||||||
# Bootable Image — firmware/test (входной контроль производства)
|
|
||||||
# Расположение: tools/host/image/bootimg_firmware_test.yaml
|
|
||||||
#
|
|
||||||
# Пайплайн сборки:
|
|
||||||
#
|
|
||||||
# 1. FCB (один раз, из tools/host/fdcb/):
|
|
||||||
# nxpimage bootable-image fcb export -c fcb_w25q64_quad.yaml -o fcb.bin
|
|
||||||
#
|
|
||||||
# 2. Образ (из tools/host/image/):
|
|
||||||
# nxpimage bootable-image export -c bootimg_firmware_test.yaml
|
|
||||||
#
|
|
||||||
# 3. Проверка:
|
|
||||||
# nxpimage bootable-image parse -b ../../../../build/Debug/firmware_test_bootable.bin -f mimxrt1050
|
|
||||||
#
|
|
||||||
# Структура образа во Flash (0x60000000):
|
|
||||||
# 0x000 FCB (512 байт)
|
|
||||||
# 0x400 зарезервировано
|
|
||||||
# 0x1000 IVT ]
|
|
||||||
# 0x1020 BDT ] HAB container
|
|
||||||
# 0x1030 DCD ]
|
|
||||||
# 0x3000 код ]
|
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
family: mimxrt1050
|
|
||||||
revision: latest
|
|
||||||
memory_type: flexspi_nor
|
|
||||||
|
|
||||||
output: "../../../build/Debug/firmware_test_bootable.bin"
|
|
||||||
output_format: bin
|
|
||||||
|
|
||||||
# FCB — собран из tools/host/fdcb/fcb_w25q64_quad.yaml
|
|
||||||
fcb: ../fdcb/fcb.bin
|
|
||||||
|
|
||||||
# HAB container — YAML напрямую, export соберёт его сам
|
|
||||||
hab_container: ../hab/hab_firmware_test.yaml
|
|
||||||
Loading…
Reference in a new issue