From 23cb8f301570033d831830f81586d68e493a794d Mon Sep 17 00:00:00 2001 From: insulee Date: Tue, 23 Jun 2026 16:15:50 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20README=EB=A5=BC=20=EC=83=88=20GUI=20?= =?UTF-8?q?=ED=94=8C=EB=9E=98=EC=85=94=20=EA=B8=B0=EC=A4=80=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EA=B0=B1=EC=8B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 앱 사용법·지원 모델 표·flash.json 작성법·포트(유령 COM) 안내 - 빌드/배포(단일 실행본, esptool 동봉 주의)·폴더 구조 - 기존 PowerShell 키트는 하위 섹션으로 유지 Co-Authored-By: Claude Opus 4.8 --- README.md | 262 ++++++++++++++++-------------------------------------- 1 file changed, 75 insertions(+), 187 deletions(-) diff --git a/README.md b/README.md index 43fd008..63b0dc1 100644 --- a/README.md +++ b/README.md @@ -1,225 +1,113 @@ -# DB720 펌웨어 적재 키트 (PowerShell) +# firmware-flasher -ESP32-P4 기반 DB720 보드에 **secure_release 서명 펌웨어**를 PowerShell로 적재하는 독립 키트입니다. -이 폴더 하나만 있으면 빌드 환경 없이도 적재할 수 있습니다(esptool만 있으면 됨). +ESP32 계열 컨트롤러(DB720·DB402S·DB400S 등)에 펌웨어를 굽는 **Windows GUI 도구**. +설치·파이썬 없이 도는 단일 실행본으로 배포되고, 모델별 설정은 `flash.json` 하나로 갈아끼운다. -- 펌웨어: `DIBD720Ue_08B_08R040C` (8단40열 = 640×128, 256색/08B) — db250513 키로 V2 서명한 secure_release 빌드 -- 빌드일: 2026-06-22 (버전 3.7.2) +> 시작은 DB720(ESP32-P4) 전용 PowerShell 키트였고, 지금은 여러 모델을 GUI로 다룬다. +> 기존 `.ps1` 스크립트도 그대로 남아 있다([아래](#powershell-키트-기존)). -> **DB720은 secure_release 단일입니다.** 적재·빌드·OTA에 쓰는 펌웨어는 **db250513 키로 서명한 바이너리뿐**입니다. -> 서명이 없는 일반 빌드(예: V3.7.1 같은 공개 릴리즈 바이너리)는 secure_release 부트로더가 **서명 검증에서 거부**해 부팅되지 않습니다. -> 이 키트의 `firmware\` 폴더에는 **db250513 서명본만** 두세요(비서명 bin 금지). +## 특징 ---- +- **멀티모델** — 칩·offset·baud·쓰기방식이 다른 모델을 프로파일로 분리. 드롭다운에서 고르거나 폴더의 `flash.json`으로 자동. +- **포트 자동 감지** — USB-JTAG(`303A:1001`)를 꽂는 즉시 잡아 자동 선택. 리셋으로 COM 번호가 바뀌어 생기는 **유령 포트**를 열기-probe로 걸러 살아있는 포트로 자동 전환. +- **esptool 동봉** — esptool v5 단독 실행본을 같이 묶어, 받는 PC에 파이썬이 없어도 동작. +- **안전장치** — "앱만"이 기본(부트로더 안 건드림). "전체"(부트로더 재작성)는 eFuse 영구 굽힘 경고 + 확인 체크. -## 0. 두 경우 — 어느 스크립트를 쓰나 +## 빠른 시작 (사용자) -| 보드 상태 | 스크립트 | 무엇을 쓰나 | 위험 | +1. 배포 zip을 풀고 `FirmwareFlasher.exe` 실행. +2. **펌웨어 폴더** 선택 → **앱**·**모델** 확인(폴더에 `flash.json` 있으면 자동). +3. **포트**는 자동으로 잡힘(안 잡히면 `↻ 새로고침`). +4. **모드** 고르고 **플래시 시작**. + - 평소: **앱만**(가장 안전) + - 새 보드 첫 굽기/복구: **전체** (eFuse 주의) +5. 끝나면 보드 전원 재인가. + +## 지원 모델 + +| 모델 | 칩 | 부트로더 offset | 포트·방식 | |---|---|---|---| -| **일상적 앱 교체** (서명 부트로더가 이미 정상) | `flash_app.ps1` | 부트로더 **제외** 4종(파티션/ota_data/앱/www) | 없음 — 부트로더 안 건드려 **brick 불가** | -| **부트로더가 비었을 때** (flash 통째 지워짐 / 0x2000 빔 / 부팅 안 됨) | `flash_full.ps1` | 부트로더+파티션+ota_data+앱+www **5종 전부** | ⚠ 부트로더(0x2000)에 손댐 — 아래 §1 경고 | +| DB720 | `esp32p4` | `0x2000` | USB-JTAG · no-stub · 115200 · 영역별 | +| DB402S | `esp32s3` | `0x0000` | UART(TTL) · stub · 921600 · 한 번에 | +| DB400S / DB400Q / DB300eM | `esp32` | `0x1000` | UART(TTL) · stub · 921600 · 한 번에 | -> **일상 적재는 `flash_app.ps1`(경우 B)만 쓰세요.** 가능하면 `-AppOnly`로 앱만 올립니다. -> `flash_full.ps1`(경우 A)은 **부트로더가 실제로 비어 부팅이 안 될 때만** 쓰는 복구 전용입니다. +공통 offset: 파티션 `0x10000` · ota_data `0x11000` · 앱 `0x20000` · (DB720만) www_fs `0x420000`. ---- +## 모델 추가 — `flash.json` -## 1. ★★★ full flash 경고 (경우 A 전용) ★★★ +펌웨어 폴더에 `flash.json`을 넣으면 앱이 **그 폴더만 보고** 그대로 굽는다. `profiles/`에 모델별 템플릿이 있다. -`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 +```json +{ + "name": "DB402S (ESP32-S3)", + "chip": "esp32s3", + "baud": 921600, + "noStub": false, + "perRegion": false, + "regions": [ + { "file": "bootloader.bin", "offset": "0x0000", "kind": "bootloader" }, + { "file": "partition-table.bin", "offset": "0x10000", "kind": "support" }, + { "file": "ota_data_initial.bin", "offset": "0x11000", "kind": "support" }, + { "app": true, "offset": "0x20000" } + ], + "consolePortHint": "10C4:EA60", + "downloadModeHint": "TTL(COM2) 연결, SW1 누른 채 SW2 눌렀다 떼고 SW1 떼면 다운로드 모드" +} ``` -### 경우 A — 부트로더 비었음 (전체 복구 전용, §1 경고 확인) -```powershell -.\flash_full.ps1 -Port COM4 -``` +주요 키: `chip` / `baud` / `noStub`(스텁 여부) / `perRegion`(영역별 vs 한 번에) / `flashSize`·`flashMode`·`flashFreq`(생략 시 자동) / `flashPortHint`(자동선택 우선 VID:PID) / `consolePortHint` / `appOnlyErasesOtadata`. -> 실행 정책 때문에 막히면(이 PC에 처음): `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` 한 번. -> `-Port`를 생략하면 기본 `COM4`로 시도합니다. +> `flash.json`이 없어도 됨 — DB720·DB402S·DB400S·DB400Q·DB300eM 설정은 앱에 내장돼 있어 "모델" 드롭다운에서 골라도 동작. ---- +## 포트 — 유령 COM 주의 -## 3a. 앱이 여러 개일 때 — 골라서 올리기 +ESP32 USB-JTAG는 보드가 리셋될 때마다 USB를 다시 잡아 **COM 번호가 올라간다**(예: COM17→COM18). 옛 번호는 목록엔 "정상"으로 남지만 열 수 없다(유령 포트). 앱은 **최신 번호 우선 + 열기-probe**로 살아있는 포트를 자동으로 쓴다. 그래도 안 되면 케이블을 다시 꽂고 `↻ 새로고침`. -`firmware\` 폴더에 앱 `.bin`이 여러 개 있을 수 있습니다. 예를 들어 지금은 두 개가 들어 있습니다. +> 적재 포트는 측정/표출 중에는 열지 말 것 — DTR/RTS가 보드를 리셋한다. -| 앱 파일 | 화면 크기 | 상태 | -|---|---|---| -| `DIBD720Te_08C_04R020C.bin` | 320×64 (4단20열, 8색) | 부팅 검증됨 — 안전, 일상·복구용 권장 | -| `DIBD720Ue_08B_08R040C.bin` | 640×128 (8단40열, 256색) | 부팅 미검증 — 테스트용(SRAM 한도 의심) | +## secure 보드 / eFuse -> 부트로더·파티션·ota_data·www_fs는 앱이 아니라 보조 파일이라 선택 대상에서 빠집니다. 앱 후보는 그 4개를 뺀 나머지 `.bin`입니다. +서명(secure boot) 보드는 부트로더(`0x8000` 아래) 쓰기를 거부하는 게 **정상**이다. 그땐 **표준/앱만**으로(부트로더 건너뜀). 꼭 부트로더를 다시 써야 하면 `--force`. eFuse는 한 번 구워지면 **되돌릴 수 없으니** 서명 키 백업 필수. -### 1단계 — 어떤 앱이 있는지 본다 +## 빌드 (개발) -앱을 지정하지 않고 그냥 실행하면, 스크립트가 **임의로 고르지 않고** 앱 목록을 보여준 뒤 멈춥니다. +요구: **.NET 9 SDK** (Windows), WPF(`net9.0-windows`). ```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 +dotnet build DB720Flasher\DB720Flasher.csproj +dotnet run --project DB720Flasher\DB720Flasher.csproj ``` -### 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 +dotnet publish DB720Flasher\DB720Flasher.csproj -c Release -r win-x64 ` + --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true ``` -- `-App` 값은 `firmware\` 안의 **파일명만** 적습니다(경로 없이). -- 앱이 **하나뿐이면** `-App`을 생략해도 그것이 자동 선택됩니다(여러 개일 때만 지정 필수). -- `flash_full.ps1`(경우 A)도 똑같이 `-App`으로 고릅니다. +> ⚠ 단일 파일 publish는 동봉 `esptool.exe`를 exe 안으로 삼킨다. publish 후 `tools\esptool\`와 `firmware\`를 **exe 옆에 따로 복사**해 배포 폴더를 만든다(그래야 앱이 esptool을 찾음). 받는 사람은 폴더 통째로 받아 `FirmwareFlasher.exe` 실행 — 설치 불필요. ---- +## 폴더 구조 -## 3b. 전체 굽기 (full flash) — 5영역 전부 +``` +firmware-flasher/ +├─ DB720Flasher/ WPF 앱 소스 (+ tools/esptool/ 동봉 엔진) +├─ firmware/ 펌웨어 폴더 (flash.json 포함; 서명 .bin 은 git 제외) +├─ profiles/ 모델별 flash.json 템플릿 (DB720·DB402S·DB400S) +├─ flash_app.ps1 / flash_full.ps1 / list_ports.ps1 기존 PowerShell 키트 +└─ README.md +``` -부트로더(0x2000)까지 포함해 **5개 영역을 전부** 쓰는 절차입니다. flash가 통째로 비었거나 부트로더가 깨져 부팅이 안 될 때 보드를 처음부터 살립니다. +> `firmware/*.bin`(서명 실펌웨어)와 `dist/`(배포본), 빌드 출력은 git에 올리지 않는다(`.gitignore`). 배포본 zip은 Gitea **Releases**로. -> ⚠ **먼저 §1 경고를 읽으세요.** 전체 굽기는 부트로더를 건드리므로, eFuse가 안 구워진 보드에서는 **첫 부팅에 secure boot eFuse가 영구로 구워집니다**(되돌릴 수 없음). 일상 적재에는 쓰지 말고 §3(앱 적재)을 쓰세요. 전체 굽기는 **부트로더가 실제로 비어 부팅이 안 될 때만** 씁니다. +## PowerShell 키트 (기존) -### 무엇을 쓰나 (영역 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 — 스크립트 (권장) +GUI 없이 명령으로 굽는 원래 방식(여전히 사용 가능). DB720 기준: ```powershell -# 앱이 하나면 그대로 -.\flash_full.ps1 -Port COM4 - -# 앱이 여러 개면 -App 으로 지정 -.\flash_full.ps1 -Port COM4 -App DIBD720Te_08C_04R020C.bin +.\list_ports.ps1 # 적재 포트(303A:1001) 확인 +.\flash_app.ps1 -Port COM4 -AppOnly # 앱만 (brick-safe, 권장) +.\flash_full.ps1 -Port COM4 # 전체 (부트로더 포함, eFuse 주의) ``` -스크립트가 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가 서명하지 않는 정상 파일입니다. +> 일상 적재는 `flash_app.ps1`(앱만)으로 충분하다. `flash_full.ps1`은 부트로더가 비어 부팅이 안 될 때만 쓰는 복구 전용. GUI 앱은 동봉 esptool(v5)로 같은 일을 더 안전하게 한다.