Skip to content

Commit a709055

Browse files
boringethanclaude
andcommitted
fix(fw): move odometer to its own flash sector (sector 6 bank 2)
The odometer and motion_config (calibration JSON) were both writing to sector 7 bank 2 (0x081E0000) via `FLASH_USER_START_ADDR`. STM32H7 flash can only be erased at sector granularity, and both modules call `Flash_Erase` for the full sector on save. Whichever wrote last wiped the other tenant's data. Symptom: flashing the integration branch onto a console that already had a stored calibration produced "no calibration on device or invalid" on the next connect, because `Odometer_Init` saw a non-magic block (the calibration JSON), treated it as first-boot, and erased the sector to write a fresh zero odometer block. Fix: dedicate sector 6 bank 2 (0x081C0000) to the odometer. - STM32H743XX_FLASH.ld + STM32H743VIHX_FLASH.ld: trim FLASH region from 1920 KB to 1792 KB so the linker reserves both sectors 6 and 7 of bank 2 for persistent data. (Code uses 8.5% of the remaining region; no risk of crowding.) - memory_map.h: add FLASH_ODOMETER_START_ADDR alongside FLASH_USER_START_ADDR. - odometer.h: point ODOMETER_FLASH_BASE_ADDR at the new sector and document why the two stores must not co-tenant. Action for already-flashed consoles: calibration must be re-loaded (or re-run) once after flashing this build, since the existing calibration on hardware that ran the buggy firmware was already wiped. After this flash, calibration and odometer writes are independent — no further clobbering. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent cde2d0f commit a709055

4 files changed

Lines changed: 29 additions & 8 deletions

File tree

Core/Inc/memory_map.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,14 @@
3535
#define ADDR_FLASH_SECTOR_6_BANK2 ((uint32_t)0x081C0000) /* Base @ of Sector 6, 128 Kbytes */
3636
#define ADDR_FLASH_SECTOR_7_BANK2 ((uint32_t)0x081E0000) /* Base @ of Sector 7, 128 Kbytes */
3737

38-
#define ADDR_FLASH_END_ADDRESS ((uint32_t)0x08200000)
39-
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_7_BANK2
38+
#define ADDR_FLASH_END_ADDRESS ((uint32_t)0x08200000)
39+
40+
/* Reserved persistent-data sectors. Each persists via full-sector erase
41+
* (the STM32H7 flash sector is 128 KB and that is the minimum erase
42+
* granularity), so two distinct tenants need two distinct sectors. The
43+
* linker script reserves both by capping FLASH at 1792 KB. */
44+
#define FLASH_USER_START_ADDR ADDR_FLASH_SECTOR_7_BANK2 /* motion_config / calibration */
45+
#define FLASH_ODOMETER_START_ADDR ADDR_FLASH_SECTOR_6_BANK2 /* system + laser odometer */
4046

4147
#ifdef __cplusplus
4248
}

Core/Inc/odometer.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,18 @@
99
#define INC_ODOMETER_H_
1010

1111
#include "stm32h7xx_hal.h"
12+
#include "memory_map.h"
1213
#include <stdint.h>
1314
#include <stdbool.h>
1415

15-
/* Flash memory addresses for odometer storage */
16-
#define ODOMETER_FLASH_BASE_ADDR (FLASH_USER_START_ADDR)
16+
/* Flash memory addresses for odometer storage.
17+
*
18+
* Lives in its own 128 KB sector (sector 6 bank 2 via FLASH_ODOMETER_START_ADDR),
19+
* distinct from FLASH_USER_START_ADDR which is owned by motion_config. The
20+
* STM32H7 minimum erase granularity is one 128 KB sector, so the two stores
21+
* must not co-tenant — otherwise either Odometer_Persist_Both() or
22+
* motion_cfg flash writes would wipe the other tenant. */
23+
#define ODOMETER_FLASH_BASE_ADDR (FLASH_ODOMETER_START_ADDR)
1724
#define SYSTEM_ODO_FLASH_ADDR (ODOMETER_FLASH_BASE_ADDR)
1825
#define LASER_ODO_FLASH_ADDR (ODOMETER_FLASH_BASE_ADDR + 32)
1926

STM32H743VIHX_FLASH.ld

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,12 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
4343
/* Specify the memory areas */
4444
MEMORY
4545
{
46-
/* Reserve the last 128KB sector (Bank2 Sector7 @ 0x081E0000) for user config. */
47-
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1920K
46+
/* Reserve the last two 128KB sectors of Bank 2 for persistent data:
47+
* Sector 7 (@ 0x081E0000) — motion_config / calibration JSON
48+
* Sector 6 (@ 0x081C0000) — odometer (system uptime + laser pulses)
49+
* Each persists via full-sector erase, so they cannot co-tenant a sector.
50+
* Trimming code to 1792 KB still leaves >10x headroom for current build. */
51+
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1792K
4852
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
4953
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
5054
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K

STM32H743XX_FLASH.ld

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,12 @@ RAM (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
6060
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
6161
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
6262
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
63-
/* Reserve the last 128KB sector (Bank2 Sector7 @ 0x081E0000) for user config. */
64-
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1920K
63+
/* Reserve the last two 128KB sectors of Bank 2 for persistent data:
64+
* Sector 7 (@ 0x081E0000) — motion_config / calibration JSON
65+
* Sector 6 (@ 0x081C0000) — odometer (system uptime + laser pulses)
66+
* Each persists via full-sector erase, so they cannot co-tenant a sector.
67+
* Trimming code to 1792 KB still leaves >10x headroom for current build. */
68+
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1792K
6569
}
6670

6771
/* Highest address of the user mode stack */

0 commit comments

Comments
 (0)