Initial commit: 펌웨어 플래시 도구 (WPF) + 기존 PowerShell 키트

- DB720Flasher: WPF .NET 9 GUI 플래셔
  - 멀티모델 프로파일(flash.json + 빌트인 DB720/DB402S/DB400S/DB400Q/DB300eM)
  - 포트 자동감지(JTAG 우선, 유령 포트 자동 회피), esptool v5 동봉
- flash_app.ps1 / flash_full.ps1 / list_ports.ps1: 기존 PowerShell 키트
- profiles/: 모델별 flash.json 템플릿
- firmware/flash.json: DB720 모델 설정 (서명 실펌웨어 .bin 은 repo 제외)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
insulee
2026-06-23 16:10:40 +09:00
commit 69f4d4754f
25 changed files with 2545 additions and 0 deletions

225
README.md Normal file
View File

@@ -0,0 +1,225 @@
# DB720 펌웨어 적재 키트 (PowerShell)
ESP32-P4 기반 DB720 보드에 **secure_release 서명 펌웨어**를 PowerShell로 적재하는 독립 키트입니다.
이 폴더 하나만 있으면 빌드 환경 없이도 적재할 수 있습니다(esptool만 있으면 됨).
- 펌웨어: `DIBD720Ue_08B_08R040C` (8단40열 = 640×128, 256색/08B) — db250513 키로 V2 서명한 secure_release 빌드
- 빌드일: 2026-06-22 (버전 3.7.2)
> **DB720은 secure_release 단일입니다.** 적재·빌드·OTA에 쓰는 펌웨어는 **db250513 키로 서명한 바이너리뿐**입니다.
> 서명이 없는 일반 빌드(예: V3.7.1 같은 공개 릴리즈 바이너리)는 secure_release 부트로더가 **서명 검증에서 거부**해 부팅되지 않습니다.
> 이 키트의 `firmware\` 폴더에는 **db250513 서명본만** 두세요(비서명 bin 금지).
---
## 0. 두 경우 — 어느 스크립트를 쓰나
| 보드 상태 | 스크립트 | 무엇을 쓰나 | 위험 |
|---|---|---|---|
| **일상적 앱 교체** (서명 부트로더가 이미 정상) | `flash_app.ps1` | 부트로더 **제외** 4종(파티션/ota_data/앱/www) | 없음 — 부트로더 안 건드려 **brick 불가** |
| **부트로더가 비었을 때** (flash 통째 지워짐 / 0x2000 빔 / 부팅 안 됨) | `flash_full.ps1` | 부트로더+파티션+ota_data+앱+www **5종 전부** | ⚠ 부트로더(0x2000)에 손댐 — 아래 §1 경고 |
> **일상 적재는 `flash_app.ps1`(경우 B)만 쓰세요.** 가능하면 `-AppOnly`로 앱만 올립니다.
> `flash_full.ps1`(경우 A)은 **부트로더가 실제로 비어 부팅이 안 될 때만** 쓰는 복구 전용입니다.
---
## 1. ★★★ full flash 경고 (경우 A 전용) ★★★
`flash_full.ps1`은 부트로더(0x2000)까지 다시 씁니다.
- **이미 secure_release로 구워진 보드** (예: 회사 `.230`) → 부트로더가 이미 영구 고정돼 있으므로 같은 서명 부트로더를 다시 쓸 이유가 없습니다. **일상 적재에 경우 A를 쓰지 마세요**`flash_app.ps1`이면 충분합니다.
- **eFuse가 아직 안 구워진 보드** → secure_release 서명본을 full flash하면 첫 부팅에 secure boot **eFuse가 영구로 구워집니다**(되돌릴 수 없음).
- **eFuse는 비가역입니다.** 한 번 구워지면 그 보드는 영원히 이 서명 체계에만 묶입니다(DB400 V1에서 `ABS_DONE_0` 잠김으로 보드가 brick된 실증이 있습니다).
- **db250513 키를 분실하면 그 보드는 OTA로 더 이상 펌웨어를 못 올립니다(영구).** 키 백업은 필수입니다.
`flash_app.ps1`(경우 B)은 부트로더를 안 건드리므로 이 위험이 **없습니다**.
---
## 2. 사전 준비
1. **USB-JTAG 케이블**로 PC ↔ DB720 연결 (보드의 USB-JTAG 포트).
2. **esptool**이 있는 파이썬. 두 스크립트는 기본으로 ESP-IDF 파이썬을 씁니다:
`C:\Users\jyheo\.espressif\python_env\idf5.5_py3.13_env\Scripts\python.exe`
- 환경이 다르면 `flash_full.ps1` / `flash_app.ps1` 상단의 `$Python` 한 줄만 고치세요.
- 또는 `pip install esptool` 한 파이썬이 PATH에 있으면 자동 폴백됩니다.
- esptool은 **v4.11 이상**이어야 합니다(낮으면 적재 중 멈춤).
3. **COM 포트 확인** — 적재 포트(USB-JTAG)는 번호가 바뀔 수 있습니다:
```powershell
.\list_ports.ps1
```
- `USB 직렬 장치(COMx)` 또는 VID `303A:1001` = **적재 포트** (`-Port COMx`)
- `Silicon Labs CP210x (COMx)` = **COM2 자리**(디버그·문구 전송, 적재 중 열지 말 것)
---
## 3. 적재 방법
PowerShell을 이 폴더에서 열고:
### 경우 B — 서명 부트로더 있음 (일상 적재, 권장)
```powershell
# 앱만 최소로(앱 0x20000 + otadata erase) — 권장
.\flash_app.ps1 -Port COM4 -AppOnly
# 표준(파티션+ota_data+앱+www, 부트로더 제외)
.\flash_app.ps1 -Port COM4
```
### 경우 A — 부트로더 비었음 (전체 복구 전용, §1 경고 확인)
```powershell
.\flash_full.ps1 -Port COM4
```
> 실행 정책 때문에 막히면(이 PC에 처음): `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` 한 번.
> `-Port`를 생략하면 기본 `COM4`로 시도합니다.
---
## 3a. 앱이 여러 개일 때 — 골라서 올리기
`firmware\` 폴더에 앱 `.bin`이 여러 개 있을 수 있습니다. 예를 들어 지금은 두 개가 들어 있습니다.
| 앱 파일 | 화면 크기 | 상태 |
|---|---|---|
| `DIBD720Te_08C_04R020C.bin` | 320×64 (4단20열, 8색) | 부팅 검증됨 — 안전, 일상·복구용 권장 |
| `DIBD720Ue_08B_08R040C.bin` | 640×128 (8단40열, 256색) | 부팅 미검증 — 테스트용(SRAM 한도 의심) |
> 부트로더·파티션·ota_data·www_fs는 앱이 아니라 보조 파일이라 선택 대상에서 빠집니다. 앱 후보는 그 4개를 뺀 나머지 `.bin`입니다.
### 1단계 — 어떤 앱이 있는지 본다
앱을 지정하지 않고 그냥 실행하면, 스크립트가 **임의로 고르지 않고** 앱 목록을 보여준 뒤 멈춥니다.
```powershell
.\flash_app.ps1 -Port COM4
```
출력 예:
```
여러 앱이 있습니다 — -App 으로 하나를 지정하세요:
DIBD720Te_08C_04R020C.bin
DIBD720Ue_08B_08R040C.bin
예: .\flash_app.ps1 -Port COM4 -App DIBD720Te_08C_04R020C.bin
```
### 2단계 — 올릴 앱을 `-App`으로 지정한다
```powershell
# 320×64(검증된 것)을 앱만 최소로 올리기 — 권장
.\flash_app.ps1 -Port COM4 -App DIBD720Te_08C_04R020C.bin -AppOnly
# 640×128(테스트)을 표준으로 올리기
.\flash_app.ps1 -Port COM4 -App DIBD720Ue_08B_08R040C.bin
```
- `-App` 값은 `firmware\` 안의 **파일명만** 적습니다(경로 없이).
- 앱이 **하나뿐이면** `-App`을 생략해도 그것이 자동 선택됩니다(여러 개일 때만 지정 필수).
- `flash_full.ps1`(경우 A)도 똑같이 `-App`으로 고릅니다.
---
## 3b. 전체 굽기 (full flash) — 5영역 전부
부트로더(0x2000)까지 포함해 **5개 영역을 전부** 쓰는 절차입니다. flash가 통째로 비었거나 부트로더가 깨져 부팅이 안 될 때 보드를 처음부터 살립니다.
> ⚠ **먼저 §1 경고를 읽으세요.** 전체 굽기는 부트로더를 건드리므로, eFuse가 안 구워진 보드에서는 **첫 부팅에 secure boot eFuse가 영구로 구워집니다**(되돌릴 수 없음). 일상 적재에는 쓰지 말고 §3(앱 적재)을 쓰세요. 전체 굽기는 **부트로더가 실제로 비어 부팅이 안 될 때만** 씁니다.
### 무엇을 쓰나 (영역 5개)
| offset | 파일 | 크기 | 서명 |
|---|---|---|---|
| `0x2000` | `firmware\bootloader.bin` | 45KB | db250513 서명 |
| `0x10000` | `firmware\partition-table.bin` | 3KB | 비서명(정상) |
| `0x11000` | `firmware\ota_data_initial.bin` | 8KB | 비서명(정상) |
| `0x20000` | 선택한 앱 (`-App`) | 1.2~1.7MB | db250513 서명 |
| `0x420000` | `firmware\www_fs.bin` | 512KB | 비서명(정상) |
### 방법 1 — 스크립트 (권장)
```powershell
# 앱이 하나면 그대로
.\flash_full.ps1 -Port COM4
# 앱이 여러 개면 -App 으로 지정
.\flash_full.ps1 -Port COM4 -App DIBD720Te_08C_04R020C.bin
```
스크립트가 5영역을 **하나씩 개별 호출**로 쓴 뒤(SDM 다중영역 한 번에 쓰면 중간 실패) hard_reset 합니다.
### 방법 2 — 수동 esptool (스크립트가 안 될 때, 한 줄씩)
`COM4`는 적재 포트로 바꾸고(`.\list_ports.ps1`), `--flash_size 16MB`**반드시** 붙입니다(이게 빠지면 SDM에서 4MB로 오인해 `0x420000`(www_fs)을 못 써 부팅 루프가 납니다 — 2026-06-22 실증).
```powershell
$P = "C:\Users\jyheo\.espressif\python_env\idf5.5_py3.13_env\Scripts\python.exe"
$C = "--chip","esp32p4","-p","COM4","-b","115200","--before","default_reset","--after","no_reset","--connect-attempts","30","--no-stub"
$W = "write_flash","--flash_mode","dio","--flash_size","16MB","--flash_freq","80m"
& $P -m esptool @C @W 0x2000 firmware\bootloader.bin
& $P -m esptool @C @W 0x10000 firmware\partition-table.bin
& $P -m esptool @C @W 0x11000 firmware\ota_data_initial.bin
& $P -m esptool @C @W 0x20000 firmware\DIBD720Te_08C_04R020C.bin # 올릴 앱
& $P -m esptool @C @W 0x420000 firmware\www_fs.bin
# SDM 탈출(정상 부팅)
& $P -c "from esptool.targets.esp32p4 import ESP32P4ROM; r=ESP32P4ROM('COM4'); r.connect('default_reset'); r.hard_reset()"
```
> ★ **secure 보드는 부트로더(0x2000)·전체 erase write를 거부할 수 있습니다** — `0105 format invalid` 같은 거부는 부트로더가 이미 같은 키로 구워져 있다는 뜻(정상)이라, 그 경우 0x2000은 건너뛰고 나머지 4영역만 쓰면 됩니다(= §3 앱 적재로 충분).
> ★ esptool/USB 리셋은 이 보드에서 다운로드 모드로 떨어지는 경향이 있어, **최종 부팅은 USB-JTAG 케이블을 뽑고 전원 사이클**해야 확실합니다.
---
## 4. 적재 메커니즘 (왜 이렇게 하나)
- **eco2 secure download mode(SDM) 레시피**: `--no-stub` + `115200` baud + `--before default_reset --after no_reset`.
secure 보드는 esptool stub를 못 올리므로 `--no-stub`, 다운로드 모드 안정 위해 115200을 씁니다.
- **영역은 하나씩 개별 esptool 호출로** 씁니다. SDM에서 여러 영역을 한 번에 쓰면 중간에 "Failed to enter Flash download mode"로 실패합니다(2026-06-22 실증 — www_fs가 빈 채 남아 부팅 루프).
- **부트로더(0x2000)는 경우 A에서만** 씁니다. secure 보드는 부트로더/전체 erase를 거부하는 게 정상입니다.
- 적재 후 `--after no_reset`로 남은 다운로드 모드를 **hard_reset**(esptool ROM 객체)으로 빠져나와 정상 부팅합니다.
- 오프셋 정본: 부트로더 `0x2000` / 파티션 `0x10000` / ota_data `0x11000` / 앱 `0x20000` / www_fs `0x420000`. flash: dio / keep / 80m.
---
## 5. 적재 후 확인
다음 중 하나로 새 펌웨어가 실제로 올라가 부팅됐는지 확인합니다.
- **COM2(디버그 콘솔, CP210x)에서 `![0081!]`** 을 115200bps로 보내 버전 배너가 오면 정상(적재 포트 COM4 아님).
- **부트로그**에 `RSA-PSS verified`(secure_release 서명 검증 통과)와 정상 부팅 메시지가 보이면 정상.
- **LAN으로 받은 빌드 시각**을 키트의 빌드일(이 README 상단)과 대조 — 날짜가 맞으면 새 펌웨어가 적용된 것입니다.
> 적재 포트(COM4/USB-JTAG)는 **측정·표출 중 열지 마세요** — DTR/RTS가 보드를 리셋해 화면이 날아갑니다.
---
## 6. 안 될 때
| 증상 | 조치 |
|---|---|
| 포트 연결 실패 / `could not open port` | `.\list_ports.ps1`로 실제 USB-JTAG COM 번호 확인 후 `-Port COMx`. 다른 프로그램이 그 포트를 잡고 있으면 닫기 |
| `~0.72MB`에서 멈춤(hang) | esptool 버전이 낮음(<4.11). `pip install -U esptool` (이 키트는 v4.11+ 전제) |
| 적재는 됐는데 부팅 안 됨(검정/무응답) | 먼저 `flash_app.ps1 -AppOnly`로 otadata를 지워 ota_0으로 폴백 시도. 그래도 안 되고 부트로더가 빈 것 같으면 경우 A `flash_full.ps1` |
| 부트로그에 서명 검증 실패 | 비서명(서명 없는) bin을 올렸을 때 발생. `firmware\`**db250513 서명본만** 있는지 확인(V3.7.1 같은 일반 릴리즈 bin은 secure_release에서 부팅 거부) |
| `secure download` / 권한 오류 반복 | USB 케이블 재연결 후 재시도(스크립트가 connect 30회 재시도) |
---
## 7. 포함 파일
```
DB720_Flash\
├─ README.md ← 이 문서
├─ list_ports.ps1 ← COM 포트 확인
├─ flash_app.ps1 ← 경우 B: 서명 부트로더 있을 때(brick-safe, 권장)
├─ flash_full.ps1 ← 경우 A: 부트로더 비었을 때(full, §1 경고)
└─ firmware\
├─ bootloader.bin (0x2000, 45KB) ← 경우 A에서만 사용 (db250513 서명)
├─ partition-table.bin (0x10000, 3KB) ← 비서명(설계상 정상)
├─ ota_data_initial.bin (0x11000, 8KB) ← 비서명(설계상 정상)
├─ DIBD720Te_08C_04R020C.bin (0x20000, 1.2MB) ← 앱① 320×64, 8색 (db250513 서명, 부팅 검증됨·권장)
├─ DIBD720Ue_08B_08R040C.bin (0x20000, 1.7MB) ← 앱② 640×128, 256색 (db250513 서명, 테스트용·미검증)
└─ www_fs.bin (0x420000, 512KB) ← 비서명(설계상 정상)
```
> 앱이 둘 다 `0x20000`(ota_0)에 올라가는 같은 자리라, **한 번에 하나만** 적재됩니다. 어느 것을 올릴지는 §3a의 `-App`으로 고릅니다.
> 서명 대상(앱·부트로더)은 모두 db250513 서명본이고, 파티션·ota_data·www_fs는 secure boot v2가 서명하지 않는 정상 파일입니다.