interrupt_handlers.c
1631 bytes
1// Copyright 2023 Nick Brassel (@tzarc)
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4///////////////////////////////////////////////////////////////////////////////
5// BEGIN: STM32 EFL Wear-leveling ECC fault handling
6//
7// Some STM32s have ECC checks for all flash memory access. Whenever there's an
8// ECC failure, the MCU raises the NMI interrupt. Whenever we receive such an
9// interrupt whilst reading the wear-leveling EEPROM area, we gracefully cater
10// for it, signalling the wear-leveling code that a failure has occurred.
11///////////////////////////////////////////////////////////////////////////////
12
13#include <ch.h>
14#include <chcore.h>
15
16#ifdef WEAR_LEVELING_EMBEDDED_FLASH
17# ifdef QMK_MCU_SERIES_STM32L4XX
18# define ECC_ERRORS_TRIGGER_NMI_INTERRUPT
19# define ECC_CHECK_REGISTER FLASH->ECCR
20# define ECC_CHECK_FLAG FLASH_ECCR_ECCD
21# endif // QMK_MCU_SERIES_STM32L4XX
22#endif // WEAR_LEVELING_EMBEDDED_FLASH
23
24#ifdef ECC_ERRORS_TRIGGER_NMI_INTERRUPT
25
26extern bool backing_store_allow_ecc_errors(void);
27extern void backing_store_signal_ecc_error(void);
28
29void NMI_Handler(void) {
30 if ((ECC_CHECK_REGISTER) & (ECC_CHECK_FLAG)) {
31 if (backing_store_allow_ecc_errors()) {
32 (ECC_CHECK_REGISTER) = (ECC_CHECK_FLAG);
33 backing_store_signal_ecc_error();
34 return;
35 }
36 }
37
38 chSysHalt("NMI");
39}
40
41#endif // ECC_ERRORS_TRIGGER_NMI_INTERRUPT
42
43///////////////////////////////////////////////////////////////////////////////
44// END: STM32 EFL Wear-leveling ECC fault handling
45///////////////////////////////////////////////////////////////////////////////