- firmware BSP_USART_BAUDRATE 460800 (divider error +0.03%); uartrst/
uartinfo follow the macro
- RX DMA ring 2KB -> 3KB: at 460800 2KB only covers 44ms, less than the
~45ms flash-erase interrupt-off window; stack top now 0x2000BDE8
(guard warns <1KB from the 0x2000C000 cliff, by design)
- tools: ble_ota_update.py UartTransport and uart_cap.py default baud
- Verified: stream OTA 55832B in 2.6s @23kB/s (one lost frame recovered
by go-back-N), PASS after reboot; text CLI fine at 460800
- docs: ble_protocol.md, design spec, AGENTS.md, dev log section 48
Firmware:
- bsp_usart: RX moved from RXDNE byte-queue IRQ to DMA CH2 circular ring
(2KB) + IDLE-irq wakeup; bytes keep landing during flash-erase
interrupt-off windows (the reason lockstep was needed before)
- app_ota: stream mode (ble_protocol.md section 6.7) - 16B BEGIN with
flags bit0=STREAM (UART channel only), DATA acked on 4KB sector
crossings (original chunk length; two ack-gating bugs fixed during
field test), throttled BAD_STATE for go-back-N
- FreeRTOS heap 20KB->18KB: the 2KB ring pushed the stack top past the
0x2000C000 SRAM cliff (probed via SWD: accesses above fault on this
silicon, usable app SRAM is 32KB) which locked the board at boot;
merge_image.py now hard-fails the package when the image initial SP
leaves (0x20004000, 0x2000C000]
Tools:
- ble_ota_update.py: UART stream sender (8KB window, stall watchdog
rewind, auto-fallback to lockstep on pre-V1.00.24 firmware,
--lockstep to force); case-insensitive option parsing
- flash_package.py/bat: stream NSpyocd output live (chunked reads keep
the \r progress bar), vendor banner rebranded to CAIIC NSLINK UMP
- merge_image.py: initial-SP cliff guard
Verified: UART stream OTA both directions, 55.8KB in ~5.9s @9.5kB/s
0 rewinds (lockstep was 39s), PASS after reboot; board boot fixed and
verified via SWD.
Docs: ble_protocol.md section 6.7, dev log section 47 (+ SRAM cliff
post-mortem), AGENTS.md RAM rule rewritten (both cliffs) + V1.00.25
- firmware version bump V1.00.22 -> V1.00.23 (0x00010017), no code change;
user-verified BLE OTA (APP1->APP2) and UART OTA both PASS
- ble_ota_update.py: frame-level live progress bar on tty (bar/pct/bytes/
rate/per-frame ack RTT, ~10fps throttled), 5%-step lines when redirected;
resend/resync notices no longer mix into the bar line; END summary now
reports resent/resynced counters; BEGIN/END stage banners
- docs: dev log 46, AGENTS.md sync
- firmware: version bump to V1.00.22 (0x00010016), no code change
- ble_ota_update.py: cur-bank detection now reads the full devinfo output
and parses strictly (early break at the 'cur bank:' prefix could miss
'APP2' and silently default to APP1 -> wrong payload selection, caught
by the device bank_mismatch guard on hardware)
- new pre-flight check_blob_bank(): payload vector reset PC must land in
the target bank before transferring (BLE and UART paths)
- UART path: post-reboot verification over the text CLI (bank+version),
deterministic PASS/FAIL like the BLE path
- verified: UART OTA APP2->APP1 V1.00.22 full pass with auto-verify
- docs: dev log 45, AGENTS.md sync