mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-10-01 02:08:24 +00:00
Port the "reduce idle power" feature from the Fantasi firmware (soeinova/Fantasi @ 9671309, plus its later ACC-SOF fix) to the PM5 (AT32F435) target. Problem ------- The PM5 firmware ran the ARM core at 288 MHz with a 1.3 V LDO and a main loop that busy-polled at full speed even when the device was idle. The 288 MHz PLL and the 1.3 V LDO dominate idle draw, and the busy loop adds to it. Nothing scaled back when there was no work. Change ------ New armsrc/pm5_power.c drives a refcounted clock/voltage governor: - Idle (nothing pending, boost count 0, boot grace elapsed, FPGA off): take SCLK off the PLL onto HICK-48, power the PLL down, drop the LDO to 1.1 V, park the FPGA 24 MHz clock (PA8 low), and halt the core in WFI until the next IRQ or the 1 ms SysTick wake. - Any timing-critical work holds a 288 MHz boost: AppMain wraps PacketReceived (which on the PM5 also covers a standalone mode, since it is only entered through a command there); the BWM low-batt poll and the RGB indicator wrap their I2C. Boost is refcounted and IRQ-guarded. - USB (OS image) moves to the crystal-less HICK-48 clock, ACC-trimmed against the SOF, so powering the PLL down never touches USB. The bootrom keeps the HEXT/PLL USB path (AS_BOOTROM), so DFU flashing is unchanged. - bwm_uart_clock_update() re-inits UART4 through the SDK usart_init() on each clock switch (the divider set at 288 MHz is 6x off at 48 MHz). - FpgaIsOff() (fpga_core.c, PM5 only) tracks the last conf word so the governor never downclocks while a reader field / emulation is running. - Wake preamble on the BWM link: the companion module firmware (Proxmark5_BWM_esp32) light-sleeps 2 s after the last byte on the link and its UART wakes on RX edges but loses the bytes that carried them. bwm_uart_write() therefore leads with four 0x55 bytes and a 10 ms settle on its first write and after 1 s without a write of its own (RX is not tracked: the ring can be drained long after the bytes came in). The module only starts light-sleeping once it has seen a preamble, so the one sent while it was still booting is repeated after the boot-time link negotiation. A module firmware without light sleep drops the preamble as noise. New `hw powersave on|off` toggles the governor at runtime (default on); `hw status` reports the idle-clock and WFI-asleep fractions. Behaviour change ---------------- - PM5 idles at 48 MHz with the PLL off and the CPU halted; it boosts to 288 MHz for commands and BWM housekeeping. Command timing and throughput are unchanged (intra-command work is always boosted). - PM5 USB now runs off HICK-48 (ACC-trimmed) instead of the HEXT PLL. - New command id CMD_PM5_POWERSAVE (0x0180). Testing ------- Built warning-free (gcc) for PLATFORM=PM5 (with and without PLATFORM_EXTRAS=BWM), PM3RDV4 and PM3GENERIC, armsrc and bootrom. Client built via the default Makefile. Not built with clang or on Windows/macOS; nothing outside PM5/AT32 guards changes. Flashed to a PM5 and exercised against a MIFARE Classic 4K card: hw version/status/ping (4000 & 512 B), hw tune, hf search, hf 14a info/reader (x12 across idle gaps), hf mf info/chk/rdbl, lf search/read, hw powersave off/on, held-field (raw -sk) correctly blocks the downclock, hw reset + re-enumerate. All pass; USB stays up across downclocks. Idle reaches ~80-95% at 48 MHz and ~90%+ WFI-halted after a few seconds idle. Measured at the USB port: idle draw 283 mA -> 207 mA with the stock BWM firmware. Co-authored-by: Soei Nova <soeinova@proton.me> Co-authored-by: noproto <noproto@zeroday.engineering> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>