#include "pid_flash.h" #include "stm32f7xx_hal.h" #include bool pid_flash_load(float *kp, float *ki, float *kd) { const pid_flash_t *p = (const pid_flash_t *)PID_FLASH_STORE_ADDR; if (p->magic != PID_FLASH_MAGIC) return false; /* Basic sanity bounds — same as JLINK_CMD_PID_SET handler */ if (p->kp < 0.0f || p->kp > 500.0f) return false; if (p->ki < 0.0f || p->ki > 50.0f) return false; if (p->kd < 0.0f || p->kd > 50.0f) return false; *kp = p->kp; *ki = p->ki; *kd = p->kd; return true; } bool pid_flash_save(float kp, float ki, float kd) { HAL_StatusTypeDef rc; /* Unlock flash */ rc = HAL_FLASH_Unlock(); if (rc != HAL_OK) return false; /* Erase sector 7 */ FLASH_EraseInitTypeDef erase = { .TypeErase = FLASH_TYPEERASE_SECTORS, .Sector = PID_FLASH_SECTOR, .NbSectors = 1, .VoltageRange = PID_FLASH_SECTOR_VOLTAGE, }; uint32_t sector_error = 0; rc = HAL_FLASHEx_Erase(&erase, §or_error); if (rc != HAL_OK || sector_error != 0xFFFFFFFFUL) { HAL_FLASH_Lock(); return false; } /* Build record */ pid_flash_t rec; memset(&rec, 0xFF, sizeof(rec)); rec.magic = PID_FLASH_MAGIC; rec.kp = kp; rec.ki = ki; rec.kd = kd; /* Write 64 bytes as 16 × 32-bit words */ const uint32_t *src = (const uint32_t *)&rec; uint32_t addr = PID_FLASH_STORE_ADDR; for (uint8_t i = 0; i < sizeof(rec) / 4u; i++) { rc = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, src[i]); if (rc != HAL_OK) { HAL_FLASH_Lock(); return false; } addr += 4u; } HAL_FLASH_Lock(); /* Verify readback */ const pid_flash_t *stored = (const pid_flash_t *)PID_FLASH_STORE_ADDR; return (stored->magic == PID_FLASH_MAGIC && stored->kp == kp && stored->ki == ki && stored->kd == kd); } /* ---- Helper: write arbitrary bytes as 32-bit words ---- */ /* * Writes 'len' bytes from 'src' to flash at 'addr'. * len must be a multiple of 4. Flash must already be unlocked. * Returns HAL_OK on success, or first failure status. */ static HAL_StatusTypeDef flash_write_words(uint32_t addr, const void *src, uint32_t len) { const uint32_t *p = (const uint32_t *)src; HAL_StatusTypeDef rc = HAL_OK; for (uint32_t i = 0; i < len / 4u; i++) { rc = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, p[i]); if (rc != HAL_OK) return rc; addr += 4u; } return HAL_OK; } /* ---- pid_flash_load_schedule() ---- */ bool pid_flash_load_schedule(pid_sched_entry_t *out_entries, uint8_t *out_n) { const pid_sched_flash_t *p = (const pid_sched_flash_t *)PID_SCHED_FLASH_ADDR; if (p->magic != PID_SCHED_MAGIC) return false; if (p->num_bands == 0u || p->num_bands > PID_SCHED_MAX_BANDS) return false; *out_n = p->num_bands; for (uint8_t i = 0; i < p->num_bands; i++) { out_entries[i] = p->bands[i]; } return true; } /* ---- pid_flash_save_all() ---- */ bool pid_flash_save_all(float kp_single, float ki_single, float kd_single, const pid_sched_entry_t *entries, uint8_t num_bands) { if (num_bands == 0u || num_bands > PID_SCHED_MAX_BANDS) return false; HAL_StatusTypeDef rc; rc = HAL_FLASH_Unlock(); if (rc != HAL_OK) return false; /* Single erase of sector 7 covers both records */ FLASH_EraseInitTypeDef erase = { .TypeErase = FLASH_TYPEERASE_SECTORS, .Sector = PID_FLASH_SECTOR, .NbSectors = 1, .VoltageRange = PID_FLASH_SECTOR_VOLTAGE, }; uint32_t sector_error = 0; rc = HAL_FLASHEx_Erase(&erase, §or_error); if (rc != HAL_OK || sector_error != 0xFFFFFFFFUL) { HAL_FLASH_Lock(); return false; } /* Build and write schedule record at PID_SCHED_FLASH_ADDR */ pid_sched_flash_t srec; memset(&srec, 0xFF, sizeof(srec)); srec.magic = PID_SCHED_MAGIC; srec.num_bands = num_bands; srec.flags = 0u; for (uint8_t i = 0; i < num_bands; i++) { srec.bands[i] = entries[i]; } rc = flash_write_words(PID_SCHED_FLASH_ADDR, &srec, sizeof(srec)); if (rc != HAL_OK) { HAL_FLASH_Lock(); return false; } /* Build and write single-PID record at PID_FLASH_STORE_ADDR */ pid_flash_t prec; memset(&prec, 0xFF, sizeof(prec)); prec.magic = PID_FLASH_MAGIC; prec.kp = kp_single; prec.ki = ki_single; prec.kd = kd_single; rc = flash_write_words(PID_FLASH_STORE_ADDR, &prec, sizeof(prec)); if (rc != HAL_OK) { HAL_FLASH_Lock(); return false; } HAL_FLASH_Lock(); /* Verify both records */ const pid_sched_flash_t *sv = (const pid_sched_flash_t *)PID_SCHED_FLASH_ADDR; const pid_flash_t *pv = (const pid_flash_t *)PID_FLASH_STORE_ADDR; return (sv->magic == PID_SCHED_MAGIC && sv->num_bands == num_bands && pv->magic == PID_FLASH_MAGIC && pv->kp == kp_single && pv->ki == ki_single && pv->kd == kd_single); }