diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2c858831ed86a80964624b7c2f84fdc3338b0aba..72dfec3d779256845c691e855da0396714f59ce2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -290,6 +290,9 @@ sbs_target(test-i2c-f7 stm32f767zi_nucleo)
 add_executable(test-wiz5500 src/tests/drivers/test-wiz5500.cpp)
 sbs_target(test-wiz5500 stm32f767zi_gemini_gs)
 
+add_executable(test-bsram src/tests/drivers/test-bsram.cpp)
+sbs_target(test-bsram stm32f767zi_lyra_biscotto)
+
 #-----------------------------------------------------------------------------#
 #                               Tests - Events                                #
 #-----------------------------------------------------------------------------#
diff --git a/libs/miosix-kernel b/libs/miosix-kernel
index 8bd5f902130fbde9235a0af750f59b9353ec3451..a52d94acbfd617ae567a5efc1626e9b88703a0dd 160000
--- a/libs/miosix-kernel
+++ b/libs/miosix-kernel
@@ -1 +1 @@
-Subproject commit 8bd5f902130fbde9235a0af750f59b9353ec3451
+Subproject commit a52d94acbfd617ae567a5efc1626e9b88703a0dd
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/config/board_options.cmake b/src/bsps/stm32f767zi_compute_unit_v2/config/board_options.cmake
index bc751fb1b2b7ecce6c7add7bf61a3cc23038a693..0028955170363faa88ecb730fbeea85b6818f66f 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/config/board_options.cmake
+++ b/src/bsps/stm32f767zi_compute_unit_v2/config/board_options.cmake
@@ -103,4 +103,5 @@ set(ARCH_SRC
     ${KPATH}/arch/common/drivers/sd_stm32f2_f4_f7.cpp
     ${KPATH}/arch/common/drivers/serial_stm32.cpp
     ${KPATH}/arch/common/drivers/stm32_hardware_rng.cpp
+    ${KPATH}/arch/common/drivers/stm32_bsram.cpp
 )
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/config/board_options_no_xram.cmake b/src/bsps/stm32f767zi_compute_unit_v2/config/board_options_no_xram.cmake
index e16999d91d3d137f94caf4e64654575e4bdeb1c6..ac3f3e5fc97409cf570f5a4e416c50d808c24d65 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/config/board_options_no_xram.cmake
+++ b/src/bsps/stm32f767zi_compute_unit_v2/config/board_options_no_xram.cmake
@@ -103,4 +103,5 @@ set(ARCH_SRC
     ${KPATH}/arch/common/drivers/sd_stm32f2_f4_f7.cpp
     ${KPATH}/arch/common/drivers/serial_stm32.cpp
     ${KPATH}/arch/common/drivers/stm32_hardware_rng.cpp
+    ${KPATH}/arch/common/drivers/stm32_bsram.cpp
 )
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/core/stage_1_boot.cpp b/src/bsps/stm32f767zi_compute_unit_v2/core/stage_1_boot.cpp
index 83eac53b4b0b56309c0a9c26aacb7ff4289558d0..95d830c5c71f91b8ccc78c62ff5cb7c9a462b0c2 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/core/stage_1_boot.cpp
+++ b/src/bsps/stm32f767zi_compute_unit_v2/core/stage_1_boot.cpp
@@ -68,6 +68,8 @@ void program_startup()
     memcpy(data, etext, edata - data);
     memset(bss_start, 0, bss_end - bss_start);
 
+    miosix::configureBackupSram();
+
     // Move on to stage 2
     _init();
 
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp.cpp b/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp.cpp
index 366e5457e1fa63b17abf93c563edae9ce5755213..cebec9b0160ce8cfabad83a3db3bc6005df6321f 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp.cpp
+++ b/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp.cpp
@@ -37,7 +37,7 @@
 #include "drivers/sd_stm32f2_f4_f7.h"
 #include "drivers/serial.h"
 #include "drivers/serial_stm32.h"
-#include "drivers/stm32_sgm.h"
+#include "drivers/stm32_bsram.h"
 #include "filesystem/console/console_device.h"
 #include "filesystem/file_access.h"
 #include "interfaces/arch_registers.h"
@@ -222,6 +222,28 @@ void configureSdram()
 #endif
 }
 
+void configureBackupSram()
+{
+    // Initialize the backup SRAM device
+    BSRAM::init();
+
+    // Defined in the linker script
+    extern unsigned char _preserve_start asm("_preserve_start");
+    extern unsigned char _preserve_end asm("_preserve_end");
+    extern unsigned char _preserve_load asm("_preserve_load");
+
+    unsigned char *preserve_start = &_preserve_start;
+    unsigned char *preserve_end   = &_preserve_end;
+    unsigned char *preserve_load  = &_preserve_load;
+
+    // Load the .preserve section from flash if not a software reset
+    if (miosix::lastResetReason() != miosix::ResetReason::SOFTWARE)
+    {
+        BSRAM::EnableWriteLock l;
+        memcpy(preserve_start, preserve_load, preserve_end - preserve_start);
+    }
+}
+
 void IRQbspInit()
 {
     // Enable USART1 pins port
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp_impl.h b/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp_impl.h
index feb02c1280930087540af07157270b0ac858f57c..6cbcdde743840c5890416a8aaffcf2b3d3d5eaca 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp_impl.h
+++ b/src/bsps/stm32f767zi_compute_unit_v2/interfaces-impl/bsp_impl.h
@@ -31,6 +31,15 @@
 #include "config/miosix_settings.h"
 #include "interfaces/gpio.h"
 
+/**
+ * Macro to place a variable in the backup SRAM. Variables are allowed to have a
+ * default value. The kernel initializes the variable to the provided value if
+ * the reset reason is not a software reset.
+ *
+ * Example usage: `PRESERVE int myVar = 0;`
+ */
+#define PRESERVE __attribute__((section(".preserve")))
+
 namespace miosix
 {
 
@@ -46,6 +55,13 @@ namespace miosix
  */
 void configureSdram();
 
+/**
+ * \internal
+ * Called by stage_1_boot.cpp to configure the backup SRAM and .preserve region
+ * Requires the CPU clock to be already configured (running from the PLL)
+ */
+void configureBackupSram();
+
 /**
  * \internal
  * Board pin definition
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+32m_xram.ld b/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+32m_xram.ld
index 044ba1c62814ca2a4081a49fa5bca4d686ca16d5..3c7843ff586ea8d42f88f51c0fb55eba92badcca 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+32m_xram.ld
+++ b/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+32m_xram.ld
@@ -178,7 +178,7 @@ SECTIONS
     _end = .;
     PROVIDE(end = .);
     
-    .preserve(NOLOAD) : ALIGN(4)
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -186,5 +186,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+384k_ram.ld b/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+384k_ram.ld
index 497bd5198760b9637c774bf3900fd9dfbc01a2b2..b25d3fe8e93d1fad0573ec2067b3e703040b7eba 100644
--- a/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+384k_ram.ld
+++ b/src/bsps/stm32f767zi_compute_unit_v2/stm32_2m+384k_ram.ld
@@ -177,7 +177,7 @@ SECTIONS
     _end = .;
     PROVIDE(end = .);
     
-    .preserve(NOLOAD) : ALIGN(4)
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -185,5 +185,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_lyra_biscotto/config/board_options.cmake b/src/bsps/stm32f767zi_lyra_biscotto/config/board_options.cmake
index 955e95ee82285219d583cd3e8a73e7a9259584ae..1f21a96fb6da6f81cde3f259f1a60abd7480e2e8 100644
--- a/src/bsps/stm32f767zi_lyra_biscotto/config/board_options.cmake
+++ b/src/bsps/stm32f767zi_lyra_biscotto/config/board_options.cmake
@@ -103,4 +103,5 @@ set(ARCH_SRC
     ${KPATH}/arch/common/drivers/sd_stm32f2_f4_f7.cpp
     ${KPATH}/arch/common/drivers/serial_stm32.cpp
     ${KPATH}/arch/common/drivers/stm32_hardware_rng.cpp
+    ${KPATH}/arch/common/drivers/stm32_bsram.cpp
 )
diff --git a/src/bsps/stm32f767zi_lyra_biscotto/core/stage_1_boot.cpp b/src/bsps/stm32f767zi_lyra_biscotto/core/stage_1_boot.cpp
index 83eac53b4b0b56309c0a9c26aacb7ff4289558d0..95d830c5c71f91b8ccc78c62ff5cb7c9a462b0c2 100644
--- a/src/bsps/stm32f767zi_lyra_biscotto/core/stage_1_boot.cpp
+++ b/src/bsps/stm32f767zi_lyra_biscotto/core/stage_1_boot.cpp
@@ -68,6 +68,8 @@ void program_startup()
     memcpy(data, etext, edata - data);
     memset(bss_start, 0, bss_end - bss_start);
 
+    miosix::configureBackupSram();
+
     // Move on to stage 2
     _init();
 
diff --git a/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp.cpp b/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp.cpp
index ba299ab90c3eb8b74e40ba541d395ae07731cb0a..e48915e327ee42f901d41805c8cbca0a91134fd1 100644
--- a/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp.cpp
+++ b/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp.cpp
@@ -37,7 +37,7 @@
 #include "drivers/sd_stm32f2_f4_f7.h"
 #include "drivers/serial.h"
 #include "drivers/serial_stm32.h"
-#include "drivers/stm32_sgm.h"
+#include "drivers/stm32_bsram.h"
 #include "filesystem/console/console_device.h"
 #include "filesystem/file_access.h"
 #include "hwmapping.h"
@@ -223,6 +223,28 @@ void configureSdram()
 #endif
 }
 
+void configureBackupSram()
+{
+    // Initialize the backup SRAM device
+    BSRAM::init();
+
+    // Defined in the linker script
+    extern unsigned char _preserve_start asm("_preserve_start");
+    extern unsigned char _preserve_end asm("_preserve_end");
+    extern unsigned char _preserve_load asm("_preserve_load");
+
+    unsigned char *preserve_start = &_preserve_start;
+    unsigned char *preserve_end   = &_preserve_end;
+    unsigned char *preserve_load  = &_preserve_load;
+
+    // Load the .preserve section from flash if not a software reset
+    if (miosix::lastResetReason() != miosix::ResetReason::SOFTWARE)
+    {
+        BSRAM::EnableWriteLock l;
+        memcpy(preserve_start, preserve_load, preserve_end - preserve_start);
+    }
+}
+
 void IRQbspInit()
 {
     // Enable USART1 pins port
diff --git a/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp_impl.h b/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp_impl.h
index feb02c1280930087540af07157270b0ac858f57c..6cbcdde743840c5890416a8aaffcf2b3d3d5eaca 100644
--- a/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp_impl.h
+++ b/src/bsps/stm32f767zi_lyra_biscotto/interfaces-impl/bsp_impl.h
@@ -31,6 +31,15 @@
 #include "config/miosix_settings.h"
 #include "interfaces/gpio.h"
 
+/**
+ * Macro to place a variable in the backup SRAM. Variables are allowed to have a
+ * default value. The kernel initializes the variable to the provided value if
+ * the reset reason is not a software reset.
+ *
+ * Example usage: `PRESERVE int myVar = 0;`
+ */
+#define PRESERVE __attribute__((section(".preserve")))
+
 namespace miosix
 {
 
@@ -46,6 +55,13 @@ namespace miosix
  */
 void configureSdram();
 
+/**
+ * \internal
+ * Called by stage_1_boot.cpp to configure the backup SRAM and .preserve region
+ * Requires the CPU clock to be already configured (running from the PLL)
+ */
+void configureBackupSram();
+
 /**
  * \internal
  * Board pin definition
diff --git a/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+32m_xram.ld b/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+32m_xram.ld
index 044ba1c62814ca2a4081a49fa5bca4d686ca16d5..991fc8a4b132a01c80247fd23c5cc5c885a94d7b 100644
--- a/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+32m_xram.ld
+++ b/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+32m_xram.ld
@@ -177,8 +177,12 @@ SECTIONS
 
     _end = .;
     PROVIDE(end = .);
-    
-    .preserve(NOLOAD) : ALIGN(4)
+
+    /*
+     * .preserve section: global variables preserved across software reboots go
+     * to bram, but also store a copy to flash to initialize them
+     */
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -186,5 +190,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+384k_ram.ld b/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+384k_ram.ld
index 497bd5198760b9637c774bf3900fd9dfbc01a2b2..a0c1415c382a477b1adbd11e91ec1af334f44466 100644
--- a/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+384k_ram.ld
+++ b/src/bsps/stm32f767zi_lyra_biscotto/stm32_2m+384k_ram.ld
@@ -176,8 +176,12 @@ SECTIONS
 
     _end = .;
     PROVIDE(end = .);
-    
-    .preserve(NOLOAD) : ALIGN(4)
+
+    /*
+     * .preserve section: global variables preserved across software reboots go
+     * to bram, but also store a copy to flash to initialize them
+     */
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -185,5 +189,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_lyra_motor/config/board_options.cmake b/src/bsps/stm32f767zi_lyra_motor/config/board_options.cmake
index 23ec4d215754bd85ad99c104802e53cf7a8423f7..75d406fa5f2ca9a99b8aa8d1e1f37b50a71cbb48 100644
--- a/src/bsps/stm32f767zi_lyra_motor/config/board_options.cmake
+++ b/src/bsps/stm32f767zi_lyra_motor/config/board_options.cmake
@@ -103,4 +103,5 @@ set(ARCH_SRC
     ${KPATH}/arch/common/drivers/sd_stm32f2_f4_f7.cpp
     ${KPATH}/arch/common/drivers/serial_stm32.cpp
     ${KPATH}/arch/common/drivers/stm32_hardware_rng.cpp
+    ${KPATH}/arch/common/drivers/stm32_bsram.cpp
 )
diff --git a/src/bsps/stm32f767zi_lyra_motor/core/stage_1_boot.cpp b/src/bsps/stm32f767zi_lyra_motor/core/stage_1_boot.cpp
index 83eac53b4b0b56309c0a9c26aacb7ff4289558d0..95d830c5c71f91b8ccc78c62ff5cb7c9a462b0c2 100644
--- a/src/bsps/stm32f767zi_lyra_motor/core/stage_1_boot.cpp
+++ b/src/bsps/stm32f767zi_lyra_motor/core/stage_1_boot.cpp
@@ -68,6 +68,8 @@ void program_startup()
     memcpy(data, etext, edata - data);
     memset(bss_start, 0, bss_end - bss_start);
 
+    miosix::configureBackupSram();
+
     // Move on to stage 2
     _init();
 
diff --git a/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp.cpp b/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp.cpp
index 1ac009ad000c06421bd21a764b6635e7dacee1ea..6698f1979cdc34cca79965cfb98a9bff54f862b5 100644
--- a/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp.cpp
+++ b/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp.cpp
@@ -37,7 +37,7 @@
 #include "drivers/sd_stm32f2_f4_f7.h"
 #include "drivers/serial.h"
 #include "drivers/serial_stm32.h"
-#include "drivers/stm32_sgm.h"
+#include "drivers/stm32_bsram.h"
 #include "filesystem/console/console_device.h"
 #include "filesystem/file_access.h"
 #include "hwmapping.h"
@@ -223,6 +223,28 @@ void configureSdram()
 #endif
 }
 
+void configureBackupSram()
+{
+    // Initialize the backup SRAM device
+    BSRAM::init();
+
+    // Defined in the linker script
+    extern unsigned char _preserve_start asm("_preserve_start");
+    extern unsigned char _preserve_end asm("_preserve_end");
+    extern unsigned char _preserve_load asm("_preserve_load");
+
+    unsigned char *preserve_start = &_preserve_start;
+    unsigned char *preserve_end   = &_preserve_end;
+    unsigned char *preserve_load  = &_preserve_load;
+
+    // Load the .preserve section from flash if not a software reset
+    if (miosix::lastResetReason() != miosix::ResetReason::SOFTWARE)
+    {
+        BSRAM::EnableWriteLock l;
+        memcpy(preserve_start, preserve_load, preserve_end - preserve_start);
+    }
+}
+
 void IRQbspInit()
 {
     // Enable USART1 pins port
diff --git a/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp_impl.h b/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp_impl.h
index feb02c1280930087540af07157270b0ac858f57c..6cbcdde743840c5890416a8aaffcf2b3d3d5eaca 100644
--- a/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp_impl.h
+++ b/src/bsps/stm32f767zi_lyra_motor/interfaces-impl/bsp_impl.h
@@ -31,6 +31,15 @@
 #include "config/miosix_settings.h"
 #include "interfaces/gpio.h"
 
+/**
+ * Macro to place a variable in the backup SRAM. Variables are allowed to have a
+ * default value. The kernel initializes the variable to the provided value if
+ * the reset reason is not a software reset.
+ *
+ * Example usage: `PRESERVE int myVar = 0;`
+ */
+#define PRESERVE __attribute__((section(".preserve")))
+
 namespace miosix
 {
 
@@ -46,6 +55,13 @@ namespace miosix
  */
 void configureSdram();
 
+/**
+ * \internal
+ * Called by stage_1_boot.cpp to configure the backup SRAM and .preserve region
+ * Requires the CPU clock to be already configured (running from the PLL)
+ */
+void configureBackupSram();
+
 /**
  * \internal
  * Board pin definition
diff --git a/src/bsps/stm32f767zi_lyra_motor/stm32_2m+32m_xram.ld b/src/bsps/stm32f767zi_lyra_motor/stm32_2m+32m_xram.ld
index 044ba1c62814ca2a4081a49fa5bca4d686ca16d5..3c7843ff586ea8d42f88f51c0fb55eba92badcca 100644
--- a/src/bsps/stm32f767zi_lyra_motor/stm32_2m+32m_xram.ld
+++ b/src/bsps/stm32f767zi_lyra_motor/stm32_2m+32m_xram.ld
@@ -178,7 +178,7 @@ SECTIONS
     _end = .;
     PROVIDE(end = .);
     
-    .preserve(NOLOAD) : ALIGN(4)
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -186,5 +186,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_lyra_motor/stm32_2m+384k_ram.ld b/src/bsps/stm32f767zi_lyra_motor/stm32_2m+384k_ram.ld
index 497bd5198760b9637c774bf3900fd9dfbc01a2b2..b25d3fe8e93d1fad0573ec2067b3e703040b7eba 100644
--- a/src/bsps/stm32f767zi_lyra_motor/stm32_2m+384k_ram.ld
+++ b/src/bsps/stm32f767zi_lyra_motor/stm32_2m+384k_ram.ld
@@ -177,7 +177,7 @@ SECTIONS
     _end = .;
     PROVIDE(end = .);
     
-    .preserve(NOLOAD) : ALIGN(4)
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -185,5 +185,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_rig_v2/config/board_options.cmake b/src/bsps/stm32f767zi_rig_v2/config/board_options.cmake
index a7586b6b8252cd68321f195967b57be8bfcb30f8..e62c44e7cf899a1ec6e8dfdae12a77f739d5c083 100644
--- a/src/bsps/stm32f767zi_rig_v2/config/board_options.cmake
+++ b/src/bsps/stm32f767zi_rig_v2/config/board_options.cmake
@@ -103,4 +103,5 @@ set(ARCH_SRC
     ${KPATH}/arch/common/drivers/sd_stm32f2_f4_f7.cpp
     ${KPATH}/arch/common/drivers/serial_stm32.cpp
     ${KPATH}/arch/common/drivers/stm32_hardware_rng.cpp
+    ${KPATH}/arch/common/drivers/stm32_bsram.cpp
 )
diff --git a/src/bsps/stm32f767zi_rig_v2/core/stage_1_boot.cpp b/src/bsps/stm32f767zi_rig_v2/core/stage_1_boot.cpp
index 83eac53b4b0b56309c0a9c26aacb7ff4289558d0..95d830c5c71f91b8ccc78c62ff5cb7c9a462b0c2 100644
--- a/src/bsps/stm32f767zi_rig_v2/core/stage_1_boot.cpp
+++ b/src/bsps/stm32f767zi_rig_v2/core/stage_1_boot.cpp
@@ -68,6 +68,8 @@ void program_startup()
     memcpy(data, etext, edata - data);
     memset(bss_start, 0, bss_end - bss_start);
 
+    miosix::configureBackupSram();
+
     // Move on to stage 2
     _init();
 
diff --git a/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp.cpp b/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp.cpp
index c796ad7dfce926c3c1a3e0900b133193ecc31d86..2c764c17e533c986fee63a0a288905cd29928560 100644
--- a/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp.cpp
+++ b/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp.cpp
@@ -37,7 +37,7 @@
 #include "drivers/sd_stm32f2_f4_f7.h"
 #include "drivers/serial.h"
 #include "drivers/serial_stm32.h"
-#include "drivers/stm32_sgm.h"
+#include "drivers/stm32_bsram.h"
 #include "filesystem/console/console_device.h"
 #include "filesystem/file_access.h"
 #include "hwmapping.h"
@@ -223,6 +223,28 @@ void configureSdram()
 #endif
 }
 
+void configureBackupSram()
+{
+    // Initialize the backup SRAM device
+    BSRAM::init();
+
+    // Defined in the linker script
+    extern unsigned char _preserve_start asm("_preserve_start");
+    extern unsigned char _preserve_end asm("_preserve_end");
+    extern unsigned char _preserve_load asm("_preserve_load");
+
+    unsigned char *preserve_start = &_preserve_start;
+    unsigned char *preserve_end   = &_preserve_end;
+    unsigned char *preserve_load  = &_preserve_load;
+
+    // Load the .preserve section from flash if not a software reset
+    if (miosix::lastResetReason() != miosix::ResetReason::SOFTWARE)
+    {
+        BSRAM::EnableWriteLock l;
+        memcpy(preserve_start, preserve_load, preserve_end - preserve_start);
+    }
+}
+
 void IRQbspInit()
 {
     // Enable USART1 pins port
diff --git a/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp_impl.h b/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp_impl.h
index feb02c1280930087540af07157270b0ac858f57c..6cbcdde743840c5890416a8aaffcf2b3d3d5eaca 100644
--- a/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp_impl.h
+++ b/src/bsps/stm32f767zi_rig_v2/interfaces-impl/bsp_impl.h
@@ -31,6 +31,15 @@
 #include "config/miosix_settings.h"
 #include "interfaces/gpio.h"
 
+/**
+ * Macro to place a variable in the backup SRAM. Variables are allowed to have a
+ * default value. The kernel initializes the variable to the provided value if
+ * the reset reason is not a software reset.
+ *
+ * Example usage: `PRESERVE int myVar = 0;`
+ */
+#define PRESERVE __attribute__((section(".preserve")))
+
 namespace miosix
 {
 
@@ -46,6 +55,13 @@ namespace miosix
  */
 void configureSdram();
 
+/**
+ * \internal
+ * Called by stage_1_boot.cpp to configure the backup SRAM and .preserve region
+ * Requires the CPU clock to be already configured (running from the PLL)
+ */
+void configureBackupSram();
+
 /**
  * \internal
  * Board pin definition
diff --git a/src/bsps/stm32f767zi_rig_v2/stm32_2m+32m_xram.ld b/src/bsps/stm32f767zi_rig_v2/stm32_2m+32m_xram.ld
index 044ba1c62814ca2a4081a49fa5bca4d686ca16d5..3c7843ff586ea8d42f88f51c0fb55eba92badcca 100644
--- a/src/bsps/stm32f767zi_rig_v2/stm32_2m+32m_xram.ld
+++ b/src/bsps/stm32f767zi_rig_v2/stm32_2m+32m_xram.ld
@@ -178,7 +178,7 @@ SECTIONS
     _end = .;
     PROVIDE(end = .);
     
-    .preserve(NOLOAD) : ALIGN(4)
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -186,5 +186,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/bsps/stm32f767zi_rig_v2/stm32_2m+384k_ram.ld b/src/bsps/stm32f767zi_rig_v2/stm32_2m+384k_ram.ld
index 497bd5198760b9637c774bf3900fd9dfbc01a2b2..b25d3fe8e93d1fad0573ec2067b3e703040b7eba 100644
--- a/src/bsps/stm32f767zi_rig_v2/stm32_2m+384k_ram.ld
+++ b/src/bsps/stm32f767zi_rig_v2/stm32_2m+384k_ram.ld
@@ -177,7 +177,7 @@ SECTIONS
     _end = .;
     PROVIDE(end = .);
     
-    .preserve(NOLOAD) : ALIGN(4)
+    .preserve : ALIGN(4)
     {
         _preserve_start = .;
         . = ALIGN(4);
@@ -185,5 +185,6 @@ SECTIONS
         *(.preserve*);
         . = ALIGN(4);
         _preserve_end = .;
-    } > bram
+    } > bram AT > flash
+    _preserve_load = LOADADDR(.preserve);
 }
diff --git a/src/tests/drivers/test-bsram.cpp b/src/tests/drivers/test-bsram.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8fcda4ab0c1fefc3182629a98290bb9937a4b7f2
--- /dev/null
+++ b/src/tests/drivers/test-bsram.cpp
@@ -0,0 +1,102 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Authors: Emilio Corigliano, Niccolò Betto
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <arch/common/drivers/stm32_bsram.h>
+#include <miosix.h>
+
+#include <iostream>
+
+int PRESERVE preservedVariable = 42;
+
+std::string to_string(miosix::ResetReason reason)
+{
+    switch (reason)
+    {
+        case miosix::ResetReason::UNKNOWN:
+            return "UNKNOWN";
+        case miosix::ResetReason::LOW_POWER:
+            return "LOW_POWER";
+        case miosix::ResetReason::WINDOW_WATCHDOG:
+            return "WINDOW_WATCHDOG";
+        case miosix::ResetReason::INDEPENDENT_WATCHDOG:
+            return "INDEPENDENT_WATCHDOG";
+        case miosix::ResetReason::SOFTWARE:
+            return "SOFTWARE";
+        case miosix::ResetReason::POWER_ON:
+            return "POWER_ON";
+        case miosix::ResetReason::PIN:
+            return "PIN";
+        default:
+            return "ResetReason not valid";
+    }
+}
+
+void printInfo()
+{
+    std::cout << "preservedVariable: " << preservedVariable << "\n";
+    std::cout << "resetReason: " << to_string(miosix::lastResetReason())
+              << "\n";
+    std::cout.flush();
+}
+
+int main()
+{
+    while (true)
+    {
+        printInfo();
+
+        int option;
+        std::cout << "Select option"
+                  << " (1 = set preserved variable; 2 = software reset): ";
+        std::cin >> option;
+
+        switch (option)
+        {
+            case 1:
+                int userInput;
+                std::cout << "Input the new value of the preserved variable"
+                          << std::endl;
+                std::cin >> userInput;
+                {
+                    // Enabling BSRAM write only in this scope
+                    miosix::BSRAM::EnableWriteLock l;
+                    preservedVariable = userInput;
+                }
+
+                // Set variable out of the allowed scope to check it isn't
+                // written
+                // cppcheck-suppress redundantAssignment
+                preservedVariable = 1337;
+                break;
+
+            case 2:
+                miosix::reboot();
+                break;
+
+            default:
+                std::cout << "Invalid option: " << option << std::endl;
+                break;
+        }
+    }
+
+    return 0;
+}