From f7ca1857b4cec097d54fe0bc90ca833094dd1f45 Mon Sep 17 00:00:00 2001
From: Davide Basso <davide.basso@skywarder.eu>
Date: Sat, 14 Sep 2024 09:27:00 +0200
Subject: [PATCH 1/4] [CubeSat] BPS support

---
 cmake/boards.cmake                            |   1 +
 .../config/board_options.cmake                | 123 ++++++
 .../config/board_settings.h                   |  74 ++++
 .../config/miosix_settings.h                  | 240 ++++++++++
 .../core/stage_1_boot.cpp                     | 372 ++++++++++++++++
 .../interfaces-impl/arch_registers_impl.h     |  34 ++
 .../interfaces-impl/bsp.cpp                   | 418 ++++++++++++++++++
 .../interfaces-impl/bsp_impl.h                |  76 ++++
 .../interfaces-impl/hwmapping.h               | 109 +++++
 .../stm32_2m+256k_rom.ld                      | 181 ++++++++
 .../stm32_2m+8m_xram.ld                       | 178 ++++++++
 .../sensors/analog/pressure/nxp/MPXH6250A.h   |  56 +++
 .../analog/pressure/nxp/MPXH6250AData.h       |  40 ++
 13 files changed, 1902 insertions(+)
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/config/board_options.cmake
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/config/board_settings.h
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/arch_registers_impl.h
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp.cpp
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp_impl.h
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/hwmapping.h
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+256k_rom.ld
 create mode 100644 src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+8m_xram.ld
 create mode 100644 src/shared/sensors/analog/pressure/nxp/MPXH6250A.h
 create mode 100644 src/shared/sensors/analog/pressure/nxp/MPXH6250AData.h

diff --git a/cmake/boards.cmake b/cmake/boards.cmake
index ae1be8a92..cab852390 100644
--- a/cmake/boards.cmake
+++ b/cmake/boards.cmake
@@ -41,4 +41,5 @@ set(BOARDCORE_BOARDS_OPTIONS_FILES
     ${BOARDCORE_PATH}/src/bsps/stm32f767zi_lyra_biscotto/config/board_options.cmake
     ${BOARDCORE_PATH}/src/bsps/stm32f767zi_lyra_motor/config/board_options.cmake
     ${BOARDCORE_PATH}/src/bsps/stm32f767zi_lyra_gs/config/board_options.cmake
+    ${BOARDCORE_PATH}/src/bsps/stm32f429zi_lyra_cubesat/config/board_options.cmake
 )
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/config/board_options.cmake b/src/bsps/stm32f429zi_lyra_cubesat/config/board_options.cmake
new file mode 100644
index 000000000..17daacb87
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/config/board_options.cmake
@@ -0,0 +1,123 @@
+# Copyright (C) 2024 by Skyward
+#
+# This program is free software; you can redistribute it and/or 
+# it under the terms of the GNU General Public License as published 
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# As a special exception, if other files instantiate templates or use
+# macros or inline functions from this file, or you compile this file
+# and link it with other works to produce a work based on this file,
+# this file does not by itself cause the resulting work to be covered
+# by the GNU General Public License. However the source code for this
+# file must still be made available in accordance with the GNU 
+# Public License. This exception does not invalidate any other 
+# why a work based on this file might be covered by the GNU General
+# Public License.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>
+
+set(BOARD_NAME stm32f429zi_lyra_cubesat)
+set(ARCH_NAME cortexM4_stm32f4)
+
+# Base directories with header files for this board
+set(ARCH_PATH ${KPATH}/arch/${ARCH_NAME}/common)
+set(BOARD_PATH ${BOARDCORE_PATH}/src/bsps/${BOARD_NAME})
+set(BOARD_CONFIG_PATH ${BOARDCORE_PATH}/src/bsps/${BOARD_NAME}/config)
+
+# Specify where to find the board specific config/miosix_settings.h
+set(BOARD_MIOSIX_SETTINGS_PATH ${BOARD_PATH})
+
+# Specify where to find the board specific config/mxgui_settings.h
+set(BOARD_MXGUI_SETTINGS_PATH ${BOARD_PATH})
+
+# Optimization flags:
+# -O0 do no optimization, the default if no optimization level is specified
+# -O or -O1 optimize minimally
+# -O2 optimize more
+# -O3 optimize even more
+# -Ofast optimize very aggressively to the point of breaking the standard
+# -Og Optimize debugging experience, enables optimizations that do not
+# interfere with debugging
+# -Os Optimize for size with -O2 optimizations that do not increase code size
+set(OPT_OPTIMIZATION
+    $<$<CONFIG:Debug>:-O2>
+    $<$<CONFIG:Release>:-O2>
+)
+
+# Boot and linker files
+set(BOOT_FILE ${BOARD_PATH}/core/stage_1_boot.cpp)
+
+# Linker script type, there are three options
+# 1) Code in FLASH, stack + heap in internal RAM (file *_rom.ld)
+#    the most common choice, available for all microcontrollers
+# 2) Code in FLASH, stack + heap in external RAM (file *8m_xram.ld)
+#    You must uncomment -D__ENABLE_XRAM below in this case.
+# set(LINKER_SCRIPT ${BOARD_PATH}/stm32_2m+256k_rom.ld)
+set(LINKER_SCRIPT ${BOARD_PATH}/stm32_2m+8m_xram.ld)
+
+# Uncommenting __ENABLE_XRAM enables the initialization of the external
+# 8MB SDRAM memory. Do not uncomment this even if you don't use a linker
+# script that requires it, as it is used for the LCD framebuffer.
+set(XRAM -D__ENABLE_XRAM)
+
+# Select clock frequency. Warning: the default clock frequency for
+# this board is 168MHz and not 180MHz because, due to a limitation in
+# the PLL, it is not possible to generate a precise 48MHz output when
+# running the core at 180MHz. If 180MHz is chosen the USB peripheral will
+# NOT WORK and the SDIO and RNG will run ~6% slower (45MHz insteand of 48)
+# Define USE_INTERNAL_CLOCK to bypass the external oscillator
+#set(CLOCK_FREQ -DHSE_VALUE=25000000 -DSYSCLK_FREQ_180MHz=180000000)
+set(CLOCK_FREQ -DHSE_VALUE=25000000 -DSYSCLK_FREQ_168MHz=168000000)
+#set(CLOCK_FREQ -DHSE_VALUE=25000000 -DSYSCLK_FREQ_100MHz=100000000)
+
+# C++ Exception/rtti support disable flags.
+# To save code size if not using C++ exceptions (nor some STL code which
+# implicitly uses it) uncomment this option.
+# -D__NO_EXCEPTIONS is used by Miosix to know if exceptions are used.
+# set(OPT_EXCEPT -fno-exceptions -fno-rtti -D__NO_EXCEPTIONS)
+
+# Specify a custom flash command
+# This is the program that is invoked when the flash flag (-f or --flash) is
+# used with the Miosix Build System. Use $binary or $hex as placeolders, they
+# will be replaced by the build systems with the binary or hex file repectively.
+# If a command is not specified, the build system will use st-flash if found
+# set(PROGRAM_CMDLINE "here your custom flash command")
+
+# Basic flags
+set(FLAGS_BASE -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16)
+
+# Flags for ASM and linker
+set(AFLAGS_BASE ${FLAGS_BASE})
+set(LFLAGS_BASE ${FLAGS_BASE} -Wl,--gc-sections,-Map,main.map -Wl,-T${LINKER_SCRIPT} ${OPT_EXCEPT} ${OPT_OPTIMIZATION} -nostdlib)
+
+# Flags for C/C++
+string(TOUPPER ${BOARD_NAME} BOARD_UPPER)
+set(CFLAGS_BASE
+    -D_BOARD_${BOARD_UPPER} -D_MIOSIX_BOARDNAME=\"${BOARD_NAME}\"
+    -D_DEFAULT_SOURCE=1 -ffunction-sections -Wall -Werror=return-type -g
+    -D_ARCH_CORTEXM4_STM32F4
+    ${CLOCK_FREQ} ${XRAM} ${SRAM_BOOT} ${FLAGS_BASE} ${OPT_OPTIMIZATION} -c
+)
+set(CXXFLAGS_BASE ${CFLAGS_BASE} ${OPT_EXCEPT})
+
+# Select architecture specific files
+set(ARCH_SRC
+    ${ARCH_PATH}/interfaces-impl/delays.cpp
+    ${ARCH_PATH}/interfaces-impl/gpio_impl.cpp
+    ${ARCH_PATH}/interfaces-impl/portability.cpp
+    ${BOARD_PATH}/interfaces-impl/bsp.cpp
+    ${KPATH}/arch/common/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c
+    ${KPATH}/arch/common/core/interrupts_cortexMx.cpp
+    ${KPATH}/arch/common/core/mpu_cortexMx.cpp
+    ${KPATH}/arch/common/core/stm32f2_f4_l4_f7_h7_os_timer.cpp
+    ${KPATH}/arch/common/drivers/sd_stm32f2_f4_f7.cpp
+    ${KPATH}/arch/common/drivers/serial_stm32.cpp
+    ${KPATH}/arch/common/drivers/stm32_hardware_rng.cpp
+)
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/config/board_settings.h b/src/bsps/stm32f429zi_lyra_cubesat/config/board_settings.h
new file mode 100644
index 000000000..6cee46f02
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/config/board_settings.h
@@ -0,0 +1,74 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+#ifndef BOARD_SETTINGS_H
+#define BOARD_SETTINGS_H
+
+#include "util/version.h"
+
+/**
+ * \internal
+ * Versioning for board_settings.h for out of git tree projects
+ */
+#define BOARD_SETTINGS_VERSION 300
+
+namespace miosix
+{
+
+/**
+ * \addtogroup Settings
+ * \{
+ */
+
+/// Size of stack for main().
+/// The C standard library is stack-heavy (iprintf requires 1KB) but the
+/// STM32F407VG only has 192KB of RAM so there is room for a big 4K stack.
+const unsigned int MAIN_STACK_SIZE = 16 * 1024;
+
+/// Serial port
+const unsigned int defaultSerial      = 1;
+const unsigned int defaultSerialSpeed = 115200;
+const bool defaultSerialFlowctrl      = false;
+#define SERIAL_1_DMA
+// #define SERIAL_2_DMA //Serial 2 can't be used (GPIO conflict), so no DMA
+// #define SERIAL_3_DMA //Serial 3 can't be used (GPIO conflict), so no DMA
+
+// #define I2C_WITH_DMA
+
+// SD card driver
+static const unsigned char sdVoltage = 33;  // Board powered @ 3.3V
+#ifdef __ENABLE_XRAM
+// Reduce SD clock to ~4.8MHz
+#define OVERRIDE_SD_CLOCK_DIVIDER_MAX 8
+#endif                      //__ENABLE_XRAM
+#define SD_ONE_BIT_DATABUS  // This board supports 4 bit databus to SD card
+
+/// Analog supply voltage for ADC, DAC, Reset blocks, RCs and PLL
+#define V_DDA_VOLTAGE 3.3f
+
+/**
+ * \}
+ */
+
+}  // namespace miosix
+
+#endif /* BOARD_SETTINGS_H */
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h b/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h
new file mode 100644
index 000000000..66b92921e
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h
@@ -0,0 +1,240 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+#pragma once
+
+// Before you can compile the kernel you have to configure it by editing this
+// file. After that, comment out this line to disable the reminder error.
+// The PARSING_FROM_IDE is because Netbeans gets confused by this, it is never
+// defined when compiling the code.
+#ifndef PARSING_FROM_IDE
+//#error This error is a reminder that you have not edited miosix_settings.h
+// yet.
+#endif  // PARSING_FROM_IDE
+
+/**
+ * \file miosix_settings.h
+ * NOTE: this file contains ONLY configuration options that are not dependent
+ * on architecture specific details. The other options are in the following
+ * files which are included here:
+ * miosix/arch/architecture name/common/arch_settings.h
+ * miosix/config/arch/architecture name/board name/board_settings.h
+ */
+#include "arch_settings.h"
+#include "board_settings.h"
+#include "util/version.h"
+
+/**
+ * \internal
+ * Versioning for miosix_settings.h for out of git tree projects
+ */
+#define MIOSIX_SETTINGS_VERSION 300
+
+namespace miosix
+{
+
+/**
+ * \addtogroup Settings
+ * \{
+ */
+
+//
+// Scheduler options
+//
+
+/// \def SCHED_TYPE_PRIORITY
+/// If uncommented selects the priority scheduler
+/// \def SCHED_TYPE_CONTROL_BASED
+/// If uncommented selects the control based scheduler
+/// \def SCHED_TYPE_EDF
+/// If uncommented selects the EDF scheduler
+// Uncomment only *one* of those
+
+#define SCHED_TYPE_PRIORITY
+//#define SCHED_TYPE_CONTROL_BASED
+//#define SCHED_TYPE_EDF
+
+/// \def WITH_CPU_TIME_COUNTER
+/// Allows to enable/disable CPUTimeCounter to save code size and remove its
+/// overhead from the scheduling process. By default it is not defined
+/// (CPUTimeCounter is disabled).
+//#define WITH_CPU_TIME_COUNTER
+
+//
+// Filesystem options
+//
+
+/// \def WITH_FILESYSTEM
+/// Allows to enable/disable filesystem support to save code size
+/// By default it is defined (filesystem support is enabled)
+#define WITH_FILESYSTEM
+
+/// \def WITH_DEVFS
+/// Allows to enable/disable DevFs support to save code size
+/// By default it is defined (DevFs is enabled)
+#define WITH_DEVFS
+
+/// \def SYNC_AFTER_WRITE
+/// Increases filesystem write robustness. After each write operation the
+/// filesystem is synced so that a power failure happens data is not lost
+/// (unless power failure happens exactly between the write and the sync)
+/// Unfortunately write latency and throughput becomes twice as worse
+/// By default it is defined (slow but safe)
+#define SYNC_AFTER_WRITE
+
+/// Maximum number of open files. Trying to open more will fail.
+/// Cannot be lower than 3, as the first three are stdin, stdout, stderr
+const unsigned char MAX_OPEN_FILES = 8;
+
+/// \def WITH_PROCESSES
+/// If uncommented enables support for processes as well as threads.
+/// This enables the dynamic loader to load elf programs, the extended system
+/// call service and, if the hardware supports it, the MPU to provide memory
+/// isolation of processes
+//#define WITH_PROCESSES
+
+#if defined(WITH_PROCESSES) && defined(__NO_EXCEPTIONS)
+#error Processes require C++ exception support
+#endif  // defined(WITH_PROCESSES) && defined(__NO_EXCEPTIONS)
+
+#if defined(WITH_PROCESSES) && !defined(WITH_FILESYSTEM)
+#error Processes require filesystem support
+#endif  // defined(WITH_PROCESSES) && !defined(WITH_FILESYSTEM)
+
+#if defined(WITH_PROCESSES) && !defined(WITH_DEVFS)
+#error Processes require devfs support
+#endif  // defined(WITH_PROCESSES) && !defined(WITH_DEVFS)
+
+//
+// C/C++ standard library I/O (stdin, stdout and stderr related)
+//
+
+/// \def WITH_BOOTLOG
+/// Uncomment to print bootlogs on stdout.
+/// By default it is defined (bootlogs are printed)
+#define WITH_BOOTLOG
+
+/// \def WITH_ERRLOG
+/// Uncomment for debug information on stdout.
+/// By default it is defined (error information is printed)
+#define WITH_ERRLOG
+
+//
+// Kernel related options (stack sizes, priorities)
+//
+
+/// \def WITH_DEEP_SLEEP
+/// Adds interfaces and required variables to support deep sleep state switch
+/// automatically when peripherals are not required
+//#define WITH_DEEP_SLEEP
+
+/**
+ * \def JTAG_DISABLE_SLEEP
+ * JTAG debuggers lose communication with the device if it enters sleep
+ * mode, so to use debugging it is necessary to disable sleep in the idle
+ * thread. By default it is not defined (idle thread calls sleep).
+ */
+#define JTAG_DISABLE_SLEEP
+
+#if defined(WITH_DEEP_SLEEP) && defined(JTAG_DISABLE_SLEEP)
+#error Deep sleep cannot work together with jtag
+#endif  // defined(WITH_PROCESSES) && !defined(WITH_DEVFS)
+
+/// Minimum stack size (MUST be divisible by 4)
+const unsigned int STACK_MIN = 256;
+
+/// \internal Size of idle thread stack.
+/// Should be >=STACK_MIN (MUST be divisible by 4)
+const unsigned int STACK_IDLE = 256;
+
+/// Default stack size for pthread_create.
+/// The chosen value is enough to call C standard library functions
+/// such as printf/fopen which are stack-heavy
+const unsigned int STACK_DEFAULT_FOR_PTHREAD = 2048;
+
+/// Maximum size of the RAM image of a process. If a program requires more
+/// the kernel will not run it (MUST be divisible by 4)
+const unsigned int MAX_PROCESS_IMAGE_SIZE = 64 * 1024;
+
+/// Minimum size of the stack for a process. If a program specifies a lower
+/// size the kernel will not run it (MUST be divisible by 4)
+const unsigned int MIN_PROCESS_STACK_SIZE = STACK_MIN;
+
+/// Every userspace thread has two stacks, one for when it is running in
+/// userspace and one for when it is running in kernelspace (that is, while it
+/// is executing system calls). This is the size of the stack for when the
+/// thread is running in kernelspace (MUST be divisible by 4)
+const unsigned int SYSTEM_MODE_PROCESS_STACK_SIZE = 2 * 1024;
+
+/// Number of priorities (MUST be >1)
+/// PRIORITY_MAX-1 is the highest priority, 0 is the lowest. -1 is reserved as
+/// the priority of the idle thread.
+/// The meaning of a thread's priority depends on the chosen scheduler.
+#ifdef SCHED_TYPE_PRIORITY
+// Can be modified, but a high value makes context switches more expensive
+const short int PRIORITY_MAX = 4;
+#elif defined(SCHED_TYPE_CONTROL_BASED)
+// Don't touch, the limit is due to the fixed point implementation
+// It's not needed for if floating point is selected, but kept for consistency
+const short int PRIORITY_MAX = 64;
+#else  // SCHED_TYPE_EDF
+// Doesn't exist for this kind of scheduler
+#endif
+
+/// Priority of main()
+/// The meaning of a thread's priority depends on the chosen scheduler.
+const unsigned char MAIN_PRIORITY = 1;
+
+#ifdef SCHED_TYPE_PRIORITY
+/// Maximum thread time slice in nanoseconds, after which preemption occurs
+const unsigned int MAX_TIME_SLICE = 1000000;
+#endif  // SCHED_TYPE_PRIORITY
+
+//
+// Other low level kernel options. There is usually no need to modify these.
+//
+
+/// \internal Length of wartermark (in bytes) to check stack overflow.
+/// MUST be divisible by 4 and can also be zero.
+/// A high value increases context switch time.
+const unsigned int WATERMARK_LEN = 16;
+
+/// \internal Used to fill watermark
+const unsigned int WATERMARK_FILL = 0xaaaaaaaa;
+
+/// \internal Used to fill stack (for checking stack usage)
+const unsigned int STACK_FILL = 0xbbbbbbbb;
+
+// Compiler version checks
+#if !defined(_MIOSIX_GCC_PATCH_MAJOR) || _MIOSIX_GCC_PATCH_MAJOR < 3
+#error \
+    "You are using a too old or unsupported compiler. Get the latest one from https://miosix.org/wiki/index.php?title=Miosix_Toolchain"
+#endif
+#if _MIOSIX_GCC_PATCH_MAJOR > 3
+#warning "You are using a too new compiler, which may not be supported"
+#endif
+
+/**
+ * \}
+ */
+
+}  // namespace miosix
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp b/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp
new file mode 100644
index 000000000..b189eb8bf
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp
@@ -0,0 +1,372 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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 <string.h>
+
+#include "core/interrupts.h"  //For the unexpected interrupt call
+#include "interfaces/arch_registers.h"
+#include "interfaces/bsp.h"
+#include "kernel/stage_2_boot.h"
+
+/*
+ * startup.cpp
+ * STM32 C++ startup.
+ * NOTE: for stm32f42x devices ONLY.
+ * Supports interrupt handlers in C++ without extern "C"
+ * Developed by Terraneo Federico, based on ST startup code.
+ * Additionally modified to boot Miosix.
+ */
+
+/**
+ * Called by Reset_Handler, performs initialization and calls main.
+ * Never returns.
+ */
+void program_startup() __attribute__((noreturn));
+void program_startup()
+{
+    // Cortex M3 core appears to get out of reset with interrupts already
+    // enabled
+    __disable_irq();
+
+    // These are defined in the linker script
+    extern unsigned char _etext asm("_etext");
+    extern unsigned char _data asm("_data");
+    extern unsigned char _edata asm("_edata");
+    extern unsigned char _bss_start asm("_bss_start");
+    extern unsigned char _bss_end asm("_bss_end");
+
+    // Initialize .data section, clear .bss section
+    unsigned char *etext     = &_etext;
+    unsigned char *data      = &_data;
+    unsigned char *edata     = &_edata;
+    unsigned char *bss_start = &_bss_start;
+    unsigned char *bss_end   = &_bss_end;
+    memcpy(data, etext, edata - data);
+    memset(bss_start, 0, bss_end - bss_start);
+
+    // Move on to stage 2
+    _init();
+
+    // If main returns, reboot
+    NVIC_SystemReset();
+    for (;;)
+        ;
+}
+
+/**
+ * Reset handler, called by hardware immediately after reset
+ */
+void Reset_Handler() __attribute__((__interrupt__, noreturn));
+void Reset_Handler()
+{
+    // SystemInit() is called *before* initializing .data and zeroing .bss
+    // Despite all startup files provided by ST do the opposite, there are three
+    // good reasons to do so:
+    // First, the CMSIS specifications say that SystemInit() must not access
+    // global variables, so it is actually possible to call it before
+    // Second, when running Miosix with the xram linker scripts .data and .bss
+    // are placed in the external RAM, so we *must* call SystemInit(), which
+    // enables xram, before touching .data and .bss
+    // Third, this is a performance improvement since the loops that initialize
+    //.data and zeros .bss now run with the CPU at full speed instead of 8MHz
+    SystemInit();
+// ST does not provide code to initialize the stm32f429-disco SDRAM at boot.
+// Put after SystemInit() as SDRAM is timing-sensitive and needs the full
+// clock speed.
+#ifdef __ENABLE_XRAM
+    miosix::configureSdram();
+#endif  //__ENABLE_XRAM
+
+    /*
+     * Initialize process stack and switch to it.
+     * This is required for booting Miosix, a small portion of the top of the
+     * heap area will be used as stack until the first thread starts. After,
+     * this stack will be abandoned and the process stack will point to the
+     * current thread's stack.
+     */
+    asm volatile(
+        "ldr r0,  =_heap_end          \n\t"
+        "msr psp, r0                  \n\t"
+        "movw r0, #2                  \n\n"  // Privileged, process stack
+        "msr control, r0              \n\t"
+        "isb                          \n\t" ::
+            : "r0");
+
+    program_startup();
+}
+
+/**
+ * All unused interrupts call this function.
+ */
+extern "C" void Default_Handler() { unexpectedInterrupt(); }
+
+// System handlers
+void /*__attribute__((weak))*/ Reset_Handler();      // These interrupts are not
+void /*__attribute__((weak))*/ NMI_Handler();        // weak because they are
+void /*__attribute__((weak))*/ HardFault_Handler();  // surely defined by Miosix
+void /*__attribute__((weak))*/ MemManage_Handler();
+void /*__attribute__((weak))*/ BusFault_Handler();
+void /*__attribute__((weak))*/ UsageFault_Handler();
+void /*__attribute__((weak))*/ SVC_Handler();
+void /*__attribute__((weak))*/ DebugMon_Handler();
+void /*__attribute__((weak))*/ PendSV_Handler();
+void __attribute__((weak)) SysTick_Handler();
+
+// Interrupt handlers
+void __attribute__((weak)) WWDG_IRQHandler();
+void __attribute__((weak)) PVD_IRQHandler();
+void __attribute__((weak)) TAMP_STAMP_IRQHandler();
+void __attribute__((weak)) RTC_WKUP_IRQHandler();
+void __attribute__((weak)) FLASH_IRQHandler();
+void __attribute__((weak)) RCC_IRQHandler();
+void __attribute__((weak)) EXTI0_IRQHandler();
+void __attribute__((weak)) EXTI1_IRQHandler();
+void __attribute__((weak)) EXTI2_IRQHandler();
+void __attribute__((weak)) EXTI3_IRQHandler();
+void __attribute__((weak)) EXTI4_IRQHandler();
+void __attribute__((weak)) DMA1_Stream0_IRQHandler();
+void __attribute__((weak)) DMA1_Stream1_IRQHandler();
+void __attribute__((weak)) DMA1_Stream2_IRQHandler();
+void __attribute__((weak)) DMA1_Stream3_IRQHandler();
+void __attribute__((weak)) DMA1_Stream4_IRQHandler();
+void __attribute__((weak)) DMA1_Stream5_IRQHandler();
+void __attribute__((weak)) DMA1_Stream6_IRQHandler();
+void __attribute__((weak)) ADC_IRQHandler();
+void __attribute__((weak)) CAN1_TX_IRQHandler();
+void __attribute__((weak)) CAN1_RX0_IRQHandler();
+void __attribute__((weak)) CAN1_RX1_IRQHandler();
+void __attribute__((weak)) CAN1_SCE_IRQHandler();
+void __attribute__((weak)) EXTI9_5_IRQHandler();
+void __attribute__((weak)) TIM1_BRK_TIM9_IRQHandler();
+void __attribute__((weak)) TIM1_UP_TIM10_IRQHandler();
+void __attribute__((weak)) TIM1_TRG_COM_TIM11_IRQHandler();
+void __attribute__((weak)) TIM1_CC_IRQHandler();
+void __attribute__((weak)) TIM2_IRQHandler();
+void __attribute__((weak)) TIM3_IRQHandler();
+void __attribute__((weak)) TIM4_IRQHandler();
+void __attribute__((weak)) I2C1_EV_IRQHandler();
+void __attribute__((weak)) I2C1_ER_IRQHandler();
+void __attribute__((weak)) I2C2_EV_IRQHandler();
+void __attribute__((weak)) I2C2_ER_IRQHandler();
+void __attribute__((weak)) SPI1_IRQHandler();
+void __attribute__((weak)) SPI2_IRQHandler();
+void __attribute__((weak)) USART1_IRQHandler();
+void __attribute__((weak)) USART2_IRQHandler();
+void __attribute__((weak)) USART3_IRQHandler();
+void __attribute__((weak)) EXTI15_10_IRQHandler();
+void __attribute__((weak)) RTC_Alarm_IRQHandler();
+void __attribute__((weak)) OTG_FS_WKUP_IRQHandler();
+void __attribute__((weak)) TIM8_BRK_TIM12_IRQHandler();
+void __attribute__((weak)) TIM8_UP_TIM13_IRQHandler();
+void __attribute__((weak)) TIM8_TRG_COM_TIM14_IRQHandler();
+void __attribute__((weak)) TIM8_CC_IRQHandler();
+void __attribute__((weak)) DMA1_Stream7_IRQHandler();
+void __attribute__((weak)) FMC_IRQHandler();
+void __attribute__((weak)) SDIO_IRQHandler();
+void __attribute__((weak)) TIM5_IRQHandler();
+void __attribute__((weak)) SPI3_IRQHandler();
+void __attribute__((weak)) UART4_IRQHandler();
+void __attribute__((weak)) UART5_IRQHandler();
+void __attribute__((weak)) TIM6_DAC_IRQHandler();
+void __attribute__((weak)) TIM7_IRQHandler();
+void __attribute__((weak)) DMA2_Stream0_IRQHandler();
+void __attribute__((weak)) DMA2_Stream1_IRQHandler();
+void __attribute__((weak)) DMA2_Stream2_IRQHandler();
+void __attribute__((weak)) DMA2_Stream3_IRQHandler();
+void __attribute__((weak)) DMA2_Stream4_IRQHandler();
+void __attribute__((weak)) ETH_IRQHandler();
+void __attribute__((weak)) ETH_WKUP_IRQHandler();
+void __attribute__((weak)) CAN2_TX_IRQHandler();
+void __attribute__((weak)) CAN2_RX0_IRQHandler();
+void __attribute__((weak)) CAN2_RX1_IRQHandler();
+void __attribute__((weak)) CAN2_SCE_IRQHandler();
+void __attribute__((weak)) OTG_FS_IRQHandler();
+void __attribute__((weak)) DMA2_Stream5_IRQHandler();
+void __attribute__((weak)) DMA2_Stream6_IRQHandler();
+void __attribute__((weak)) DMA2_Stream7_IRQHandler();
+void __attribute__((weak)) USART6_IRQHandler();
+void __attribute__((weak)) I2C3_EV_IRQHandler();
+void __attribute__((weak)) I2C3_ER_IRQHandler();
+void __attribute__((weak)) OTG_HS_EP1_OUT_IRQHandler();
+void __attribute__((weak)) OTG_HS_EP1_IN_IRQHandler();
+void __attribute__((weak)) OTG_HS_WKUP_IRQHandler();
+void __attribute__((weak)) OTG_HS_IRQHandler();
+void __attribute__((weak)) DCMI_IRQHandler();
+void __attribute__((weak)) CRYP_IRQHandler();
+void __attribute__((weak)) HASH_RNG_IRQHandler();
+void __attribute__((weak)) FPU_IRQHandler();
+void __attribute__((weak)) UART7_IRQHandler();
+void __attribute__((weak)) UART8_IRQHandler();
+void __attribute__((weak)) SPI4_IRQHandler();
+void __attribute__((weak)) SPI5_IRQHandler();
+void __attribute__((weak)) SPI6_IRQHandler();
+void __attribute__((weak)) SAI1_IRQHandler();
+void __attribute__((weak)) LTDC_IRQHandler();
+void __attribute__((weak)) LTDC_ER_IRQHandler();
+void __attribute__((weak)) DMA2D_IRQHandler();
+
+// Stack top, defined in the linker script
+extern char _main_stack_top asm("_main_stack_top");
+
+// Interrupt vectors, must be placed @ address 0x00000000
+// The extern declaration is required otherwise g++ optimizes it out
+extern void (*const __Vectors[])();
+void (*const __Vectors[])() __attribute__((section(".isr_vector"))) = {
+    reinterpret_cast<void (*)()>(&_main_stack_top), /* Stack pointer*/
+    Reset_Handler,                                  /* Reset Handler */
+    NMI_Handler,                                    /* NMI Handler */
+    HardFault_Handler,                              /* Hard Fault Handler */
+    MemManage_Handler,                              /* MPU Fault Handler */
+    BusFault_Handler,                               /* Bus Fault Handler */
+    UsageFault_Handler,                             /* Usage Fault Handler */
+    0,                                              /* Reserved */
+    0,                                              /* Reserved */
+    0,                                              /* Reserved */
+    0,                                              /* Reserved */
+    SVC_Handler,                                    /* SVCall Handler */
+    DebugMon_Handler,                               /* Debug Monitor Handler */
+    0,                                              /* Reserved */
+    PendSV_Handler,                                 /* PendSV Handler */
+    SysTick_Handler,                                /* SysTick Handler */
+
+    /* External Interrupts */
+    WWDG_IRQHandler, PVD_IRQHandler, TAMP_STAMP_IRQHandler, RTC_WKUP_IRQHandler,
+    FLASH_IRQHandler, RCC_IRQHandler, EXTI0_IRQHandler, EXTI1_IRQHandler,
+    EXTI2_IRQHandler, EXTI3_IRQHandler, EXTI4_IRQHandler,
+    DMA1_Stream0_IRQHandler, DMA1_Stream1_IRQHandler, DMA1_Stream2_IRQHandler,
+    DMA1_Stream3_IRQHandler, DMA1_Stream4_IRQHandler, DMA1_Stream5_IRQHandler,
+    DMA1_Stream6_IRQHandler, ADC_IRQHandler, CAN1_TX_IRQHandler,
+    CAN1_RX0_IRQHandler, CAN1_RX1_IRQHandler, CAN1_SCE_IRQHandler,
+    EXTI9_5_IRQHandler, TIM1_BRK_TIM9_IRQHandler, TIM1_UP_TIM10_IRQHandler,
+    TIM1_TRG_COM_TIM11_IRQHandler, TIM1_CC_IRQHandler, TIM2_IRQHandler,
+    TIM3_IRQHandler, TIM4_IRQHandler, I2C1_EV_IRQHandler, I2C1_ER_IRQHandler,
+    I2C2_EV_IRQHandler, I2C2_ER_IRQHandler, SPI1_IRQHandler, SPI2_IRQHandler,
+    USART1_IRQHandler, USART2_IRQHandler, USART3_IRQHandler,
+    EXTI15_10_IRQHandler, RTC_Alarm_IRQHandler, OTG_FS_WKUP_IRQHandler,
+    TIM8_BRK_TIM12_IRQHandler, TIM8_UP_TIM13_IRQHandler,
+    TIM8_TRG_COM_TIM14_IRQHandler, TIM8_CC_IRQHandler, DMA1_Stream7_IRQHandler,
+    FMC_IRQHandler, SDIO_IRQHandler, TIM5_IRQHandler, SPI3_IRQHandler,
+    UART4_IRQHandler, UART5_IRQHandler, TIM6_DAC_IRQHandler, TIM7_IRQHandler,
+    DMA2_Stream0_IRQHandler, DMA2_Stream1_IRQHandler, DMA2_Stream2_IRQHandler,
+    DMA2_Stream3_IRQHandler, DMA2_Stream4_IRQHandler, ETH_IRQHandler,
+    ETH_WKUP_IRQHandler, CAN2_TX_IRQHandler, CAN2_RX0_IRQHandler,
+    CAN2_RX1_IRQHandler, CAN2_SCE_IRQHandler, OTG_FS_IRQHandler,
+    DMA2_Stream5_IRQHandler, DMA2_Stream6_IRQHandler, DMA2_Stream7_IRQHandler,
+    USART6_IRQHandler, I2C3_EV_IRQHandler, I2C3_ER_IRQHandler,
+    OTG_HS_EP1_OUT_IRQHandler, OTG_HS_EP1_IN_IRQHandler, OTG_HS_WKUP_IRQHandler,
+    OTG_HS_IRQHandler, DCMI_IRQHandler, CRYP_IRQHandler, HASH_RNG_IRQHandler,
+    FPU_IRQHandler, UART7_IRQHandler, UART8_IRQHandler, SPI4_IRQHandler,
+    SPI5_IRQHandler, SPI6_IRQHandler, SAI1_IRQHandler, LTDC_IRQHandler,
+    LTDC_ER_IRQHandler, DMA2D_IRQHandler};
+
+#pragma weak SysTick_IRQHandler            = Default_Handler
+#pragma weak WWDG_IRQHandler               = Default_Handler
+#pragma weak PVD_IRQHandler                = Default_Handler
+#pragma weak TAMP_STAMP_IRQHandler         = Default_Handler
+#pragma weak RTC_WKUP_IRQHandler           = Default_Handler
+#pragma weak FLASH_IRQHandler              = Default_Handler
+#pragma weak RCC_IRQHandler                = Default_Handler
+#pragma weak EXTI0_IRQHandler              = Default_Handler
+#pragma weak EXTI1_IRQHandler              = Default_Handler
+#pragma weak EXTI2_IRQHandler              = Default_Handler
+#pragma weak EXTI3_IRQHandler              = Default_Handler
+#pragma weak EXTI4_IRQHandler              = Default_Handler
+#pragma weak DMA1_Stream0_IRQHandler       = Default_Handler
+#pragma weak DMA1_Stream1_IRQHandler       = Default_Handler
+#pragma weak DMA1_Stream2_IRQHandler       = Default_Handler
+#pragma weak DMA1_Stream3_IRQHandler       = Default_Handler
+#pragma weak DMA1_Stream4_IRQHandler       = Default_Handler
+#pragma weak DMA1_Stream5_IRQHandler       = Default_Handler
+#pragma weak DMA1_Stream6_IRQHandler       = Default_Handler
+#pragma weak ADC_IRQHandler                = Default_Handler
+#pragma weak CAN1_TX_IRQHandler            = Default_Handler
+#pragma weak CAN1_RX0_IRQHandler           = Default_Handler
+#pragma weak CAN1_RX1_IRQHandler           = Default_Handler
+#pragma weak CAN1_SCE_IRQHandler           = Default_Handler
+#pragma weak EXTI9_5_IRQHandler            = Default_Handler
+#pragma weak TIM1_BRK_TIM9_IRQHandler      = Default_Handler
+#pragma weak TIM1_UP_TIM10_IRQHandler      = Default_Handler
+#pragma weak TIM1_TRG_COM_TIM11_IRQHandler = Default_Handler
+#pragma weak TIM1_CC_IRQHandler            = Default_Handler
+#pragma weak TIM2_IRQHandler               = Default_Handler
+#pragma weak TIM3_IRQHandler               = Default_Handler
+#pragma weak TIM4_IRQHandler               = Default_Handler
+#pragma weak I2C1_EV_IRQHandler            = Default_Handler
+#pragma weak I2C1_ER_IRQHandler            = Default_Handler
+#pragma weak I2C2_EV_IRQHandler            = Default_Handler
+#pragma weak I2C2_ER_IRQHandler            = Default_Handler
+#pragma weak SPI1_IRQHandler               = Default_Handler
+#pragma weak SPI2_IRQHandler               = Default_Handler
+// #pragma weak USART1_IRQHandler             = Default_Handler
+// #pragma weak USART2_IRQHandler             = Default_Handler
+// #pragma weak USART3_IRQHandler             = Default_Handler
+#pragma weak EXTI15_10_IRQHandler          = Default_Handler
+#pragma weak RTC_Alarm_IRQHandler          = Default_Handler
+#pragma weak OTG_FS_WKUP_IRQHandler        = Default_Handler
+#pragma weak TIM8_BRK_TIM12_IRQHandler     = Default_Handler
+#pragma weak TIM8_UP_TIM13_IRQHandler      = Default_Handler
+#pragma weak TIM8_TRG_COM_TIM14_IRQHandler = Default_Handler
+#pragma weak TIM8_CC_IRQHandler            = Default_Handler
+#pragma weak DMA1_Stream7_IRQHandler       = Default_Handler
+#pragma weak FMC_IRQHandler                = Default_Handler
+#pragma weak SDIO_IRQHandler               = Default_Handler
+#pragma weak TIM5_IRQHandler               = Default_Handler
+#pragma weak SPI3_IRQHandler               = Default_Handler
+// #pragma weak UART4_IRQHandler              = Default_Handler
+// #pragma weak UART5_IRQHandler              = Default_Handler
+#pragma weak TIM6_DAC_IRQHandler     = Default_Handler
+#pragma weak TIM7_IRQHandler         = Default_Handler
+#pragma weak DMA2_Stream0_IRQHandler = Default_Handler
+#pragma weak DMA2_Stream1_IRQHandler = Default_Handler
+#pragma weak DMA2_Stream2_IRQHandler = Default_Handler
+#pragma weak DMA2_Stream3_IRQHandler = Default_Handler
+#pragma weak DMA2_Stream4_IRQHandler = Default_Handler
+#pragma weak ETH_IRQHandler          = Default_Handler
+#pragma weak ETH_WKUP_IRQHandler     = Default_Handler
+#pragma weak CAN2_TX_IRQHandler      = Default_Handler
+#pragma weak CAN2_RX0_IRQHandler     = Default_Handler
+#pragma weak CAN2_RX1_IRQHandler     = Default_Handler
+#pragma weak CAN2_SCE_IRQHandler     = Default_Handler
+#pragma weak OTG_FS_IRQHandler       = Default_Handler
+#pragma weak DMA2_Stream5_IRQHandler = Default_Handler
+#pragma weak DMA2_Stream6_IRQHandler = Default_Handler
+#pragma weak DMA2_Stream7_IRQHandler = Default_Handler
+// #pragma weak USART6_IRQHandler             = Default_Handler
+#pragma weak I2C3_EV_IRQHandler        = Default_Handler
+#pragma weak I2C3_ER_IRQHandler        = Default_Handler
+#pragma weak OTG_HS_EP1_OUT_IRQHandler = Default_Handler
+#pragma weak OTG_HS_EP1_IN_IRQHandler  = Default_Handler
+#pragma weak OTG_HS_WKUP_IRQHandler    = Default_Handler
+#pragma weak OTG_HS_IRQHandler         = Default_Handler
+#pragma weak DCMI_IRQHandler           = Default_Handler
+#pragma weak CRYP_IRQHandler           = Default_Handler
+#pragma weak HASH_RNG_IRQHandler       = Default_Handler
+#pragma weak FPU_IRQHandler            = Default_Handler
+// #pragma weak UART7_IRQHandler              = Default_Handler
+// #pragma weak UART8_IRQHandler              = Default_Handler
+#pragma weak SPI4_IRQHandler    = Default_Handler
+#pragma weak SPI5_IRQHandler    = Default_Handler
+#pragma weak SPI6_IRQHandler    = Default_Handler
+#pragma weak SAI1_IRQHandler    = Default_Handler
+#pragma weak LTDC_IRQHandler    = Default_Handler
+#pragma weak LTDC_ER_IRQHandler = Default_Handler
+#pragma weak DMA2D_IRQHandler   = Default_Handler
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/arch_registers_impl.h b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/arch_registers_impl.h
new file mode 100644
index 000000000..f3276b6d0
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/arch_registers_impl.h
@@ -0,0 +1,34 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+#ifndef ARCH_REGISTERS_IMPL_H
+#define ARCH_REGISTERS_IMPL_H
+
+// Always include stm32f4xx.h before core_cm4.h, there's some nasty dependency
+#define STM32F429xx
+#include "CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h"
+#include "CMSIS/Device/ST/STM32F4xx/Include/system_stm32f4xx.h"
+#include "CMSIS/Include/core_cm4.h"
+
+#define RCC_SYNC() __DSB()  // Workaround for a bug in stm32f42x
+
+#endif  // ARCH_REGISTERS_IMPL_H
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp.cpp b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp.cpp
new file mode 100644
index 000000000..e4447baca
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp.cpp
@@ -0,0 +1,418 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+/***********************************************************************
+ * bsp.cpp Part of the Miosix Embedded OS.
+ * Board support package, this file initializes hardware.
+ ************************************************************************/
+
+#include <inttypes.h>
+#include <sys/ioctl.h>
+
+#include <cstdlib>
+
+#include "board_settings.h"
+#include "config/miosix_settings.h"
+#include "drivers/sd_stm32f2_f4_f7.h"
+#include "drivers/serial.h"
+#include "drivers/serial_stm32.h"
+#include "drivers/stm32_sgm.h"
+#include "filesystem/console/console_device.h"
+#include "filesystem/file_access.h"
+#include "hwmapping.h"
+#include "interfaces/arch_registers.h"
+#include "interfaces/delays.h"
+#include "interfaces/portability.h"
+#include "kernel/kernel.h"
+#include "kernel/logging.h"
+#include "kernel/sync.h"
+
+namespace miosix
+{
+
+//
+// Initialization
+//
+
+/**
+ * The example code from ST checks for the busy flag after each command.
+ * Interestingly I couldn't find any mention of this in the datsheet.
+ */
+static void sdramCommandWait()
+{
+    for (int i = 0; i < 0xffff; i++)
+        if ((FMC_Bank5_6->SDSR & FMC_SDSR_BUSY) == 0)
+            return;
+}
+
+#ifdef SDRAM_ISSI
+
+void configureSdram()
+{
+    // Enable all gpios, passing clock
+    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN |
+                    RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN |
+                    RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN |
+                    RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN;
+    RCC_SYNC();
+
+    // First, configure SDRAM GPIOs
+    GPIOB->AFR[0] = 0x0cc00000;
+    GPIOC->AFR[0] = 0x0000000c;
+    GPIOD->AFR[0] = 0x000000cc;
+    GPIOD->AFR[1] = 0xcc000ccc;
+    GPIOE->AFR[0] = 0xc00000cc;
+    GPIOE->AFR[1] = 0xcccccccc;
+    GPIOF->AFR[0] = 0x00cccccc;
+    GPIOF->AFR[1] = 0xccccc000;
+    GPIOG->AFR[0] = 0x00cc00cc;
+    GPIOG->AFR[1] = 0xc000000c;
+
+    GPIOB->MODER = 0x00002800;
+    GPIOC->MODER = 0x00000002;
+    GPIOD->MODER = 0xa02a000a;
+    GPIOE->MODER = 0xaaaa800a;
+    GPIOF->MODER = 0xaa800aaa;
+    GPIOG->MODER = 0x80020a0a;
+
+    GPIOA->OSPEEDR = 0xaaaaaaaa;  // Default to 50MHz speed for all GPIOs...
+    GPIOB->OSPEEDR =
+        0xaaaaaaaa | 0x00003c00;  //...but 100MHz for the SDRAM pins
+    GPIOC->OSPEEDR = 0xaaaaaaaa | 0x00000003;
+    GPIOD->OSPEEDR = 0xaaaaaaaa | 0xf03f000f;
+    GPIOE->OSPEEDR = 0xaaaaaaaa | 0xffffc00f;
+    GPIOF->OSPEEDR = 0xaaaaaaaa | 0xffc00fff;
+    GPIOG->OSPEEDR = 0xaaaaaaaa | 0xc0030f0f;
+    GPIOH->OSPEEDR = 0xaaaaaaaa;
+
+    // Since we'we un-configured PB3/PB4 from the default at boot TDO,NTRST,
+    // finish the job and remove the default pull-up
+    GPIOB->PUPDR = 0;
+
+    // Second, actually start the SDRAM controller
+    RCC->AHB3ENR |= RCC_AHB3ENR_FMCEN;
+    RCC_SYNC();
+
+    // SDRAM is a IS42S16400J -7 speed grade, connected to bank 2 (0xd0000000)
+    // Some bits in SDCR[1] are don't care, and the have to be set in SDCR[0],
+    // they aren't just don't care, the controller will fail if they aren't at 0
+    FMC_Bank5_6->SDCR[0] = FMC_SDCR1_SDCLK_1  // SDRAM runs @ half CPU frequency
+                           | FMC_SDCR1_RBURST  // Enable read burst
+                           | 0;              //  0 delay between reads after CAS
+    FMC_Bank5_6->SDCR[1] = 0                 //  8 bit column address
+                           | FMC_SDCR1_NR_0  // 12 bit row address
+                           | FMC_SDCR1_MWID_0  // 16 bit data bus
+                           | FMC_SDCR1_NB      //  4 banks
+                           |
+                           FMC_SDCR1_CAS_1;  //  2 cycle CAS latency (F<133MHz)
+
+#ifdef SYSCLK_FREQ_180MHz
+    // One SDRAM clock cycle is 11.1ns
+    // Some bits in SDTR[1] are don't care, and the have to be set in SDTR[0],
+    // they aren't just don't care, the controller will fail if they aren't at 0
+    FMC_Bank5_6->SDTR[0] = (6 - 1) << 12     // 6 cycle TRC  (66.6ns>63ns)
+                           | (2 - 1) << 20;  // 2 cycle TRP  (22.2ns>15ns)
+    FMC_Bank5_6->SDTR[1] = (2 - 1) << 0      // 2 cycle TMRD
+                           | (7 - 1) << 4    // 7 cycle TXSR (77.7ns>70ns)
+                           | (4 - 1) << 8    // 4 cycle TRAS (44.4ns>42ns)
+                           | (2 - 1) << 16   // 2 cycle TWR
+                           | (2 - 1) << 24;  // 2 cycle TRCD (22.2ns>15ns)
+#elif defined(SYSCLK_FREQ_168MHz)
+    // One SDRAM clock cycle is 11.9ns
+    // Some bits in SDTR[1] are don't care, and the have to be set in SDTR[0],
+    // they aren't just don't care, the controller will fail if they aren't at 0
+    FMC_Bank5_6->SDTR[0] = (6 - 1) << 12     // 6 cycle TRC  (71.4ns>63ns)
+                           | (2 - 1) << 20;  // 2 cycle TRP  (23.8ns>15ns)
+    FMC_Bank5_6->SDTR[1] = (2 - 1) << 0      // 2 cycle TMRD
+                           | (6 - 1) << 4    // 6 cycle TXSR (71.4ns>70ns)
+                           | (4 - 1) << 8    // 4 cycle TRAS (47.6ns>42ns)
+                           | (2 - 1) << 16   // 2 cycle TWR
+                           | (2 - 1) << 24;  // 2 cycle TRCD (23.8ns>15ns)
+#else
+#error No SDRAM timings for this clock
+#endif
+
+    FMC_Bank5_6->SDCMR = FMC_SDCMR_CTB2  // Enable bank 2
+                         | 1;            // MODE=001 clock enabled
+    sdramCommandWait();
+
+    // ST and SDRAM datasheet agree a 100us delay is required here.
+    delayUs(100);
+
+    FMC_Bank5_6->SDCMR = FMC_SDCMR_CTB2  // Enable bank 2
+                         | 2;            // MODE=010 precharge all command
+    sdramCommandWait();
+
+    FMC_Bank5_6->SDCMR = (8 - 1) << 5      // NRFS=8 SDRAM datasheet says
+                                           // "at least two AUTO REFRESH cycles"
+                         | FMC_SDCMR_CTB2  // Enable bank 2
+                         | 3;              // MODE=011 auto refresh
+    sdramCommandWait();
+
+    FMC_Bank5_6->SDCMR = 0x220 << 9  // MRD=0x220:CAS latency=2 burst len=1
+                         | FMC_SDCMR_CTB2  // Enable bank 2
+                         | 4;              // MODE=100 load mode register
+    sdramCommandWait();
+
+// 64ms/4096=15.625us
+#ifdef SYSCLK_FREQ_180MHz
+    // 15.625us*90MHz=1406-20=1386
+    FMC_Bank5_6->SDRTR = 1386 << 1;
+#elif defined(SYSCLK_FREQ_168MHz)
+    // 15.625us*84MHz=1312-20=1292
+    FMC_Bank5_6->SDRTR = 1292 << 1;
+#else
+#error No refresh timings for this clock
+#endif
+}
+
+#else
+
+void configureSdram()
+{
+    // Enable all gpios
+    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN |
+                    RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN |
+                    RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN |
+                    RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN;
+    RCC_SYNC();
+
+    // First, configure SDRAM GPIOs
+    GPIOB->AFR[0] = 0x0cc00000;
+    GPIOC->AFR[0] = 0x0000000c;
+    GPIOD->AFR[0] = 0x000000cc;
+    GPIOD->AFR[1] = 0xcc000ccc;
+    GPIOE->AFR[0] = 0xc00000cc;
+    GPIOE->AFR[1] = 0xcccccccc;
+    GPIOF->AFR[0] = 0x00cccccc;
+    GPIOF->AFR[1] = 0xccccc000;
+    GPIOG->AFR[0] = 0x00cc00cc;
+    GPIOG->AFR[1] = 0xc000000c;
+
+    GPIOB->MODER = 0x00002800;
+    GPIOC->MODER = 0x00000002;
+    GPIOD->MODER = 0xa02a000a;
+    GPIOE->MODER = 0xaaaa800a;
+    GPIOF->MODER = 0xaa800aaa;
+    GPIOG->MODER = 0x80020a0a;
+
+    GPIOA->OSPEEDR = 0xaaaaaaaa;  // Default to 50MHz speed for all GPIOs...
+    GPIOB->OSPEEDR =
+        0xaaaaaaaa | 0x00003c00;  //...but 100MHz for the SDRAM pins
+    GPIOC->OSPEEDR = 0xaaaaaaaa | 0x00000003;
+    GPIOD->OSPEEDR = 0xaaaaaaaa | 0xf03f000f;
+    GPIOE->OSPEEDR = 0xaaaaaaaa | 0xffffc00f;
+    GPIOF->OSPEEDR = 0xaaaaaaaa | 0xffc00fff;
+    GPIOG->OSPEEDR = 0xaaaaaaaa | 0xc0030f0f;
+    GPIOH->OSPEEDR = 0xaaaaaaaa;
+
+    // Since we'we un-configured PB3/PB4 from the default at boot TDO,NTRST,
+    // finish the job and remove the default pull-up
+    GPIOB->PUPDR = 0;
+
+    // Second, actually start the SDRAM controller
+    RCC->AHB3ENR |= RCC_AHB3ENR_FMCEN;
+    RCC_SYNC();
+
+    // SDRAM is a AS4C4M16SA-6TAN, connected to bank 2 (0xd0000000)
+    // Some bits in SDCR[1] are don't care, and the have to be set in SDCR[0],
+    // they aren't just don't care, the controller will fail if they aren't at 0
+    FMC_Bank5_6->SDCR[0] = FMC_SDCR1_SDCLK_1  // SDRAM runs @ half CPU frequency
+                           | FMC_SDCR1_RBURST  // Enable read burst
+                           | 0;  //  0 delay between reads after CAS
+    FMC_Bank5_6->SDCR[1] =
+        0                   //  8 bit column address
+        | FMC_SDCR1_NR_0    // 12 bit row address
+        | FMC_SDCR1_MWID_0  // 16 bit data bus
+        | FMC_SDCR1_NB      //  4 banks
+        | FMC_SDCR1_CAS_1;  //  2 cycle CAS latency (TCK>9+0.5ns [1])
+
+#ifdef SYSCLK_FREQ_180MHz
+    // One SDRAM clock cycle is 11.1ns
+    // Some bits in SDTR[1] are don't care, and the have to be set in SDTR[0],
+    // they aren't just don't care, the controller will fail if they aren't at 0
+    FMC_Bank5_6->SDTR[0] = (6 - 1) << 12     // 6 cycle TRC  (66.6ns>60ns)
+                           | (2 - 1) << 20;  // 2 cycle TRP  (22.2ns>18ns)
+    FMC_Bank5_6->SDTR[1] = (2 - 1) << 0      // 2 cycle TMRD
+                           |
+                           (6 - 1) << 4  // 6 cycle TXSR (66.6ns>61.5+0.5ns [1])
+                           | (4 - 1) << 8    // 4 cycle TRAS (44.4ns>42ns)
+                           | (2 - 1) << 16   // 2 cycle TWR
+                           | (2 - 1) << 24;  // 2 cycle TRCD (22.2ns>18ns)
+#elif defined(SYSCLK_FREQ_168MHz)
+    // One SDRAM clock cycle is 11.9ns
+    // Some bits in SDTR[1] are don't care, and the have to be set in SDTR[0],
+    // they aren't just don't care, the controller will fail if they aren't at 0
+    FMC_Bank5_6->SDTR[0] = (6 - 1) << 12     // 6 cycle TRC  (71.4ns>60ns)
+                           | (2 - 1) << 20;  // 2 cycle TRP  (23.8ns>18ns)
+    FMC_Bank5_6->SDTR[1] = (2 - 1) << 0      // 2 cycle TMRD
+                           |
+                           (6 - 1) << 4  // 6 cycle TXSR (71.4ns>61.5+0.5ns [1])
+                           | (4 - 1) << 8    // 4 cycle TRAS (47.6ns>42ns)
+                           | (2 - 1) << 16   // 2 cycle TWR
+                           | (2 - 1) << 24;  // 2 cycle TRCD (23.8ns>18ns)
+#else
+#error No SDRAM timings for this clock
+#endif
+    // NOTE [1]: the timings for TCK and TIS depend on rise and fall times
+    //(see note 9 and 10 on datasheet). Timings are adjusted accordingly to
+    // the measured 2ns rise and fall time
+
+    FMC_Bank5_6->SDCMR = FMC_SDCMR_CTB2  // Enable bank 2
+                         | 1;            // MODE=001 clock enabled
+    sdramCommandWait();
+
+    // SDRAM datasheet requires 200us delay here (note 11), here we use 10% more
+    delayUs(220);
+
+    FMC_Bank5_6->SDCMR = FMC_SDCMR_CTB2  // Enable bank 2
+                         | 2;            // MODE=010 precharge all command
+    sdramCommandWait();
+
+    // FIXME: note 11 on SDRAM datasheet says extended mode register must be
+    // set, but the ST datasheet does not seem to explain how
+    FMC_Bank5_6->SDCMR = 0x220 << 9  // MRD=0x220:CAS latency=2 burst len=1
+                         | FMC_SDCMR_CTB2  // Enable bank 2
+                         | 4;              // MODE=100 load mode register
+    sdramCommandWait();
+
+    FMC_Bank5_6->SDCMR = (4 - 1) << 5  // NRFS=8 SDRAM datasheet requires
+                                       // a minimum of 2 cycles, here we use 4
+                         | FMC_SDCMR_CTB2  // Enable bank 2
+                         | 3;              // MODE=011 auto refresh
+    sdramCommandWait();
+
+// 32ms/4096=7.8125us, but datasheet says to round that to 7.8us
+#ifdef SYSCLK_FREQ_180MHz
+    // 7.8us*90MHz=702-20=682
+    FMC_Bank5_6->SDRTR = 682 << 1;
+#elif defined(SYSCLK_FREQ_168MHz)
+    // 7.8us*84MHz=655-20=635
+    FMC_Bank5_6->SDRTR = 635 << 1;
+#else
+#error No refresh timings for this clock
+#endif
+}
+
+#endif
+
+void IRQbspInit()
+{
+// If using SDRAM GPIOs are enabled by configureSdram(), else enable them here
+#ifndef __ENABLE_XRAM
+    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN |
+                    RCC_AHB1ENR_GPIOCEN | RCC_AHB1ENR_GPIODEN |
+                    RCC_AHB1ENR_GPIOEEN | RCC_AHB1ENR_GPIOFEN |
+                    RCC_AHB1ENR_GPIOGEN | RCC_AHB1ENR_GPIOHEN;
+    RCC_SYNC();
+#endif  //__ENABLE_XRAM
+
+    // enable spi1, spi2
+    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
+    RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
+
+    // enable can1
+    RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
+
+    RCC_SYNC();
+
+    using namespace interfaces;
+
+    spi1::sck::mode(Mode::ALTERNATE);
+    spi1::sck::alternateFunction(5);
+    spi1::miso::mode(Mode::ALTERNATE);
+    spi1::miso::alternateFunction(5);
+    spi1::mosi::mode(Mode::ALTERNATE);
+    spi1::mosi::alternateFunction(5);
+
+    spi4::sck::mode(Mode::ALTERNATE);
+    spi4::sck::alternateFunction(5);
+    spi4::miso::mode(Mode::ALTERNATE);
+    spi4::miso::alternateFunction(5);
+    spi4::mosi::mode(Mode::ALTERNATE);
+    spi4::mosi::alternateFunction(5);
+
+    uart2::rx::mode(Mode::ALTERNATE);
+    uart2::rx::alternateFunction(7);
+    uart2::tx::mode(Mode::ALTERNATE);
+    uart2::tx::alternateFunction(7);
+
+    uart4::rx::mode(Mode::ALTERNATE);
+    uart4::rx::alternateFunction(8);
+    uart4::tx::mode(Mode::ALTERNATE);
+    uart4::tx::alternateFunction(8);
+
+    using namespace sensors;
+
+    ads131m04::cs::mode(Mode::OUTPUT);
+    ads131m04::cs::high();
+
+    ubxgps::cs::mode(Mode::OUTPUT);
+    ubxgps::cs::high();
+
+    LSM6DSRX::cs::mode(Mode::OUTPUT);
+    LSM6DSRX::cs::high();
+
+    DefaultConsole::instance().IRQset(intrusive_ref_ptr<Device>(
+        new STM32Serial(defaultSerial, defaultSerialSpeed,
+                        defaultSerialFlowctrl ? STM32Serial::RTSCTS
+                                              : STM32Serial::NOFLOWCTRL)));
+
+    using namespace leds;
+
+    led_red1::mode(Mode::OUTPUT);
+    led_ext::mode(Mode::OUTPUT);
+    led_green::mode(Mode::OUTPUT);
+}
+
+void bspInit2()
+{
+#ifdef WITH_FILESYSTEM
+    // PA2,PA3
+    intrusive_ref_ptr<DevFs> devFs =
+        basicFilesystemSetup(SDIODriver::instance());
+#endif  // WITH_FILESYSTEM
+}
+
+//
+// Shutdown and reboot
+//
+
+void reboot()
+{
+    ioctl(STDOUT_FILENO, IOCTL_SYNC, 0);
+
+#ifdef WITH_FILESYSTEM
+    FilesystemManager::instance().umountAll();
+#endif  // WITH_FILESYSTEM
+
+    disableInterrupts();
+    miosix_private::IRQsystemReboot();
+}
+
+/**
+ * For safety reasons, we never want the board to shutdown.
+ * When requested to shutdown, we reboot instead.
+ */
+void shutdown() { reboot(); }
+
+}  // namespace miosix
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp_impl.h b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp_impl.h
new file mode 100644
index 000000000..6bea1f4d5
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/bsp_impl.h
@@ -0,0 +1,76 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+/***********************************************************************
+ * bsp_impl.h Part of the Miosix Embedded OS.
+ * Board support package, this file initializes hardware.
+ ************************************************************************/
+
+#ifndef BSP_IMPL_H
+#define BSP_IMPL_H
+
+#include "config/miosix_settings.h"
+#include "drivers/stm32_hardware_rng.h"
+#include "hwmapping.h"
+#include "interfaces/gpio.h"
+
+namespace miosix
+{
+
+/**
+\addtogroup Hardware
+\{
+*/
+
+/**
+ * \internal
+ * Called by stage_1_boot.cpp to enable the SDRAM before initializing .data/.bss
+ * Requires the CPU clock to be already configured (running from the PLL)
+ */
+void configureSdram();
+
+/**
+ * \internal
+ * used by the ledOn() and ledOff() implementation
+ */
+
+inline void ledOn()
+{
+    leds::led_red1::high();
+    leds::led_green::high();
+    leds::led_ext::high();
+}
+
+inline void ledOff()
+{
+    leds::led_red1::low();
+    leds::led_green::low();
+    leds::led_ext::low();
+}
+
+/**
+\}
+*/
+
+}  // namespace miosix
+
+#endif  // BSP_IMPL_H
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/hwmapping.h b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/hwmapping.h
new file mode 100644
index 000000000..a96880095
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/interfaces-impl/hwmapping.h
@@ -0,0 +1,109 @@
+/* Copyright (c) 2022 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+#ifndef HWMAPPING_H
+#define HWMAPPING_H
+#endif
+
+#include "interfaces/gpio.h"
+
+namespace miosix
+{
+
+namespace interfaces
+{
+
+// spi LSM6DSRX
+namespace spi1
+{
+using sck  = Gpio<GPIOA_BASE, 5>;
+using miso = Gpio<GPIOA_BASE, 6>;
+using mosi = Gpio<GPIOA_BASE, 7>;
+}  // namespace spi1
+
+// spi gps,adc
+namespace spi4
+{
+using sck  = Gpio<GPIOE_BASE, 2>;
+using miso = Gpio<GPIOE_BASE, 5>;
+using mosi = Gpio<GPIOE_BASE, 6>;
+}  // namespace spi4
+
+// USB UART
+namespace uart1
+{
+using tx = Gpio<GPIOA_BASE, 9>;
+using rx = Gpio<GPIOA_BASE, 10>;
+}  // namespace uart1
+
+// HIL UART
+namespace uart2
+{
+using tx = Gpio<GPIOA_BASE, 2>;
+using rx = Gpio<GPIOA_BASE, 3>;
+}  // namespace uart2
+
+// SIM900 UART
+namespace uart4
+{
+using tx = Gpio<GPIOA_BASE, 0>;
+using rx = Gpio<GPIOA_BASE, 1>;
+}  // namespace uart4
+
+}  // namespace interfaces
+
+namespace sensors
+{
+
+namespace LSM6DSRX
+{
+using cs = Gpio<GPIOC_BASE, 4>;
+
+}  // namespace LSM6DSRX
+
+namespace ads131m04
+{
+using cs = Gpio<GPIOE_BASE, 4>;
+}  // namespace ads131m04
+
+namespace ubxgps
+{
+using cs = Gpio<GPIOE_BASE, 3>;
+}  // namespace ubxgps
+
+}  // namespace sensors
+
+namespace leds
+{
+using led_red1  = Gpio<GPIOB_BASE, 0>;
+using led_green = Gpio<GPIOB_BASE, 1>;
+using led_ext   = Gpio<GPIOB_BASE, 10>;
+
+/**
+ * These are connected to the enable pin of the thermal cutters and the cs of
+ * the lis3mdl magnetometer.
+ */
+// using led_blue2  = Gpio<GPIOG_BASE, 2>;
+// using led_green1 = Gpio<GPIOG_BASE, 6>;
+// using led_green2 = Gpio<GPIOD_BASE, 11>;
+}  // namespace leds
+}  // namespace miosix
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+256k_rom.ld b/src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+256k_rom.ld
new file mode 100644
index 000000000..cfcc2ce53
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+256k_rom.ld
@@ -0,0 +1,181 @@
+/*
+ * C++ enabled linker script for stm32 (2M FLASH, 256K RAM)
+ * Developed by TFT: Terraneo Federico Technologies
+ * Optimized for use with the Miosix kernel
+ */
+
+/*
+ * This chip has an unusual quirk that the RAM is divided in two block mapped
+ * at two non contiguous memory addresses. I don't know why they've done that,
+ * probably doing the obvious thing would have made writing code too easy...
+ * Anyway, since hardware can't be changed, we've got to live with that and
+ * try to make use of both RAMs.
+ * 
+ * Given the constraints above, this linker script puts:
+ * - read only data and code (.text, .rodata, .eh_*) in FLASH
+ * - the 512Byte main (IRQ) stack, .data and .bss in the "small" 64KB RAM
+ * - stacks and heap in the "large" 192KB RAM.
+ * 
+ * Unfortunately thread stacks can't be put in the small RAM as Miosix
+ * allocates them inside the heap.
+ */
+
+/*
+ * The main stack is used for interrupt handling by the kernel.
+ *
+ * *** Readme ***
+ * This linker script places the main stack (used by the kernel for interrupts)
+ * at the bottom of the ram, instead of the top. This is done for two reasons:
+ *
+ * - as an optimization for microcontrollers with little ram memory. In fact
+ *   the implementation of malloc from newlib requests memory to the OS in 4KB
+ *   block (except the first block that can be smaller). This is probably done
+ *   for compatibility with OSes with an MMU and paged memory. To see why this
+ *   is bad, consider a microcontroller with 8KB of ram: when malloc finishes
+ *   up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will
+ *   fail because the top part of the ram is used by the main stack. As a
+ *   result, the top part of the memory will not be used by malloc, even if
+ *   available (and it is nearly *half* the ram on an 8KB mcu). By placing the
+ *   main stack at the bottom of the ram, the upper 4KB block will be entirely
+ *   free and available as heap space.
+ *
+ * - In case of main stack overflow the cpu will fault because access to memory
+ *   before the beginning of the ram faults. Instead with the default stack
+ *   placement the main stack will silently collide with the heap.
+ * Note: if increasing the main stack size also increase the ORIGIN value in
+ * the MEMORY definitions below accordingly.
+ */
+_main_stack_size = 0x00000200;                     /* main stack = 512Bytes */
+_main_stack_top  = 0x10000000 + _main_stack_size;
+ASSERT(_main_stack_size   % 8 == 0, "MAIN stack size error");
+
+/* Mapping the heap into the large 192KB RAM */
+_end =      0x20000000;
+_heap_end = 0x20030000;                            /* end of available ram  */
+
+/* identify the Entry Point  */
+ENTRY(_Z13Reset_Handlerv)
+
+/* specify the memory areas  */
+MEMORY
+{
+    flash(rx)    : ORIGIN = 0x08000000, LENGTH =   2M
+    /*
+     * Note, the small ram starts at 0x10000000 but it is necessary to add the
+     * size of the main stack, so it is 0x10000200.
+     */
+    smallram(wx) : ORIGIN = 0x10000200, LENGTH =  64K-0x200 
+    largeram(wx) : ORIGIN = 0x20000000, LENGTH = 192K
+    backupram(rw): ORIGIN = 0x40024000, LENGTH =  4K
+}
+
+/* now define the output sections  */
+SECTIONS
+{
+    . = 0;
+    
+    /* .text section: code goes to flash */
+    .text :
+    {
+        /* Startup code must go at address 0 */
+        KEEP(*(.isr_vector))
+        
+        *(.text)
+        *(.text.*)
+        *(.gnu.linkonce.t.*)
+        /* these sections for thumb interwork? */
+        *(.glue_7)
+        *(.glue_7t)
+        /* these sections for C++? */
+        *(.gcc_except_table)
+        *(.gcc_except_table.*)
+        *(.ARM.extab*)
+        *(.gnu.linkonce.armextab.*)
+
+        . = ALIGN(4);
+        /* .rodata: constant data */
+        *(.rodata)
+        *(.rodata.*)
+        *(.gnu.linkonce.r.*)
+
+        /* C++ Static constructors/destructors (eabi) */
+        . = ALIGN(4);
+        KEEP(*(.init))
+        
+        . = ALIGN(4);
+        __miosix_init_array_start = .;
+        KEEP (*(SORT(.miosix_init_array.*)))
+        KEEP (*(.miosix_init_array))
+        __miosix_init_array_end = .;
+
+        . = ALIGN(4);
+        __preinit_array_start = .;
+        KEEP (*(.preinit_array))
+        __preinit_array_end = .;
+
+        . = ALIGN(4);
+        __init_array_start = .;
+        KEEP (*(SORT(.init_array.*)))
+        KEEP (*(.init_array))
+        __init_array_end = .;
+
+        . = ALIGN(4);
+        KEEP(*(.fini))
+
+        . = ALIGN(4);
+        __fini_array_start = .;
+        KEEP (*(.fini_array))
+        KEEP (*(SORT(.fini_array.*)))
+        __fini_array_end = .;
+
+        /* C++ Static constructors/destructors (elf)  */
+        . = ALIGN(4);
+        _ctor_start = .;
+        KEEP (*crtbegin.o(.ctors))
+        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+        KEEP (*(SORT(.ctors.*)))
+        KEEP (*crtend.o(.ctors))
+       _ctor_end = .;
+
+        . = ALIGN(4);
+        KEEP (*crtbegin.o(.dtors))
+        KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+        KEEP (*(SORT(.dtors.*)))
+        KEEP (*crtend.o(.dtors))
+    } > flash
+
+    /* .ARM.exidx is sorted, so has to go in its own output section.  */
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > flash
+    __exidx_end = .;
+
+	/* .data section: global variables go to ram, but also store a copy to
+       flash to initialize them */
+    .data : ALIGN(8)
+    {
+        _data = .;
+        *(.data)
+        *(.data.*)
+        *(.gnu.linkonce.d.*)
+        . = ALIGN(8);
+        _edata = .;
+    } > smallram AT > flash
+    _etext = LOADADDR(.data);
+
+    /* .bss section: uninitialized global variables go to ram */
+    _bss_start = .;
+    .bss :
+    {
+        *(.bss)
+        *(.bss.*)
+        *(.gnu.linkonce.b.*)
+        . = ALIGN(8);
+    } > smallram
+    _bss_end = .;
+
+    /*_end = .;*/
+    /*PROVIDE(end = .);*/
+}
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+8m_xram.ld b/src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+8m_xram.ld
new file mode 100644
index 000000000..b6a0d2668
--- /dev/null
+++ b/src/bsps/stm32f429zi_lyra_cubesat/stm32_2m+8m_xram.ld
@@ -0,0 +1,178 @@
+/*
+ * C++ enabled linker script for stm32 (2M FLASH, 256K RAM, 8M XRAM)
+ * Developed by TFT: Terraneo Federico Technologies
+ * Optimized for use with the Miosix kernel
+ */
+
+/*
+ * This chip has an unusual quirk that the RAM is divided in two block mapped
+ * at two non contiguous memory addresses. I don't know why they've done that,
+ * probably doing the obvious thing would have made writing code too easy...
+ * Anyway, since hardware can't be changed, we've got to live with that and
+ * try to make use of both RAMs.
+ * 
+ * Given the constraints above, this linker script puts:
+ * - read only data and code (.text, .rodata, .eh_*) in FLASH
+ * - the 512Byte main (IRQ) stack, .data and .bss in the "small" 64KB RAM
+ * - .data, .bss, stacks and heap in the external 8MB SDRAM.
+ */
+
+/*
+ * The main stack is used for interrupt handling by the kernel.
+ *
+ * *** Readme ***
+ * This linker script places the main stack (used by the kernel for interrupts)
+ * at the bottom of the ram, instead of the top. This is done for two reasons:
+ *
+ * - as an optimization for microcontrollers with little ram memory. In fact
+ *   the implementation of malloc from newlib requests memory to the OS in 4KB
+ *   block (except the first block that can be smaller). This is probably done
+ *   for compatibility with OSes with an MMU and paged memory. To see why this
+ *   is bad, consider a microcontroller with 8KB of ram: when malloc finishes
+ *   up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will
+ *   fail because the top part of the ram is used by the main stack. As a
+ *   result, the top part of the memory will not be used by malloc, even if
+ *   available (and it is nearly *half* the ram on an 8KB mcu). By placing the
+ *   main stack at the bottom of the ram, the upper 4KB block will be entirely
+ *   free and available as heap space.
+ *
+ * - In case of main stack overflow the cpu will fault because access to memory
+ *   before the beginning of the ram faults. Instead with the default stack
+ *   placement the main stack will silently collide with the heap.
+ * Note: if increasing the main stack size also increase the ORIGIN value in
+ * the MEMORY definitions below accordingly.
+ */
+_main_stack_size = 0x00000200;                     /* main stack = 512Bytes */
+_main_stack_top  = 0x10000000 + _main_stack_size;
+ASSERT(_main_stack_size   % 8 == 0, "MAIN stack size error");
+
+/* Mapping the heap into XRAM */
+_heap_end = 0xd0800000;                            /* end of available ram  */
+
+/* identify the Entry Point  */
+ENTRY(_Z13Reset_Handlerv)
+
+/* specify the memory areas  */
+MEMORY
+{
+    flash(rx)    : ORIGIN = 0x08000000, LENGTH =   2M
+    /*
+     * Note, the small ram starts at 0x10000000 but it is necessary to add the
+     * size of the main stack, so it is 0x10000200.
+     */
+    smallram(wx) : ORIGIN = 0x10000200, LENGTH =  64K-0x200 
+    largeram(wx) : ORIGIN = 0x20000000, LENGTH = 192K
+    backupram(rw): ORIGIN = 0x40024000, LENGTH =   4K
+    xram(wx)     : ORIGIN = 0xd0000000, LENGTH =   8M
+}
+
+/* now define the output sections  */
+SECTIONS
+{
+    . = 0;
+    
+    /* .text section: code goes to flash */
+    .text :
+    {
+        /* Startup code must go at address 0 */
+        KEEP(*(.isr_vector))
+        
+        *(.text)
+        *(.text.*)
+        *(.gnu.linkonce.t.*)
+        /* these sections for thumb interwork? */
+        *(.glue_7)
+        *(.glue_7t)
+        /* these sections for C++? */
+        *(.gcc_except_table)
+        *(.gcc_except_table.*)
+        *(.ARM.extab*)
+        *(.gnu.linkonce.armextab.*)
+
+        . = ALIGN(4);
+        /* .rodata: constant data */
+        *(.rodata)
+        *(.rodata.*)
+        *(.gnu.linkonce.r.*)
+
+        /* C++ Static constructors/destructors (eabi) */
+        . = ALIGN(4);
+        KEEP(*(.init))
+        
+        . = ALIGN(4);
+        __miosix_init_array_start = .;
+        KEEP (*(SORT(.miosix_init_array.*)))
+        KEEP (*(.miosix_init_array))
+        __miosix_init_array_end = .;
+
+        . = ALIGN(4);
+        __preinit_array_start = .;
+        KEEP (*(.preinit_array))
+        __preinit_array_end = .;
+
+        . = ALIGN(4);
+        __init_array_start = .;
+        KEEP (*(SORT(.init_array.*)))
+        KEEP (*(.init_array))
+        __init_array_end = .;
+
+        . = ALIGN(4);
+        KEEP(*(.fini))
+
+        . = ALIGN(4);
+        __fini_array_start = .;
+        KEEP (*(.fini_array))
+        KEEP (*(SORT(.fini_array.*)))
+        __fini_array_end = .;
+
+        /* C++ Static constructors/destructors (elf)  */
+        . = ALIGN(4);
+        _ctor_start = .;
+        KEEP (*crtbegin.o(.ctors))
+        KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+        KEEP (*(SORT(.ctors.*)))
+        KEEP (*crtend.o(.ctors))
+       _ctor_end = .;
+
+        . = ALIGN(4);
+        KEEP (*crtbegin.o(.dtors))
+        KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+        KEEP (*(SORT(.dtors.*)))
+        KEEP (*crtend.o(.dtors))
+    } > flash
+
+    /* .ARM.exidx is sorted, so has to go in its own output section.  */
+    __exidx_start = .;
+    .ARM.exidx :
+    {
+        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    } > flash
+    __exidx_end = .;
+
+	/* .data section: global variables go to ram, but also store a copy to
+       flash to initialize them */
+    .data : ALIGN(8)
+    {
+        _data = .;
+        *(.data)
+        *(.data.*)
+        *(.gnu.linkonce.d.*)
+        . = ALIGN(8);
+        _edata = .;
+    } > xram AT > flash
+    _etext = LOADADDR(.data);
+
+    /* .bss section: uninitialized global variables go to ram */
+    _bss_start = .;
+    .bss :
+    {
+        *(.bss)
+        *(.bss.*)
+        *(.gnu.linkonce.b.*)
+        . = ALIGN(8);
+    } > xram
+    _bss_end = .;
+
+    _end = .;
+    PROVIDE(end = .);
+}
diff --git a/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h b/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h
new file mode 100644
index 000000000..5e2c66022
--- /dev/null
+++ b/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <sensors/analog/pressure/AnalogPressureSensor.h>
+#include <utils/Stats/Stats.h>
+
+#include "MPXH6250AData.h"
+
+namespace Boardcore
+{
+
+/**
+ * @brief Driver for NXP's MPXHZ6130A pressure sensor
+ */
+class MPXH6250A final : public AnalogPressureSensor<MPXH6250AData>
+{
+public:
+    MPXH6250A(std::function<ADCData()> getVoltage,
+              const float supplyVoltage = 5.0)
+        : AnalogPressureSensor(getVoltage, supplyVoltage, 250000, 20000)
+    {
+    }
+
+private:
+    float voltageToPressure(float voltage) override
+    {
+        return (((voltage / supplyVoltage) + CONST_B) / CONST_A) * 1000.0;
+    }
+
+    // Constants from datasheet
+    static constexpr float CONST_A = 0.0040;
+    static constexpr float CONST_B = 0.040;
+};
+
+}  // namespace Boardcore
diff --git a/src/shared/sensors/analog/pressure/nxp/MPXH6250AData.h b/src/shared/sensors/analog/pressure/nxp/MPXH6250AData.h
new file mode 100644
index 000000000..a35e28010
--- /dev/null
+++ b/src/shared/sensors/analog/pressure/nxp/MPXH6250AData.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Author: Vincenzo Tirolese
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include <sensors/SensorData.h>
+
+namespace Boardcore
+{
+
+struct MPXH6250AData : public PressureData
+{
+    static std::string header() { return "pressureTimestamp,pressure\n"; }
+
+    void print(std::ostream& os) const
+    {
+        os << pressureTimestamp << "," << pressure << "\n";
+    }
+};
+
+}  // namespace Boardcore
-- 
GitLab


From 409f937b2237ae28fd8204f4eb32aab413d19877 Mon Sep 17 00:00:00 2001
From: Davide Basso <davide.basso@skywarder.eu>
Date: Sat, 14 Sep 2024 17:18:45 +0200
Subject: [PATCH 2/4] [BSP] Add lyra_cubesat config to c_cpp_properties

---
 .vscode/c_cpp_properties.json | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
index 89f94061b..a715574af 100644
--- a/.vscode/c_cpp_properties.json
+++ b/.vscode/c_cpp_properties.json
@@ -571,6 +571,29 @@
                 "${workspaceFolder}/libs/miosix-kernel/miosix/arch/cortexM7_stm32f7/stm32f769ni_discovery",
                 "${workspaceFolder}/libs/miosix-kernel/miosix/config/arch/cortexM7_stm32f7/stm32f769ni_discovery"
             ]
+        },
+        {
+            "name": "stm32f429zi_lyra_cubesat",
+            "cStandard": "c11",
+            "cppStandard": "c++14",
+            "compilerPath": "/opt/arm-miosix-eabi/bin/arm-miosix-eabi-g++",
+            "defines": [
+                "${defaultDefines}",
+                "_MIOSIX_BOARDNAME=stm32f429zi_lyra_cubesat",
+                "_BOARD_STM32F429ZI_LYRA_CUBESAT",
+                "_ARCH_CORTEXM4_STM32F4",
+                "STM32F429xx",
+                "HSE_VALUE=8000000",
+                "SYSCLK_FREQ_168MHz=168000000",
+                "__ENABLE_XRAM",
+                "V_DDA_VOLTAGE=3.3f"
+            ],
+            "includePath": [
+                "${defaultIncludePaths}",
+                "${workspaceFolder}/libs/miosix-kernel/miosix/arch/cortexM4_stm32f4/common",
+                "${workspaceFolder}/src/bsps/stm32f429zi_lyra_cubesat/config",
+                "${workspaceFolder}/src/bsps/stm32f429zi_lyra_cubesat"
+            ]
         }
     ],
     "version": 4
-- 
GitLab


From aaf259db663559ef5e1cc2c4d63ea6939f7be06b Mon Sep 17 00:00:00 2001
From: Davide Basso <davide.basso@skywarder.eu>
Date: Mon, 9 Dec 2024 22:44:11 +0100
Subject: [PATCH 3/4] [BSP] Remove final keyword from MPXH6250A

---
 src/shared/sensors/analog/pressure/nxp/MPXH6250A.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h b/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h
index 5e2c66022..a862bfa79 100644
--- a/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h
+++ b/src/shared/sensors/analog/pressure/nxp/MPXH6250A.h
@@ -33,7 +33,7 @@ namespace Boardcore
 /**
  * @brief Driver for NXP's MPXHZ6130A pressure sensor
  */
-class MPXH6250A final : public AnalogPressureSensor<MPXH6250AData>
+class MPXH6250A : public AnalogPressureSensor<MPXH6250AData>
 {
 public:
     MPXH6250A(std::function<ADCData()> getVoltage,
-- 
GitLab


From e3b1a8be4f2bf21a94c4c006747f158374127196 Mon Sep 17 00:00:00 2001
From: Davide Basso <davide.basso@skywarder.eu>
Date: Tue, 17 Dec 2024 19:14:20 +0100
Subject: [PATCH 4/4] [Style] Fix format

---
 .../config/miosix_settings.h                       | 14 +++++++-------
 .../stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp | 10 +++++-----
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h b/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h
index 66b92921e..c1dcb0cd3 100644
--- a/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h
+++ b/src/bsps/stm32f429zi_lyra_cubesat/config/miosix_settings.h
@@ -27,8 +27,8 @@
 // The PARSING_FROM_IDE is because Netbeans gets confused by this, it is never
 // defined when compiling the code.
 #ifndef PARSING_FROM_IDE
-//#error This error is a reminder that you have not edited miosix_settings.h
-// yet.
+// #error This error is a reminder that you have not edited miosix_settings.h
+//  yet.
 #endif  // PARSING_FROM_IDE
 
 /**
@@ -70,14 +70,14 @@ namespace miosix
 // Uncomment only *one* of those
 
 #define SCHED_TYPE_PRIORITY
-//#define SCHED_TYPE_CONTROL_BASED
-//#define SCHED_TYPE_EDF
+// #define SCHED_TYPE_CONTROL_BASED
+// #define SCHED_TYPE_EDF
 
 /// \def WITH_CPU_TIME_COUNTER
 /// Allows to enable/disable CPUTimeCounter to save code size and remove its
 /// overhead from the scheduling process. By default it is not defined
 /// (CPUTimeCounter is disabled).
-//#define WITH_CPU_TIME_COUNTER
+// #define WITH_CPU_TIME_COUNTER
 
 //
 // Filesystem options
@@ -110,7 +110,7 @@ const unsigned char MAX_OPEN_FILES = 8;
 /// This enables the dynamic loader to load elf programs, the extended system
 /// call service and, if the hardware supports it, the MPU to provide memory
 /// isolation of processes
-//#define WITH_PROCESSES
+// #define WITH_PROCESSES
 
 #if defined(WITH_PROCESSES) && defined(__NO_EXCEPTIONS)
 #error Processes require C++ exception support
@@ -145,7 +145,7 @@ const unsigned char MAX_OPEN_FILES = 8;
 /// \def WITH_DEEP_SLEEP
 /// Adds interfaces and required variables to support deep sleep state switch
 /// automatically when peripherals are not required
-//#define WITH_DEEP_SLEEP
+// #define WITH_DEEP_SLEEP
 
 /**
  * \def JTAG_DISABLE_SLEEP
diff --git a/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp b/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp
index b189eb8bf..87ecbf08e 100644
--- a/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp
+++ b/src/bsps/stm32f429zi_lyra_cubesat/core/stage_1_boot.cpp
@@ -55,11 +55,11 @@ void program_startup()
     extern unsigned char _bss_end asm("_bss_end");
 
     // Initialize .data section, clear .bss section
-    unsigned char *etext     = &_etext;
-    unsigned char *data      = &_data;
-    unsigned char *edata     = &_edata;
-    unsigned char *bss_start = &_bss_start;
-    unsigned char *bss_end   = &_bss_end;
+    unsigned char* etext     = &_etext;
+    unsigned char* data      = &_data;
+    unsigned char* edata     = &_edata;
+    unsigned char* bss_start = &_bss_start;
+    unsigned char* bss_end   = &_bss_end;
     memcpy(data, etext, edata - data);
     memset(bss_start, 0, bss_end - bss_start);
 
-- 
GitLab