sl-firmware 4beef8da03 feat(firmware): OTA DFU entry via JLink command and Python flash script (Issue #124)
- Add ota.h / ota.c: ota_enter_dfu() (armed guard, writes BKP15R, resets),
  ota_fw_crc32() using STM32F7 hardware CRC peripheral (CRC-32/MPEG-2, 512 KB)
- Add JLINK_CMD_DFU_ENTER (0x06) and dfu_req flag to jlink.h / jlink.c
- Handle dfu_req in main loop: calls ota_enter_dfu(is_armed) — no-op if armed
- Update usbd_cdc_if.c: move DFU magic from BKP0R to BKP15R (OTA_DFU_BKP_IDX)
  resolving BKP register conflict with BNO055 calibration (BKP0R–6R, PR #150)
- Add scripts/flash_firmware.py: CRC-32/MPEG-2 + ISO-HDLC verification,
  dfu-util flash, host-side backup/rollback, --trigger-dfu JLink serial path
- Add test/test_ota.py: 42 tests passing (CRC-32/MPEG-2, CRC-16/XMODEM,
  DFU_ENTER frame structure, BKP register safety, flash constants)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 09:56:18 -05:00

64 lines
2.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef OTA_H
#define OTA_H
#include <stdint.h>
#include <stdbool.h>
/*
* OTA firmware update — Issue #124
*
* DFU entry triggered by JLINK_CMD_DFU_ENTER (0x06) or USB CDC 'R' command.
* Uses RTC backup register OTA_DFU_BKP_IDX to pass magic across the soft reset.
*
* RTC BKP register map:
* BKP0RBKP5R : BNO055 calibration offsets (PR #150)
* BKP6R : BNO055 magic (0xB055CA10, PR #150)
* BKP7RBKP14R : Reserved
* BKP15R : OTA DFU magic (this module)
*
* Using BKP15R avoids collision with BNO055 (BKP06) and the old BKP0R
* that the original request_bootloader() used before this module.
*
* Dual-bank note: STM32F722 has single-bank flash (512 KB). Hardware A/B
* rollback is not supported without a custom bootloader. DFU via the ST
* system bootloader at 0x1FF00000 is the supported update path. Rollback
* is handled by the host-side flash_firmware.py script, which keeps a
* backup of the previous binary.
*/
/* RTC backup register index used for DFU magic — avoids BNO055 BKP06 */
#define OTA_DFU_BKP_IDX 15u
/* Magic value written before reset to trigger DFU entry on next boot */
#define OTA_DFU_MAGIC 0xDEADBEEFu
/* STM32F722 internal flash: 512 KB starting at 0x08000000 */
#define OTA_FLASH_BASE 0x08000000u
#define OTA_FLASH_SIZE 0x00080000u /* 512 KB */
/*
* ota_enter_dfu(is_armed)
*
* Request entry to USB DFU mode (ST system bootloader at 0x1FF00000).
* Returns false without side effects if is_armed is true.
* Otherwise: enables backup domain, writes OTA_DFU_MAGIC to BKP15R,
* disables IRQs, calls NVIC_SystemReset(). Never returns on success.
*
* Call from the main loop only (not from ISR context).
*/
bool ota_enter_dfu(bool is_armed);
/*
* ota_fw_crc32()
*
* Compute a CRC-32/MPEG-2 checksum of the full flash region using the
* STM32 hardware CRC peripheral (poly 0x04C11DB7, init 0xFFFFFFFF,
* 32-bit words, no reflection). Covers OTA_FLASH_SIZE bytes from
* OTA_FLASH_BASE including erased padding.
*
* Takes ~0.5 ms at 216 MHz. Call only while disarmed.
*/
uint32_t ota_fw_crc32(void);
#endif /* OTA_H */