// macro_config.cpp // NVM-Zugriff für die Makro-Tabelle (Row 0+1, 0x1FB00–0x1FCFF, 512 Bytes). // Nutzt dieselben NVMCTRL-Hilfsfunktionen wie nvm_config.cpp (dupliziert, // da static – kein gemeinsamer Header für interne NVM-Helfer). #include "macro_config.h" #include #include static const uint32_t k_macro_addr = 0x1FB00UL; // Row 0+1 (zwei Rows à 256B) static bool nvm_wait() { // ~400ms Timeout bei 48MHz, konservativ 4 Zyklen pro Loop-Iteration uint32_t timeout = 48000000UL / 4 * 400 / 1000; // ≈ 4 800 000 while (!NVMCTRL->INTFLAG.bit.READY) { if (--timeout == 0) return false; } return true; } static bool nvm_exec(uint16_t cmd) { NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMDEX_KEY | cmd; return nvm_wait(); } static bool nvm_erase_row(uint32_t addr) { if (!nvm_wait()) return false; NVMCTRL->ADDR.reg = addr / 2; return nvm_exec(NVMCTRL_CTRLA_CMD_ER); } static bool nvm_write_page(uint32_t addr, const uint8_t* data) { if (!nvm_exec(NVMCTRL_CTRLA_CMD_PBC)) return false; volatile uint32_t* dst = reinterpret_cast(addr); const uint32_t* src = reinterpret_cast(data); for (uint8_t i = 0; i < 64 / 4; i++) dst[i] = src[i]; NVMCTRL->ADDR.reg = addr / 2; return nvm_exec(NVMCTRL_CTRLA_CMD_WP); } bool macro_config_load(SMacroTable& tbl) { memcpy(&tbl, reinterpret_cast(k_macro_addr), sizeof(tbl)); // Prüfen ob beide Rows noch gelöscht sind (alle 0xFF = nie beschrieben) const uint8_t* raw = reinterpret_cast(&tbl); bool all_ff = true; for (uint16_t i = 0; i < sizeof(tbl); i++) { if (raw[i] != 0xFF) { all_ff = false; break; } } if (all_ff) { memset(&tbl, 0, sizeof(tbl)); // Leere Tabelle als Default return false; } return true; } bool macro_config_save(const SMacroTable& tbl) { // Auf 4-Byte-ausgerichteten Puffer kopieren bevor nvm_write_page ihn als uint32_t* liest. // SMacroTable ist __attribute__((packed)) und könnte unaligned liegen → // direkter uint32_t*-Cast würde auf Cortex-M0+ einen HardFault auslösen. uint8_t aligned_buf[512] __attribute__((aligned(4))); memcpy(aligned_buf, &tbl, sizeof(tbl)); NVMCTRL->CTRLB.bit.MANW = 1; // Beide Rows löschen (Row 0: 0x1FB00, Row 1: 0x1FC00) if (!nvm_erase_row(k_macro_addr)) return false; if (!nvm_erase_row(k_macro_addr + 256)) return false; // 8 Pages à 64B schreiben for (uint8_t p = 0; p < 8; p++) { if (!nvm_write_page(k_macro_addr + p * 64, aligned_buf + p * 64)) return false; } return true; }