From e2af8c5ddb515593d8ecf4d3475cf5b9b4ad7be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Sun, 30 Nov 2025 13:57:40 +0100 Subject: [PATCH 01/76] Initial structure --- .vscode/settings.json | 2 +- CMakeLists.txt | 6 +- Inc/HALAL/HALAL.hpp | 3 + Inc/HALAL/Models/GPIO.hpp | 223 ++++++++++++++++++++++++++++++++++++++ Inc/HALAL/Models/Pin.hpp | 7 ++ Inc/ST-LIB.hpp | 88 ++++++++++++++- Inc/stm32h7xx_hal_conf.h | 2 +- 7 files changed, 325 insertions(+), 6 deletions(-) create mode 100644 Inc/HALAL/Models/GPIO.hpp create mode 100644 Inc/HALAL/Models/Pin.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json index d161326bb..b2abce05a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "C_Cpp.default.cppStandard": "c++20", + "C_Cpp.default.cppStandard": "c++23", "C_Cpp.default.cStandard": "c17", "C_Cpp.clang_format_fallbackStyle": "{BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 80}", "C_Cpp.formatting": "clangFormat", diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ba062c27..7d35f2ef8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -263,7 +263,7 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE $<$:-specs=nosys.specs> $<$:-ffunction-sections> $<$:-fdata-sections> - $<$:-fno-exceptions> + # $<$:-fno-exceptions> -Wno-psabi @@ -272,8 +272,8 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE $<$:-Wall> $<$:-Wpedantic> $<$:-Werror> - $<$:-Wno-gnu-zero-variadic-macro-arguments> - $<$:-Wno-inconsistent-missing-override> + # $<$:-Wno-gnu-zero-variadic-macro-arguments> + # $<$:-Wno-inconsistent-missing-override> $<$:-fno-use-cxa-atexit> $<$:-fno-rtti> $<$:-Wno-address-of-packed-member> diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index d1c0438ce..316c9605a 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -1,5 +1,8 @@ #pragma once +#include "HALAL/Models/GPIO.hpp" +#include "HALAL/Models/Pin.hpp" + #include "HALAL/Models/HALconfig/HALconfig.hpp" #include "HALAL/Models/DMA/DMA.hpp" diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp new file mode 100644 index 000000000..e9bfafe5a --- /dev/null +++ b/Inc/HALAL/Models/GPIO.hpp @@ -0,0 +1,223 @@ +#pragma once + +#include "stm32h7xx_hal.h" +#include +#include +#include + +using std::array; +using std::size_t; +using std::span; +using std::tuple; + +namespace ST_LIB { +struct GPIODomain { + enum class OperationMode : uint8_t { + INPUT, + OUTPUT, + ANALOG, + EXTERNAL_INTERRUPT_RISING, + EXTERNAL_INTERRUPT_FALLING, + EXTERNAL_INTERRUPT_RISING_FALLING, + TIMER_ALTERNATE_FUNCTION, + ALTERNATIVE, + }; + enum class Port : uint8_t { A, B, C, D, E, F, G, H }; + static inline GPIO_TypeDef *port_to_reg(Port p) { + switch (p) { + case Port::A: + return GPIOA; + case Port::B: + return GPIOB; + case Port::C: + return GPIOC; + case Port::D: + return GPIOD; + case Port::E: + return GPIOE; + case Port::F: + return GPIOF; + case Port::G: + return GPIOG; + case Port::H: + return GPIOH; + default: + return nullptr; + } + } + static inline void enable_gpio_clock(Port port) { + switch (port) { + case Port::A: + __HAL_RCC_GPIOA_CLK_ENABLE(); + break; + + case Port::B: + __HAL_RCC_GPIOB_CLK_ENABLE(); + break; + + case Port::C: + __HAL_RCC_GPIOC_CLK_ENABLE(); + break; + + case Port::D: + __HAL_RCC_GPIOD_CLK_ENABLE(); + break; + + case Port::E: + __HAL_RCC_GPIOE_CLK_ENABLE(); + break; + + case Port::F: + __HAL_RCC_GPIOF_CLK_ENABLE(); + break; + + case Port::G: + __HAL_RCC_GPIOG_CLK_ENABLE(); + break; + + case Port::H: + __HAL_RCC_GPIOH_CLK_ENABLE(); + break; + } + } + + struct Pin2 { + GPIODomain::Port port; + uint32_t pin; + + consteval Pin2(GPIODomain::Port port, uint32_t pin) + : port(port), pin(pin) {} + }; + + struct Entry { + size_t id; + Port port; + uint32_t pin; + OperationMode mode; + }; + + struct GPIO { + using domain = GPIODomain; + + Entry e; + + consteval GPIO(std::size_t id, Pin2 pin, OperationMode mode) + : e(id, pin.port, pin.pin, mode) {} + + template consteval void inscribe(Ctx &ctx) const { + ctx.template add(e); + } + }; + + static constexpr std::size_t max_instances{110}; + static_assert(max_instances > 0, + "The number of instances must be greater than 0"); + + struct Config { + size_t id; + std::tuple init_data{}; + }; + + template + static consteval array build(span pins) { + array cfgs{}; + for (std::size_t i = 0; i < N; ++i) { + const auto &e = pins[i]; + + for (std::size_t j = 0; j < i; ++j) { + const auto &prev = pins[j]; + if (prev.pin == e.pin) { + struct gpio_already_inscribed {}; + throw gpio_already_inscribed{}; + } + } + + GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitStruct.Pin = e.pin; + switch (e.mode) { + + case OperationMode::OUTPUT: + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + break; + + case OperationMode::INPUT: + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_NOPULL; + break; + + case OperationMode::ANALOG: + GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; + GPIO_InitStruct.Pull = GPIO_NOPULL; + break; + case OperationMode::EXTERNAL_INTERRUPT_RISING: + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + break; + case OperationMode::EXTERNAL_INTERRUPT_FALLING: + GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + break; + case OperationMode::EXTERNAL_INTERRUPT_RISING_FALLING: + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + break; + // case OperationMode::TIMER_ALTERNATE_FUNCTION: + // GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + // GPIO_InitStruct.Pull = GPIO_NOPULL; + // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + // GPIO_InitStruct.Alternate = pin.alternative_function; + // break; + + default: + break; + } + + cfgs[i].id = e.id; + cfgs[i].init_data = std::make_tuple(e.port, GPIO_InitStruct); + } + + return cfgs; + } + + // Runtime object + struct Instance { + GPIO_TypeDef *port; + uint16_t pin; + + void turn_on() { HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); } + + void turn_off() { HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); } + + void toggle() { HAL_GPIO_TogglePin(port, pin); } + }; + +private: + inline static Instance *instances_ptr = nullptr; + +public: + static Instance &instance(std::size_t id) { return instances_ptr[id]; } + + template struct Init { + static inline std::array instances{}; + + static void init(std::span cfgs) { + static_assert(N > 0); + for (std::size_t i = 0; i < N; ++i) { + const auto &e = cfgs[i]; + auto [port, gpio_init] = e.init_data; + + enable_gpio_clock(port); + HAL_GPIO_Init(port_to_reg(port), &gpio_init); + + auto &inst = instances[e.id]; + inst.port = port_to_reg(port); + inst.pin = gpio_init.Pin; + } + + instances_ptr = instances.data(); + } + }; +}; +} // namespace ST_LIB \ No newline at end of file diff --git a/Inc/HALAL/Models/Pin.hpp b/Inc/HALAL/Models/Pin.hpp new file mode 100644 index 000000000..987e689db --- /dev/null +++ b/Inc/HALAL/Models/Pin.hpp @@ -0,0 +1,7 @@ +#include "HALAL/Models/GPIO.hpp" + +namespace ST_LIB { +constexpr GPIODomain::Pin2 PA0{GPIODomain::Port::A, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PA1{GPIODomain::Port::A, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PB0{GPIODomain::Port::B, GPIO_PIN_0}; +} // namespace ST_LIB \ No newline at end of file diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 0736c791d..68e4efaf6 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -22,4 +22,90 @@ class STLIB { #endif static void update(); -}; \ No newline at end of file +}; + +namespace ST_LIB { +template struct BuildCtx { + template using Decl = typename D::Entry; + template + static constexpr std::size_t max_count_v = D::max_instances; + + std::tuple, max_count_v>...> storage{}; + std::array sizes{}; + + template + static consteval std::size_t domain_index() { + if constexpr (I >= sizeof...(Domains)) { + static_assert([] { return false; }(), "Domain not found"); + return 0; + } else if constexpr (std::is_same_v>>) { + return I; + } else { + return domain_index(); + } + } + + template consteval void add(typename D::Entry e) { + constexpr std::size_t I = domain_index(); + auto &arr = std::get(storage); + auto &size = sizes[I]; + arr[size++] = e; + } + + template consteval auto span() const { + constexpr std::size_t I = domain_index(); + auto const &arr = std::get(storage); + auto const size = sizes[I]; + using E = typename D::Entry; + return std::span{arr.data(), size}; + } +}; + +template consteval std::size_t domain_count() { + return (... + + (std::is_same_v ? 1u : 0u)); +} + +using DomainsCtx = BuildCtx; + +// Configure HW (compile-time) +template consteval auto build() { + DomainsCtx ctx{}; + + (devs.inscribe(ctx), ...); + + constexpr std::size_t gpioN = domain_count(); + // constexpr std::size_t adcN = domain_count(); + // constexpr std::size_t pwmN = domain_count(); + + struct ConfigBundle { + array gpio_cfgs; + // array adc_cgfs; + // array pwm_cgfs; + }; + + return ConfigBundle{ + .gpio_cfgs = + GPIODomain::template build(ctx.template span()), + // .adc_cgfs = + // ADCDomain::template build(ctx.template span()), + // .pwm_cgfs = + // PWMDomain::template build(ctx.template span()), + }; +} + +// Init real HW (runtime) +template void init() { + static constexpr auto cfg = build(); + + constexpr std::size_t gpioN = domain_count(); + // constexpr std::size_t adcN = domain_count(); + // constexpr std::size_t pwmN = domain_count(); + + GPIODomain::Init::init(cfg.gpio_cfgs); + // ADCDomain::Init::init(cfg.adc_cfgs); + // PWMDomain::Init::init(cfg.pwm_cfgs); +} + +} // namespace ST_LIB \ No newline at end of file diff --git a/Inc/stm32h7xx_hal_conf.h b/Inc/stm32h7xx_hal_conf.h index 574000009..74fdc0c32 100644 --- a/Inc/stm32h7xx_hal_conf.h +++ b/Inc/stm32h7xx_hal_conf.h @@ -233,7 +233,7 @@ * @brief Uncomment the line below to expanse the "assert_param" macro in the * HAL drivers code */ -/* #define USE_FULL_ASSERT 1 */ +#define USE_FULL_ASSERT 1 /* Includes ------------------------------------------------------------------*/ From 3eec305d09b320a092d10579cbef5926eb67c0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Sun, 30 Nov 2025 15:50:54 +0100 Subject: [PATCH 02/76] no need to have an id for instance --- Inc/HALAL/Models/GPIO.hpp | 10 +-- Inc/HALAL/Models/Pin.hpp | 148 +++++++++++++++++++++++++++++++++++++- Inc/ST-LIB.hpp | 126 ++++++++++++++++++++++---------- 3 files changed, 237 insertions(+), 47 deletions(-) diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index e9bfafe5a..09da6a27d 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -90,7 +90,6 @@ struct GPIODomain { }; struct Entry { - size_t id; Port port; uint32_t pin; OperationMode mode; @@ -101,8 +100,7 @@ struct GPIODomain { Entry e; - consteval GPIO(std::size_t id, Pin2 pin, OperationMode mode) - : e(id, pin.port, pin.pin, mode) {} + consteval GPIO(Pin2 pin, OperationMode mode) : e(pin.port, pin.pin, mode) {} template consteval void inscribe(Ctx &ctx) const { ctx.template add(e); @@ -114,7 +112,6 @@ struct GPIODomain { "The number of instances must be greater than 0"); struct Config { - size_t id; std::tuple init_data{}; }; @@ -126,7 +123,7 @@ struct GPIODomain { for (std::size_t j = 0; j < i; ++j) { const auto &prev = pins[j]; - if (prev.pin == e.pin) { + if (prev.pin == e.pin && prev.port == e.port) { struct gpio_already_inscribed {}; throw gpio_already_inscribed{}; } @@ -174,7 +171,6 @@ struct GPIODomain { break; } - cfgs[i].id = e.id; cfgs[i].init_data = std::make_tuple(e.port, GPIO_InitStruct); } @@ -211,7 +207,7 @@ struct GPIODomain { enable_gpio_clock(port); HAL_GPIO_Init(port_to_reg(port), &gpio_init); - auto &inst = instances[e.id]; + auto &inst = instances[i]; inst.port = port_to_reg(port); inst.pin = gpio_init.Pin; } diff --git a/Inc/HALAL/Models/Pin.hpp b/Inc/HALAL/Models/Pin.hpp index 987e689db..fd598fcd0 100644 --- a/Inc/HALAL/Models/Pin.hpp +++ b/Inc/HALAL/Models/Pin.hpp @@ -1,7 +1,149 @@ #include "HALAL/Models/GPIO.hpp" namespace ST_LIB { -constexpr GPIODomain::Pin2 PA0{GPIODomain::Port::A, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PA1{GPIODomain::Port::A, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PB0{GPIODomain::Port::B, GPIO_PIN_0}; + +// Port A +constexpr GPIODomain::Pin2 PA0 {GPIODomain::Port::A, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PA1 {GPIODomain::Port::A, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PA2 {GPIODomain::Port::A, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PA3 {GPIODomain::Port::A, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PA4 {GPIODomain::Port::A, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PA5 {GPIODomain::Port::A, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PA6 {GPIODomain::Port::A, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PA7 {GPIODomain::Port::A, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PA8 {GPIODomain::Port::A, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PA9 {GPIODomain::Port::A, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PA10{GPIODomain::Port::A, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PA11{GPIODomain::Port::A, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PA12{GPIODomain::Port::A, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PA13{GPIODomain::Port::A, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PA14{GPIODomain::Port::A, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PA15{GPIODomain::Port::A, GPIO_PIN_15}; + +// Port B +constexpr GPIODomain::Pin2 PB0 {GPIODomain::Port::B, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PB1 {GPIODomain::Port::B, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PB2 {GPIODomain::Port::B, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PB3 {GPIODomain::Port::B, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PB4 {GPIODomain::Port::B, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PB5 {GPIODomain::Port::B, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PB6 {GPIODomain::Port::B, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PB7 {GPIODomain::Port::B, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PB8 {GPIODomain::Port::B, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PB9 {GPIODomain::Port::B, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PB10{GPIODomain::Port::B, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PB11{GPIODomain::Port::B, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PB12{GPIODomain::Port::B, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PB13{GPIODomain::Port::B, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PB14{GPIODomain::Port::B, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PB15{GPIODomain::Port::B, GPIO_PIN_15}; + +// Port C +constexpr GPIODomain::Pin2 PC0 {GPIODomain::Port::C, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PC1 {GPIODomain::Port::C, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PC2 {GPIODomain::Port::C, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PC3 {GPIODomain::Port::C, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PC4 {GPIODomain::Port::C, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PC5 {GPIODomain::Port::C, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PC6 {GPIODomain::Port::C, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PC7 {GPIODomain::Port::C, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PC8 {GPIODomain::Port::C, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PC9 {GPIODomain::Port::C, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PC10{GPIODomain::Port::C, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PC11{GPIODomain::Port::C, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PC12{GPIODomain::Port::C, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PC13{GPIODomain::Port::C, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PC14{GPIODomain::Port::C, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PC15{GPIODomain::Port::C, GPIO_PIN_15}; + +// Port D +constexpr GPIODomain::Pin2 PD0 {GPIODomain::Port::D, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PD1 {GPIODomain::Port::D, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PD2 {GPIODomain::Port::D, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PD3 {GPIODomain::Port::D, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PD4 {GPIODomain::Port::D, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PD5 {GPIODomain::Port::D, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PD6 {GPIODomain::Port::D, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PD7 {GPIODomain::Port::D, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PD8 {GPIODomain::Port::D, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PD9 {GPIODomain::Port::D, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PD10{GPIODomain::Port::D, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PD11{GPIODomain::Port::D, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PD12{GPIODomain::Port::D, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PD13{GPIODomain::Port::D, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PD14{GPIODomain::Port::D, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PD15{GPIODomain::Port::D, GPIO_PIN_15}; + +// Port E +constexpr GPIODomain::Pin2 PE0 {GPIODomain::Port::E, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PE1 {GPIODomain::Port::E, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PE2 {GPIODomain::Port::E, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PE3 {GPIODomain::Port::E, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PE4 {GPIODomain::Port::E, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PE5 {GPIODomain::Port::E, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PE6 {GPIODomain::Port::E, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PE7 {GPIODomain::Port::E, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PE8 {GPIODomain::Port::E, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PE9 {GPIODomain::Port::E, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PE10{GPIODomain::Port::E, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PE11{GPIODomain::Port::E, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PE12{GPIODomain::Port::E, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PE13{GPIODomain::Port::E, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PE14{GPIODomain::Port::E, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PE15{GPIODomain::Port::E, GPIO_PIN_15}; + +// Port F +constexpr GPIODomain::Pin2 PF0 {GPIODomain::Port::F, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PF1 {GPIODomain::Port::F, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PF2 {GPIODomain::Port::F, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PF3 {GPIODomain::Port::F, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PF4 {GPIODomain::Port::F, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PF5 {GPIODomain::Port::F, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PF6 {GPIODomain::Port::F, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PF7 {GPIODomain::Port::F, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PF8 {GPIODomain::Port::F, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PF9 {GPIODomain::Port::F, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PF10{GPIODomain::Port::F, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PF11{GPIODomain::Port::F, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PF12{GPIODomain::Port::F, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PF13{GPIODomain::Port::F, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PF14{GPIODomain::Port::F, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PF15{GPIODomain::Port::F, GPIO_PIN_15}; + +// Port G +constexpr GPIODomain::Pin2 PG0 {GPIODomain::Port::G, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PG1 {GPIODomain::Port::G, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PG2 {GPIODomain::Port::G, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PG3 {GPIODomain::Port::G, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PG4 {GPIODomain::Port::G, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PG5 {GPIODomain::Port::G, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PG6 {GPIODomain::Port::G, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PG7 {GPIODomain::Port::G, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PG8 {GPIODomain::Port::G, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PG9 {GPIODomain::Port::G, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PG10{GPIODomain::Port::G, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PG11{GPIODomain::Port::G, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PG12{GPIODomain::Port::G, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PG13{GPIODomain::Port::G, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PG14{GPIODomain::Port::G, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PG15{GPIODomain::Port::G, GPIO_PIN_15}; + +// Port H +constexpr GPIODomain::Pin2 PH0 {GPIODomain::Port::H, GPIO_PIN_0}; +constexpr GPIODomain::Pin2 PH1 {GPIODomain::Port::H, GPIO_PIN_1}; +constexpr GPIODomain::Pin2 PH2 {GPIODomain::Port::H, GPIO_PIN_2}; +constexpr GPIODomain::Pin2 PH3 {GPIODomain::Port::H, GPIO_PIN_3}; +constexpr GPIODomain::Pin2 PH4 {GPIODomain::Port::H, GPIO_PIN_4}; +constexpr GPIODomain::Pin2 PH5 {GPIODomain::Port::H, GPIO_PIN_5}; +constexpr GPIODomain::Pin2 PH6 {GPIODomain::Port::H, GPIO_PIN_6}; +constexpr GPIODomain::Pin2 PH7 {GPIODomain::Port::H, GPIO_PIN_7}; +constexpr GPIODomain::Pin2 PH8 {GPIODomain::Port::H, GPIO_PIN_8}; +constexpr GPIODomain::Pin2 PH9 {GPIODomain::Port::H, GPIO_PIN_9}; +constexpr GPIODomain::Pin2 PH10{GPIODomain::Port::H, GPIO_PIN_10}; +constexpr GPIODomain::Pin2 PH11{GPIODomain::Port::H, GPIO_PIN_11}; +constexpr GPIODomain::Pin2 PH12{GPIODomain::Port::H, GPIO_PIN_12}; +constexpr GPIODomain::Pin2 PH13{GPIODomain::Port::H, GPIO_PIN_13}; +constexpr GPIODomain::Pin2 PH14{GPIODomain::Port::H, GPIO_PIN_14}; +constexpr GPIODomain::Pin2 PH15{GPIODomain::Port::H, GPIO_PIN_15}; + } // namespace ST_LIB \ No newline at end of file diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 68e4efaf6..2f416eb5f 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -62,50 +62,102 @@ template struct BuildCtx { } }; -template consteval std::size_t domain_count() { +template consteval std::size_t domain_count() { return (... + - (std::is_same_v ? 1u : 0u)); + (std::is_same_v::domain, + Domain> + ? 1u + : 0u)); } using DomainsCtx = BuildCtx; -// Configure HW (compile-time) -template consteval auto build() { - DomainsCtx ctx{}; - - (devs.inscribe(ctx), ...); - - constexpr std::size_t gpioN = domain_count(); - // constexpr std::size_t adcN = domain_count(); - // constexpr std::size_t pwmN = domain_count(); - - struct ConfigBundle { - array gpio_cfgs; - // array adc_cgfs; - // array pwm_cgfs; - }; - - return ConfigBundle{ - .gpio_cfgs = - GPIODomain::template build(ctx.template span()), - // .adc_cgfs = - // ADCDomain::template build(ctx.template span()), - // .pwm_cgfs = - // PWMDomain::template build(ctx.template span()), - }; -} +template struct Board { + // ========== build compile-time ========== + static consteval auto build() { + DomainsCtx ctx{}; + + (devs.inscribe(ctx), ...); + + constexpr std::size_t gpioN = domain_count(); + // constexpr std::size_t adcN = domain_count(); + // constexpr std::size_t pwmN = domain_count(); + + struct ConfigBundle { + std::array gpio_cfgs; + // std::array adc_cgfs; + // std::array pwm_cgfs; + }; + + return ConfigBundle{ + .gpio_cfgs = + GPIODomain::template build(ctx.template span()), + // .adc_cgfs = + // ADCDomain::template build(ctx.template span()), + // .pwm_cgfs = + // PWMDomain::template build(ctx.template span()), + }; + } -// Init real HW (runtime) -template void init() { - static constexpr auto cfg = build(); + // ========== init runtime ========== + static void init() { + static constexpr auto cfg = build(); - constexpr std::size_t gpioN = domain_count(); - // constexpr std::size_t adcN = domain_count(); - // constexpr std::size_t pwmN = domain_count(); + constexpr std::size_t gpioN = domain_count(); + // constexpr std::size_t adcN = domain_count(); + // constexpr std::size_t pwmN = domain_count(); - GPIODomain::Init::init(cfg.gpio_cfgs); - // ADCDomain::Init::init(cfg.adc_cfgs); - // PWMDomain::Init::init(cfg.pwm_cfgs); -} + GPIODomain::Init::init(cfg.gpio_cfgs); + // ADCDomain::Init::init(cfg.adc_cfgs); + // PWMDomain::Init::init(cfg.pwm_cfgs); + } + + template static consteval std::size_t domain_size() { + return domain_count(); + } + + template + static consteval std::size_t domain_index_of_impl() { + std::size_t idx = 0; + bool found = false; + + ( + [&] { + using DevT = std::remove_cvref_t; + if constexpr (std::is_same_v) { + if (!found) { + if (&devs == &Target) { + found = true; + } else { + ++idx; + } + } + } + }(), + ...); + + if (!found) { + struct device_not_found_for_domain {}; + throw device_not_found_for_domain{}; + } + + return idx; + } + + template + static consteval std::size_t domain_index_of() { + return domain_index_of_impl(); + } + + template static auto &instance_of() { + using DevT = std::remove_cvref_t; + using Domain = typename DevT::domain; + + constexpr std::size_t idx = domain_index_of(); + constexpr std::size_t N = domain_size(); + + return Domain::template Init::instances[idx]; + } +}; } // namespace ST_LIB \ No newline at end of file From fa3498bc702818fbbd6ab0b3d486bdb13b7c2960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 1 Dec 2025 23:47:30 +0100 Subject: [PATCH 03/76] erased no longer needed code --- Inc/HALAL/Models/GPIO.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index 09da6a27d..5423cd22d 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -189,12 +189,6 @@ struct GPIODomain { void toggle() { HAL_GPIO_TogglePin(port, pin); } }; -private: - inline static Instance *instances_ptr = nullptr; - -public: - static Instance &instance(std::size_t id) { return instances_ptr[id]; } - template struct Init { static inline std::array instances{}; @@ -211,8 +205,6 @@ struct GPIODomain { inst.port = port_to_reg(port); inst.pin = gpio_init.Pin; } - - instances_ptr = instances.data(); } }; }; From c92a7386f0218300f3d5241caf705f0ccba86f1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Wed, 3 Dec 2025 00:23:23 +0100 Subject: [PATCH 04/76] Added DigitalInput and DigitalOutput Services, and added support for Alternate functions --- CMakeLists.txt | 1 - Inc/HALAL/Models/GPIO.hpp | 167 ++++++++++++------- Inc/HALAL/Models/Pin.hpp | 258 +++++++++++++++--------------- Inc/ST-LIB.hpp | 80 +++++---- Inc/ST-LIB_LOW/DigitalInput2.hpp | 63 ++++++++ Inc/ST-LIB_LOW/DigitalOutput2.hpp | 75 +++++++++ Inc/ST-LIB_LOW/ST-LIB_LOW.hpp | 3 + 7 files changed, 426 insertions(+), 221 deletions(-) create mode 100644 Inc/ST-LIB_LOW/DigitalInput2.hpp create mode 100644 Inc/ST-LIB_LOW/DigitalOutput2.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d35f2ef8..9ff603b45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -263,7 +263,6 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE $<$:-specs=nosys.specs> $<$:-ffunction-sections> $<$:-fdata-sections> - # $<$:-fno-exceptions> -Wno-psabi diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index 5423cd22d..335ac3d26 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -13,14 +13,80 @@ using std::tuple; namespace ST_LIB { struct GPIODomain { enum class OperationMode : uint8_t { - INPUT, - OUTPUT, - ANALOG, - EXTERNAL_INTERRUPT_RISING, - EXTERNAL_INTERRUPT_FALLING, - EXTERNAL_INTERRUPT_RISING_FALLING, - TIMER_ALTERNATE_FUNCTION, - ALTERNATIVE, + INPUT, // GPIO_MODE_INPUT + OUTPUT_PUSHPULL, // GPIO_MODE_OUTPUT_PP + OUTPUT_OPENDRAIN, // GPIO_MODE_OUTPUT_OD + ANALOG, // GPIO_MODE_ANALOG + ALT_PP, // GPIO_MODE_AF_PP + ALT_OD, // GPIO_MODE_AF_OD + EXTI_RISING, // GPIO_MODE_IT_RISING + EXTI_FALLING, // GPIO_MODE_IT_FALLING + EXTI_RISING_FALLING, // GPIO_MODE_IT_RISING_FALLING + }; + static constexpr uint32_t to_hal_mode(OperationMode m) { + switch (m) { + case OperationMode::INPUT: + return GPIO_MODE_INPUT; + case OperationMode::OUTPUT_PUSHPULL: + return GPIO_MODE_OUTPUT_PP; + case OperationMode::OUTPUT_OPENDRAIN: + return GPIO_MODE_OUTPUT_OD; + case OperationMode::ANALOG: + return GPIO_MODE_ANALOG; + case OperationMode::ALT_PP: + return GPIO_MODE_AF_PP; + case OperationMode::ALT_OD: + return GPIO_MODE_AF_OD; + case OperationMode::EXTI_RISING: + return GPIO_MODE_IT_RISING; + case OperationMode::EXTI_FALLING: + return GPIO_MODE_IT_FALLING; + case OperationMode::EXTI_RISING_FALLING: + return GPIO_MODE_IT_RISING_FALLING; + } + } + enum class Pull : uint8_t { None, Up, Down }; + static constexpr uint32_t to_hal_pull(Pull p) { + switch (p) { + case Pull::None: + return GPIO_NOPULL; + case Pull::Up: + return GPIO_PULLUP; + case Pull::Down: + return GPIO_PULLDOWN; + } + } + enum class Speed : uint8_t { Low, Medium, High, VeryHigh }; + static constexpr uint32_t to_hal_speed(Speed s) { + switch (s) { + case Speed::Low: + return GPIO_SPEED_FREQ_LOW; + case Speed::Medium: + return GPIO_SPEED_FREQ_MEDIUM; + case Speed::High: + return GPIO_SPEED_FREQ_HIGH; + case Speed::VeryHigh: + return GPIO_SPEED_FREQ_VERY_HIGH; + } + } + enum class AlternateFunction : uint8_t { + NO_AF = 20, + AF0 = 15, + AF1 = 14, + AF2 = 13, + AF3 = 12, + AF4 = 11, + AF5 = 10, + AF6 = 9, + AF7 = 8, + AF8 = 7, + AF9 = 6, + AF10 = 5, + AF11 = 4, + AF12 = 3, + AF13 = 2, + AF14 = 1, + AF15 = 0 }; enum class Port : uint8_t { A, B, C, D, E, F, G, H }; static inline GPIO_TypeDef *port_to_reg(Port p) { @@ -81,18 +147,25 @@ struct GPIODomain { } } - struct Pin2 { + struct Pin { GPIODomain::Port port; uint32_t pin; + uint16_t afs; - consteval Pin2(GPIODomain::Port port, uint32_t pin) - : port(port), pin(pin) {} + inline constexpr bool valid_af(const AlternateFunction af) const { + if (af == AlternateFunction::NO_AF) + return true; + return ((1 << static_cast(af)) & afs) != 0; + } }; struct Entry { Port port; uint32_t pin; OperationMode mode; + Pull pull; + Speed speed; + AlternateFunction af; }; struct GPIO { @@ -100,7 +173,13 @@ struct GPIODomain { Entry e; - consteval GPIO(Pin2 pin, OperationMode mode) : e(pin.port, pin.pin, mode) {} + consteval GPIO(const Pin &pin, OperationMode mode, Pull pull, Speed speed, + AlternateFunction af = AlternateFunction::NO_AF) + : e{pin.port, pin.pin, mode, pull, speed, af} { + if (!pin.valid_af(af)) { + throw "Alternate function not valid for this pin"; + } + } template consteval void inscribe(Ctx &ctx) const { ctx.template add(e); @@ -108,8 +187,6 @@ struct GPIODomain { }; static constexpr std::size_t max_instances{110}; - static_assert(max_instances > 0, - "The number of instances must be greater than 0"); struct Config { std::tuple init_data{}; @@ -124,51 +201,17 @@ struct GPIODomain { for (std::size_t j = 0; j < i; ++j) { const auto &prev = pins[j]; if (prev.pin == e.pin && prev.port == e.port) { - struct gpio_already_inscribed {}; - throw gpio_already_inscribed{}; + throw "GPIO already inscribed"; } } - GPIO_InitTypeDef GPIO_InitStruct; + GPIO_InitTypeDef GPIO_InitStruct{}; GPIO_InitStruct.Pin = e.pin; - switch (e.mode) { - - case OperationMode::OUTPUT: - GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; - GPIO_InitStruct.Pull = GPIO_NOPULL; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - break; - - case OperationMode::INPUT: - GPIO_InitStruct.Mode = GPIO_MODE_INPUT; - GPIO_InitStruct.Pull = GPIO_NOPULL; - break; - - case OperationMode::ANALOG: - GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; - GPIO_InitStruct.Pull = GPIO_NOPULL; - break; - case OperationMode::EXTERNAL_INTERRUPT_RISING: - GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; - GPIO_InitStruct.Pull = GPIO_PULLDOWN; - break; - case OperationMode::EXTERNAL_INTERRUPT_FALLING: - GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; - GPIO_InitStruct.Pull = GPIO_PULLDOWN; - break; - case OperationMode::EXTERNAL_INTERRUPT_RISING_FALLING: - GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; - GPIO_InitStruct.Pull = GPIO_PULLDOWN; - break; - // case OperationMode::TIMER_ALTERNATE_FUNCTION: - // GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - // GPIO_InitStruct.Pull = GPIO_NOPULL; - // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; - // GPIO_InitStruct.Alternate = pin.alternative_function; - // break; - - default: - break; + GPIO_InitStruct.Mode = to_hal_mode(e.mode); + GPIO_InitStruct.Pull = to_hal_pull(e.pull); + GPIO_InitStruct.Speed = to_hal_speed(e.speed); + if (e.mode == OperationMode::ALT_PP || e.mode == OperationMode::ALT_OD) { + GPIO_InitStruct.Alternate = static_cast(e.af); } cfgs[i].init_data = std::make_tuple(e.port, GPIO_InitStruct); @@ -179,14 +222,22 @@ struct GPIODomain { // Runtime object struct Instance { + private: GPIO_TypeDef *port; - uint16_t pin; + uint32_t pin; + + public: + constexpr Instance() : port{nullptr}, pin{0} {} + Instance(GPIO_TypeDef *p, uint32_t pin) + : port{p}, pin{static_cast(pin)} {} void turn_on() { HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET); } void turn_off() { HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET); } void toggle() { HAL_GPIO_TogglePin(port, pin); } + + GPIO_PinState read() { return HAL_GPIO_ReadPin(port, pin); } }; template struct Init { @@ -201,9 +252,7 @@ struct GPIODomain { enable_gpio_clock(port); HAL_GPIO_Init(port_to_reg(port), &gpio_init); - auto &inst = instances[i]; - inst.port = port_to_reg(port); - inst.pin = gpio_init.Pin; + instances[i] = Instance{port_to_reg(port), gpio_init.Pin}; } } }; diff --git a/Inc/HALAL/Models/Pin.hpp b/Inc/HALAL/Models/Pin.hpp index fd598fcd0..bc3a5331e 100644 --- a/Inc/HALAL/Models/Pin.hpp +++ b/Inc/HALAL/Models/Pin.hpp @@ -1,149 +1,151 @@ #include "HALAL/Models/GPIO.hpp" +using enum ST_LIB::GPIODomain::Port; + namespace ST_LIB { // Port A -constexpr GPIODomain::Pin2 PA0 {GPIODomain::Port::A, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PA1 {GPIODomain::Port::A, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PA2 {GPIODomain::Port::A, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PA3 {GPIODomain::Port::A, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PA4 {GPIODomain::Port::A, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PA5 {GPIODomain::Port::A, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PA6 {GPIODomain::Port::A, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PA7 {GPIODomain::Port::A, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PA8 {GPIODomain::Port::A, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PA9 {GPIODomain::Port::A, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PA10{GPIODomain::Port::A, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PA11{GPIODomain::Port::A, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PA12{GPIODomain::Port::A, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PA13{GPIODomain::Port::A, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PA14{GPIODomain::Port::A, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PA15{GPIODomain::Port::A, GPIO_PIN_15}; +constexpr GPIODomain::Pin PA0{A, GPIO_PIN_0, 0b0111110111111001}; +constexpr GPIODomain::Pin PA1{A, GPIO_PIN_1}; +constexpr GPIODomain::Pin PA2{A, GPIO_PIN_2}; +constexpr GPIODomain::Pin PA3{A, GPIO_PIN_3}; +constexpr GPIODomain::Pin PA4{A, GPIO_PIN_4}; +constexpr GPIODomain::Pin PA5{A, GPIO_PIN_5}; +constexpr GPIODomain::Pin PA6{A, GPIO_PIN_6}; +constexpr GPIODomain::Pin PA7{A, GPIO_PIN_7}; +constexpr GPIODomain::Pin PA8{A, GPIO_PIN_8}; +constexpr GPIODomain::Pin PA9{A, GPIO_PIN_9}; +constexpr GPIODomain::Pin PA10{A, GPIO_PIN_10}; +constexpr GPIODomain::Pin PA11{A, GPIO_PIN_11}; +constexpr GPIODomain::Pin PA12{A, GPIO_PIN_12}; +constexpr GPIODomain::Pin PA13{A, GPIO_PIN_13}; +constexpr GPIODomain::Pin PA14{A, GPIO_PIN_14}; +constexpr GPIODomain::Pin PA15{A, GPIO_PIN_15}; // Port B -constexpr GPIODomain::Pin2 PB0 {GPIODomain::Port::B, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PB1 {GPIODomain::Port::B, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PB2 {GPIODomain::Port::B, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PB3 {GPIODomain::Port::B, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PB4 {GPIODomain::Port::B, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PB5 {GPIODomain::Port::B, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PB6 {GPIODomain::Port::B, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PB7 {GPIODomain::Port::B, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PB8 {GPIODomain::Port::B, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PB9 {GPIODomain::Port::B, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PB10{GPIODomain::Port::B, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PB11{GPIODomain::Port::B, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PB12{GPIODomain::Port::B, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PB13{GPIODomain::Port::B, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PB14{GPIODomain::Port::B, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PB15{GPIODomain::Port::B, GPIO_PIN_15}; +constexpr GPIODomain::Pin PB0{B, GPIO_PIN_0}; +constexpr GPIODomain::Pin PB1{B, GPIO_PIN_1}; +constexpr GPIODomain::Pin PB2{B, GPIO_PIN_2}; +constexpr GPIODomain::Pin PB3{B, GPIO_PIN_3}; +constexpr GPIODomain::Pin PB4{B, GPIO_PIN_4}; +constexpr GPIODomain::Pin PB5{B, GPIO_PIN_5}; +constexpr GPIODomain::Pin PB6{B, GPIO_PIN_6}; +constexpr GPIODomain::Pin PB7{B, GPIO_PIN_7}; +constexpr GPIODomain::Pin PB8{B, GPIO_PIN_8}; +constexpr GPIODomain::Pin PB9{B, GPIO_PIN_9}; +constexpr GPIODomain::Pin PB10{B, GPIO_PIN_10}; +constexpr GPIODomain::Pin PB11{B, GPIO_PIN_11}; +constexpr GPIODomain::Pin PB12{B, GPIO_PIN_12}; +constexpr GPIODomain::Pin PB13{B, GPIO_PIN_13}; +constexpr GPIODomain::Pin PB14{B, GPIO_PIN_14}; +constexpr GPIODomain::Pin PB15{B, GPIO_PIN_15}; // Port C -constexpr GPIODomain::Pin2 PC0 {GPIODomain::Port::C, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PC1 {GPIODomain::Port::C, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PC2 {GPIODomain::Port::C, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PC3 {GPIODomain::Port::C, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PC4 {GPIODomain::Port::C, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PC5 {GPIODomain::Port::C, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PC6 {GPIODomain::Port::C, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PC7 {GPIODomain::Port::C, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PC8 {GPIODomain::Port::C, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PC9 {GPIODomain::Port::C, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PC10{GPIODomain::Port::C, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PC11{GPIODomain::Port::C, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PC12{GPIODomain::Port::C, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PC13{GPIODomain::Port::C, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PC14{GPIODomain::Port::C, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PC15{GPIODomain::Port::C, GPIO_PIN_15}; +constexpr GPIODomain::Pin PC0{C, GPIO_PIN_0}; +constexpr GPIODomain::Pin PC1{C, GPIO_PIN_1}; +constexpr GPIODomain::Pin PC2{C, GPIO_PIN_2}; +constexpr GPIODomain::Pin PC3{C, GPIO_PIN_3}; +constexpr GPIODomain::Pin PC4{C, GPIO_PIN_4}; +constexpr GPIODomain::Pin PC5{C, GPIO_PIN_5}; +constexpr GPIODomain::Pin PC6{C, GPIO_PIN_6}; +constexpr GPIODomain::Pin PC7{C, GPIO_PIN_7}; +constexpr GPIODomain::Pin PC8{C, GPIO_PIN_8}; +constexpr GPIODomain::Pin PC9{C, GPIO_PIN_9}; +constexpr GPIODomain::Pin PC10{C, GPIO_PIN_10}; +constexpr GPIODomain::Pin PC11{C, GPIO_PIN_11}; +constexpr GPIODomain::Pin PC12{C, GPIO_PIN_12}; +constexpr GPIODomain::Pin PC13{C, GPIO_PIN_13}; +constexpr GPIODomain::Pin PC14{C, GPIO_PIN_14}; +constexpr GPIODomain::Pin PC15{C, GPIO_PIN_15}; // Port D -constexpr GPIODomain::Pin2 PD0 {GPIODomain::Port::D, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PD1 {GPIODomain::Port::D, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PD2 {GPIODomain::Port::D, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PD3 {GPIODomain::Port::D, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PD4 {GPIODomain::Port::D, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PD5 {GPIODomain::Port::D, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PD6 {GPIODomain::Port::D, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PD7 {GPIODomain::Port::D, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PD8 {GPIODomain::Port::D, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PD9 {GPIODomain::Port::D, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PD10{GPIODomain::Port::D, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PD11{GPIODomain::Port::D, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PD12{GPIODomain::Port::D, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PD13{GPIODomain::Port::D, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PD14{GPIODomain::Port::D, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PD15{GPIODomain::Port::D, GPIO_PIN_15}; +constexpr GPIODomain::Pin PD0{D, GPIO_PIN_0}; +constexpr GPIODomain::Pin PD1{D, GPIO_PIN_1}; +constexpr GPIODomain::Pin PD2{D, GPIO_PIN_2}; +constexpr GPIODomain::Pin PD3{D, GPIO_PIN_3}; +constexpr GPIODomain::Pin PD4{D, GPIO_PIN_4}; +constexpr GPIODomain::Pin PD5{D, GPIO_PIN_5}; +constexpr GPIODomain::Pin PD6{D, GPIO_PIN_6}; +constexpr GPIODomain::Pin PD7{D, GPIO_PIN_7}; +constexpr GPIODomain::Pin PD8{D, GPIO_PIN_8}; +constexpr GPIODomain::Pin PD9{D, GPIO_PIN_9}; +constexpr GPIODomain::Pin PD10{D, GPIO_PIN_10}; +constexpr GPIODomain::Pin PD11{D, GPIO_PIN_11}; +constexpr GPIODomain::Pin PD12{D, GPIO_PIN_12}; +constexpr GPIODomain::Pin PD13{D, GPIO_PIN_13}; +constexpr GPIODomain::Pin PD14{D, GPIO_PIN_14}; +constexpr GPIODomain::Pin PD15{D, GPIO_PIN_15}; // Port E -constexpr GPIODomain::Pin2 PE0 {GPIODomain::Port::E, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PE1 {GPIODomain::Port::E, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PE2 {GPIODomain::Port::E, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PE3 {GPIODomain::Port::E, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PE4 {GPIODomain::Port::E, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PE5 {GPIODomain::Port::E, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PE6 {GPIODomain::Port::E, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PE7 {GPIODomain::Port::E, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PE8 {GPIODomain::Port::E, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PE9 {GPIODomain::Port::E, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PE10{GPIODomain::Port::E, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PE11{GPIODomain::Port::E, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PE12{GPIODomain::Port::E, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PE13{GPIODomain::Port::E, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PE14{GPIODomain::Port::E, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PE15{GPIODomain::Port::E, GPIO_PIN_15}; +constexpr GPIODomain::Pin PE0{E, GPIO_PIN_0}; +constexpr GPIODomain::Pin PE1{E, GPIO_PIN_1}; +constexpr GPIODomain::Pin PE2{E, GPIO_PIN_2}; +constexpr GPIODomain::Pin PE3{E, GPIO_PIN_3}; +constexpr GPIODomain::Pin PE4{E, GPIO_PIN_4}; +constexpr GPIODomain::Pin PE5{E, GPIO_PIN_5}; +constexpr GPIODomain::Pin PE6{E, GPIO_PIN_6}; +constexpr GPIODomain::Pin PE7{E, GPIO_PIN_7}; +constexpr GPIODomain::Pin PE8{E, GPIO_PIN_8}; +constexpr GPIODomain::Pin PE9{E, GPIO_PIN_9}; +constexpr GPIODomain::Pin PE10{E, GPIO_PIN_10}; +constexpr GPIODomain::Pin PE11{E, GPIO_PIN_11}; +constexpr GPIODomain::Pin PE12{E, GPIO_PIN_12}; +constexpr GPIODomain::Pin PE13{E, GPIO_PIN_13}; +constexpr GPIODomain::Pin PE14{E, GPIO_PIN_14}; +constexpr GPIODomain::Pin PE15{E, GPIO_PIN_15}; // Port F -constexpr GPIODomain::Pin2 PF0 {GPIODomain::Port::F, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PF1 {GPIODomain::Port::F, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PF2 {GPIODomain::Port::F, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PF3 {GPIODomain::Port::F, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PF4 {GPIODomain::Port::F, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PF5 {GPIODomain::Port::F, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PF6 {GPIODomain::Port::F, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PF7 {GPIODomain::Port::F, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PF8 {GPIODomain::Port::F, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PF9 {GPIODomain::Port::F, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PF10{GPIODomain::Port::F, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PF11{GPIODomain::Port::F, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PF12{GPIODomain::Port::F, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PF13{GPIODomain::Port::F, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PF14{GPIODomain::Port::F, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PF15{GPIODomain::Port::F, GPIO_PIN_15}; +constexpr GPIODomain::Pin PF0{F, GPIO_PIN_0}; +constexpr GPIODomain::Pin PF1{F, GPIO_PIN_1}; +constexpr GPIODomain::Pin PF2{F, GPIO_PIN_2}; +constexpr GPIODomain::Pin PF3{F, GPIO_PIN_3}; +constexpr GPIODomain::Pin PF4{F, GPIO_PIN_4}; +constexpr GPIODomain::Pin PF5{F, GPIO_PIN_5}; +constexpr GPIODomain::Pin PF6{F, GPIO_PIN_6}; +constexpr GPIODomain::Pin PF7{F, GPIO_PIN_7}; +constexpr GPIODomain::Pin PF8{F, GPIO_PIN_8}; +constexpr GPIODomain::Pin PF9{F, GPIO_PIN_9}; +constexpr GPIODomain::Pin PF10{F, GPIO_PIN_10}; +constexpr GPIODomain::Pin PF11{F, GPIO_PIN_11}; +constexpr GPIODomain::Pin PF12{F, GPIO_PIN_12}; +constexpr GPIODomain::Pin PF13{F, GPIO_PIN_13}; +constexpr GPIODomain::Pin PF14{F, GPIO_PIN_14}; +constexpr GPIODomain::Pin PF15{F, GPIO_PIN_15}; // Port G -constexpr GPIODomain::Pin2 PG0 {GPIODomain::Port::G, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PG1 {GPIODomain::Port::G, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PG2 {GPIODomain::Port::G, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PG3 {GPIODomain::Port::G, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PG4 {GPIODomain::Port::G, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PG5 {GPIODomain::Port::G, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PG6 {GPIODomain::Port::G, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PG7 {GPIODomain::Port::G, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PG8 {GPIODomain::Port::G, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PG9 {GPIODomain::Port::G, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PG10{GPIODomain::Port::G, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PG11{GPIODomain::Port::G, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PG12{GPIODomain::Port::G, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PG13{GPIODomain::Port::G, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PG14{GPIODomain::Port::G, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PG15{GPIODomain::Port::G, GPIO_PIN_15}; +constexpr GPIODomain::Pin PG0{G, GPIO_PIN_0}; +constexpr GPIODomain::Pin PG1{G, GPIO_PIN_1}; +constexpr GPIODomain::Pin PG2{G, GPIO_PIN_2}; +constexpr GPIODomain::Pin PG3{G, GPIO_PIN_3}; +constexpr GPIODomain::Pin PG4{G, GPIO_PIN_4}; +constexpr GPIODomain::Pin PG5{G, GPIO_PIN_5}; +constexpr GPIODomain::Pin PG6{G, GPIO_PIN_6}; +constexpr GPIODomain::Pin PG7{G, GPIO_PIN_7}; +constexpr GPIODomain::Pin PG8{G, GPIO_PIN_8}; +constexpr GPIODomain::Pin PG9{G, GPIO_PIN_9}; +constexpr GPIODomain::Pin PG10{G, GPIO_PIN_10}; +constexpr GPIODomain::Pin PG11{G, GPIO_PIN_11}; +constexpr GPIODomain::Pin PG12{G, GPIO_PIN_12}; +constexpr GPIODomain::Pin PG13{G, GPIO_PIN_13}; +constexpr GPIODomain::Pin PG14{G, GPIO_PIN_14}; +constexpr GPIODomain::Pin PG15{G, GPIO_PIN_15}; // Port H -constexpr GPIODomain::Pin2 PH0 {GPIODomain::Port::H, GPIO_PIN_0}; -constexpr GPIODomain::Pin2 PH1 {GPIODomain::Port::H, GPIO_PIN_1}; -constexpr GPIODomain::Pin2 PH2 {GPIODomain::Port::H, GPIO_PIN_2}; -constexpr GPIODomain::Pin2 PH3 {GPIODomain::Port::H, GPIO_PIN_3}; -constexpr GPIODomain::Pin2 PH4 {GPIODomain::Port::H, GPIO_PIN_4}; -constexpr GPIODomain::Pin2 PH5 {GPIODomain::Port::H, GPIO_PIN_5}; -constexpr GPIODomain::Pin2 PH6 {GPIODomain::Port::H, GPIO_PIN_6}; -constexpr GPIODomain::Pin2 PH7 {GPIODomain::Port::H, GPIO_PIN_7}; -constexpr GPIODomain::Pin2 PH8 {GPIODomain::Port::H, GPIO_PIN_8}; -constexpr GPIODomain::Pin2 PH9 {GPIODomain::Port::H, GPIO_PIN_9}; -constexpr GPIODomain::Pin2 PH10{GPIODomain::Port::H, GPIO_PIN_10}; -constexpr GPIODomain::Pin2 PH11{GPIODomain::Port::H, GPIO_PIN_11}; -constexpr GPIODomain::Pin2 PH12{GPIODomain::Port::H, GPIO_PIN_12}; -constexpr GPIODomain::Pin2 PH13{GPIODomain::Port::H, GPIO_PIN_13}; -constexpr GPIODomain::Pin2 PH14{GPIODomain::Port::H, GPIO_PIN_14}; -constexpr GPIODomain::Pin2 PH15{GPIODomain::Port::H, GPIO_PIN_15}; +constexpr GPIODomain::Pin PH0{H, GPIO_PIN_0}; +constexpr GPIODomain::Pin PH1{H, GPIO_PIN_1}; +constexpr GPIODomain::Pin PH2{H, GPIO_PIN_2}; +constexpr GPIODomain::Pin PH3{H, GPIO_PIN_3}; +constexpr GPIODomain::Pin PH4{H, GPIO_PIN_4}; +constexpr GPIODomain::Pin PH5{H, GPIO_PIN_5}; +constexpr GPIODomain::Pin PH6{H, GPIO_PIN_6}; +constexpr GPIODomain::Pin PH7{H, GPIO_PIN_7}; +constexpr GPIODomain::Pin PH8{H, GPIO_PIN_8}; +constexpr GPIODomain::Pin PH9{H, GPIO_PIN_9}; +constexpr GPIODomain::Pin PH10{H, GPIO_PIN_10}; +constexpr GPIODomain::Pin PH11{H, GPIO_PIN_11}; +constexpr GPIODomain::Pin PH12{H, GPIO_PIN_12}; +constexpr GPIODomain::Pin PH13{H, GPIO_PIN_13}; +constexpr GPIODomain::Pin PH14{H, GPIO_PIN_14}; +constexpr GPIODomain::Pin PH15{H, GPIO_PIN_15}; } // namespace ST_LIB \ No newline at end of file diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 2f416eb5f..dff92504d 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -46,11 +46,13 @@ template struct BuildCtx { } } - template consteval void add(typename D::Entry e) { + template consteval std::size_t add(typename D::Entry e) { constexpr std::size_t I = domain_index(); auto &arr = std::get(storage); auto &size = sizes[I]; + const auto idx = size; arr[size++] = e; + return idx; } template consteval auto span() const { @@ -60,60 +62,72 @@ template struct BuildCtx { using E = typename D::Entry; return std::span{arr.data(), size}; } -}; -template consteval std::size_t domain_count() { - return (... + - (std::is_same_v::domain, - Domain> - ? 1u - : 0u)); -} + template consteval std::size_t size() const { + constexpr std::size_t I = domain_index(); + return sizes[I]; + } +}; -using DomainsCtx = BuildCtx; +using DomainsCtx = BuildCtx; template struct Board { - // ========== build compile-time ========== - static consteval auto build() { + static consteval auto build_ctx() { DomainsCtx ctx{}; - (devs.inscribe(ctx), ...); + return ctx; + } + + static constexpr auto ctx = build_ctx(); - constexpr std::size_t gpioN = domain_count(); - // constexpr std::size_t adcN = domain_count(); - // constexpr std::size_t pwmN = domain_count(); + template static consteval std::size_t domain_size() { + return ctx.template span().size(); + } + + static consteval auto build() { + constexpr std::size_t gpioN = domain_size(); + constexpr std::size_t doutN = domain_size(); + constexpr std::size_t dinN = domain_size(); + // ... struct ConfigBundle { std::array gpio_cfgs; - // std::array adc_cgfs; - // std::array pwm_cgfs; + std::array dout_cfgs; + std::array din_cfgs; + // ... }; return ConfigBundle{ .gpio_cfgs = GPIODomain::template build(ctx.template span()), - // .adc_cgfs = - // ADCDomain::template build(ctx.template span()), - // .pwm_cgfs = - // PWMDomain::template build(ctx.template span()), + .dout_cfgs = DigitalOutputDomain::template build( + ctx.template span()), + .din_cfgs = DigitalInputDomain::template build( + ctx.template span()), + // ... }; } - // ========== init runtime ========== - static void init() { - static constexpr auto cfg = build(); + static constexpr auto cfg = build(); - constexpr std::size_t gpioN = domain_count(); - // constexpr std::size_t adcN = domain_count(); - // constexpr std::size_t pwmN = domain_count(); + static void init() { + constexpr std::size_t gpioN = domain_size(); + constexpr std::size_t doutN = domain_size(); + constexpr std::size_t dinN = domain_size(); + // ... GPIODomain::Init::init(cfg.gpio_cfgs); - // ADCDomain::Init::init(cfg.adc_cfgs); - // PWMDomain::Init::init(cfg.pwm_cfgs); + DigitalOutputDomain::Init::init(cfg.dout_cfgs, + GPIODomain::Init::instances); + DigitalInputDomain::Init::init(cfg.din_cfgs, + GPIODomain::Init::instances); + // ... } - template static consteval std::size_t domain_size() { - return domain_count(); + template + static consteval std::size_t domain_size_for_instance() { + return domain_size(); } template @@ -154,7 +168,7 @@ template struct Board { using Domain = typename DevT::domain; constexpr std::size_t idx = domain_index_of(); - constexpr std::size_t N = domain_size(); + constexpr std::size_t N = domain_size_for_instance(); return Domain::template Init::instances[idx]; } diff --git a/Inc/ST-LIB_LOW/DigitalInput2.hpp b/Inc/ST-LIB_LOW/DigitalInput2.hpp new file mode 100644 index 000000000..e161e39a5 --- /dev/null +++ b/Inc/ST-LIB_LOW/DigitalInput2.hpp @@ -0,0 +1,63 @@ +#pragma once + +#include "HALAL/Models/GPIO.hpp" + +using ST_LIB::GPIODomain; + +namespace ST_LIB { +struct DigitalInputDomain { + struct Entry { + size_t gpio_idx; + }; + struct DigitalInput { + GPIODomain::GPIO gpio; + using domain = DigitalInputDomain; + + consteval DigitalInput(const GPIODomain::Pin &pin, + GPIODomain::Pull pull = GPIODomain::Pull::None, + GPIODomain::Speed speed = GPIODomain::Speed::Low) + : gpio{pin, GPIODomain::OperationMode::INPUT, pull, speed} {} + + template consteval void inscribe(Ctx &ctx) const { + const auto gpio_idx = ctx.template add(gpio.e); + Entry e{.gpio_idx = gpio_idx}; + ctx.template add(e); + } + }; + + static constexpr std::size_t max_instances{110}; + + struct Config { + size_t gpio_idx; + }; + + template + static consteval array build(span outputs) { + array cfgs{}; + + for (std::size_t i = 0; i < N; ++i) { + cfgs[i].gpio_idx = outputs[i].gpio_idx; + } + return cfgs; + } + + struct Instance { + GPIODomain::Instance *gpio_instance; + + GPIO_PinState read() { return gpio_instance->read(); } + }; + + template struct Init { + static inline std::array instances{}; + + static void init(std::span cfgs, + std::span gpio_instances) { + for (std::size_t i = 0; i < N; ++i) { + const auto &e = cfgs[i]; + + instances[i].gpio_instance = &gpio_instances[e.gpio_idx]; + } + } + }; +}; +} // namespace ST_LIB diff --git a/Inc/ST-LIB_LOW/DigitalOutput2.hpp b/Inc/ST-LIB_LOW/DigitalOutput2.hpp new file mode 100644 index 000000000..7dcad5b65 --- /dev/null +++ b/Inc/ST-LIB_LOW/DigitalOutput2.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "HALAL/Models/GPIO.hpp" + +using ST_LIB::GPIODomain; + +namespace ST_LIB { +struct DigitalOutputDomain { + enum class OutputMode : uint8_t { + PUSH_PULL = + static_cast(GPIODomain::OperationMode::OUTPUT_PUSHPULL), + OPEN_DRAIN = + static_cast(GPIODomain::OperationMode::OUTPUT_OPENDRAIN), + }; + struct Entry { + size_t gpio_idx; + }; + struct DigitalOutput { + GPIODomain::GPIO gpio; + using domain = DigitalOutputDomain; + + consteval DigitalOutput(const GPIODomain::Pin &pin, + OutputMode mode = OutputMode::PUSH_PULL, + GPIODomain::Pull pull = GPIODomain::Pull::None, + GPIODomain::Speed speed = GPIODomain::Speed::Low) + : gpio{pin, static_cast(mode), pull, speed} { + } + + template consteval void inscribe(Ctx &ctx) const { + const auto gpio_idx = ctx.template add(gpio.e); + Entry e{.gpio_idx = gpio_idx}; + ctx.template add(e); + } + }; + + static constexpr std::size_t max_instances{110}; + + struct Config { + size_t gpio_idx; + }; + + template + static consteval array build(span outputs) { + array cfgs{}; + + for (std::size_t i = 0; i < N; ++i) { + cfgs[i].gpio_idx = outputs[i].gpio_idx; + } + return cfgs; + } + + struct Instance { + GPIODomain::Instance *gpio_instance; + + void turn_on() { gpio_instance->turn_on(); } + + void turn_off() { gpio_instance->turn_off(); } + + void toggle() { gpio_instance->toggle(); } + }; + + template struct Init { + static inline std::array instances{}; + + static void init(std::span cfgs, + std::span gpio_instances) { + for (std::size_t i = 0; i < N; ++i) { + const auto &e = cfgs[i]; + + instances[i].gpio_instance = &gpio_instances[e.gpio_idx]; + } + } + }; +}; +} // namespace ST_LIB diff --git a/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp b/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp index 5473a9d1e..b73165c24 100644 --- a/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp +++ b/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp @@ -1,5 +1,8 @@ #pragma once +#include "ST-LIB_LOW/DigitalOutput2.hpp" +#include "ST-LIB_LOW/DigitalInput2.hpp" + #include "Clocks/Counter.hpp" #include "Clocks/Stopwatch.hpp" #include "Sensors/LinearSensor/LinearSensor.hpp" From 9dc516bd6b48a3f23821be33bce8721d605c08fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 12:11:04 +0100 Subject: [PATCH 05/76] Replaced throw by undefined function --- CMakeLists.txt | 5 +++-- Inc/HALAL/Models/GPIO.hpp | 6 ++++-- Inc/ST-LIB.hpp | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ff603b45..9ba062c27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -263,6 +263,7 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE $<$:-specs=nosys.specs> $<$:-ffunction-sections> $<$:-fdata-sections> + $<$:-fno-exceptions> -Wno-psabi @@ -271,8 +272,8 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE $<$:-Wall> $<$:-Wpedantic> $<$:-Werror> - # $<$:-Wno-gnu-zero-variadic-macro-arguments> - # $<$:-Wno-inconsistent-missing-override> + $<$:-Wno-gnu-zero-variadic-macro-arguments> + $<$:-Wno-inconsistent-missing-override> $<$:-fno-use-cxa-atexit> $<$:-fno-rtti> $<$:-Wno-address-of-packed-member> diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index 335ac3d26..c19131e37 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -11,6 +11,8 @@ using std::span; using std::tuple; namespace ST_LIB { +extern void compile_error(const char *msg); + struct GPIODomain { enum class OperationMode : uint8_t { INPUT, // GPIO_MODE_INPUT @@ -177,7 +179,7 @@ struct GPIODomain { AlternateFunction af = AlternateFunction::NO_AF) : e{pin.port, pin.pin, mode, pull, speed, af} { if (!pin.valid_af(af)) { - throw "Alternate function not valid for this pin"; + compile_error("Alternate function not valid for this pin"); } } @@ -201,7 +203,7 @@ struct GPIODomain { for (std::size_t j = 0; j < i; ++j) { const auto &prev = pins[j]; if (prev.pin == e.pin && prev.port == e.port) { - throw "GPIO already inscribed"; + compile_error("GPIO already inscribed"); } } diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index dff92504d..32fb54814 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -25,6 +25,7 @@ class STLIB { }; namespace ST_LIB { +extern void compile_error(const char *msg); template struct BuildCtx { template using Decl = typename D::Entry; template @@ -151,8 +152,7 @@ template struct Board { ...); if (!found) { - struct device_not_found_for_domain {}; - throw device_not_found_for_domain{}; + compile_error("Device not found for domain"); } return idx; From d9263feeff56bd698ecf2f54b4c35b4f6903e4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 12:11:14 +0100 Subject: [PATCH 06/76] Implemented alternate functions --- Inc/HALAL/Models/Pin.hpp | 242 ++++++++++++++++++--------------------- 1 file changed, 114 insertions(+), 128 deletions(-) diff --git a/Inc/HALAL/Models/Pin.hpp b/Inc/HALAL/Models/Pin.hpp index bc3a5331e..ad1bc45df 100644 --- a/Inc/HALAL/Models/Pin.hpp +++ b/Inc/HALAL/Models/Pin.hpp @@ -6,146 +6,132 @@ namespace ST_LIB { // Port A constexpr GPIODomain::Pin PA0{A, GPIO_PIN_0, 0b0111110111111001}; -constexpr GPIODomain::Pin PA1{A, GPIO_PIN_1}; -constexpr GPIODomain::Pin PA2{A, GPIO_PIN_2}; -constexpr GPIODomain::Pin PA3{A, GPIO_PIN_3}; -constexpr GPIODomain::Pin PA4{A, GPIO_PIN_4}; -constexpr GPIODomain::Pin PA5{A, GPIO_PIN_5}; -constexpr GPIODomain::Pin PA6{A, GPIO_PIN_6}; -constexpr GPIODomain::Pin PA7{A, GPIO_PIN_7}; -constexpr GPIODomain::Pin PA8{A, GPIO_PIN_8}; -constexpr GPIODomain::Pin PA9{A, GPIO_PIN_9}; -constexpr GPIODomain::Pin PA10{A, GPIO_PIN_10}; -constexpr GPIODomain::Pin PA11{A, GPIO_PIN_11}; -constexpr GPIODomain::Pin PA12{A, GPIO_PIN_12}; -constexpr GPIODomain::Pin PA13{A, GPIO_PIN_13}; -constexpr GPIODomain::Pin PA14{A, GPIO_PIN_14}; -constexpr GPIODomain::Pin PA15{A, GPIO_PIN_15}; +constexpr GPIODomain::Pin PA1{A, GPIO_PIN_1, 0b0111100111111011}; +constexpr GPIODomain::Pin PA2{A, GPIO_PIN_2, 0b0111101110011011}; +constexpr GPIODomain::Pin PA3{A, GPIO_PIN_3, 0b0111111101111011}; +constexpr GPIODomain::Pin PA4{A, GPIO_PIN_4, 0b1010011110001111}; +constexpr GPIODomain::Pin PA5{A, GPIO_PIN_5, 0b1101010010101111}; +constexpr GPIODomain::Pin PA6{A, GPIO_PIN_6, 0b0111011011111111}; +constexpr GPIODomain::Pin PA7{A, GPIO_PIN_7, 0b0111010011111011}; +constexpr GPIODomain::Pin PA8{A, GPIO_PIN_8, 0b1101101100111111}; +constexpr GPIODomain::Pin PA9{A, GPIO_PIN_9, 0b0101111100010111}; +constexpr GPIODomain::Pin PA10{A, GPIO_PIN_10, 0b0101110100010111}; +constexpr GPIODomain::Pin PA11{A, GPIO_PIN_11, 0b0101111110010011}; +constexpr GPIODomain::Pin PA12{A, GPIO_PIN_12, 0b0011111110010111}; +constexpr GPIODomain::Pin PA13{A, GPIO_PIN_13, 0b1000000000000001}; +constexpr GPIODomain::Pin PA14{A, GPIO_PIN_14, 0b1000000000000001}; +constexpr GPIODomain::Pin PA15{A, GPIO_PIN_15, 0b0111010111111011}; // Port B -constexpr GPIODomain::Pin PB0{B, GPIO_PIN_0}; -constexpr GPIODomain::Pin PB1{B, GPIO_PIN_1}; -constexpr GPIODomain::Pin PB2{B, GPIO_PIN_2}; -constexpr GPIODomain::Pin PB3{B, GPIO_PIN_3}; -constexpr GPIODomain::Pin PB4{B, GPIO_PIN_4}; -constexpr GPIODomain::Pin PB5{B, GPIO_PIN_5}; -constexpr GPIODomain::Pin PB6{B, GPIO_PIN_6}; -constexpr GPIODomain::Pin PB7{B, GPIO_PIN_7}; -constexpr GPIODomain::Pin PB8{B, GPIO_PIN_8}; -constexpr GPIODomain::Pin PB9{B, GPIO_PIN_9}; -constexpr GPIODomain::Pin PB10{B, GPIO_PIN_10}; -constexpr GPIODomain::Pin PB11{B, GPIO_PIN_11}; -constexpr GPIODomain::Pin PB12{B, GPIO_PIN_12}; -constexpr GPIODomain::Pin PB13{B, GPIO_PIN_13}; -constexpr GPIODomain::Pin PB14{B, GPIO_PIN_14}; -constexpr GPIODomain::Pin PB15{B, GPIO_PIN_15}; +constexpr GPIODomain::Pin PB0{B, GPIO_PIN_0, 0b0111110011111011}; +constexpr GPIODomain::Pin PB1{B, GPIO_PIN_1, 0b0111110011111011}; +constexpr GPIODomain::Pin PB2{B, GPIO_PIN_2, 0b0110111110111011}; +constexpr GPIODomain::Pin PB3{B, GPIO_PIN_3, 0b0111110110111011}; +constexpr GPIODomain::Pin PB4{B, GPIO_PIN_4, 0b0111111110110011}; +constexpr GPIODomain::Pin PB5{B, GPIO_PIN_5, 0b0111110111111111}; +constexpr GPIODomain::Pin PB6{B, GPIO_PIN_6, 0b0111110111111111}; +constexpr GPIODomain::Pin PB7{B, GPIO_PIN_7, 0b0111110111111011}; +constexpr GPIODomain::Pin PB8{B, GPIO_PIN_8, 0b0110111111111111}; +constexpr GPIODomain::Pin PB9{B, GPIO_PIN_9, 0b0110111111111111}; +constexpr GPIODomain::Pin PB10{B, GPIO_PIN_10, 0b0111110111111111}; +constexpr GPIODomain::Pin PB11{B, GPIO_PIN_11, 0b0111110111111011}; +constexpr GPIODomain::Pin PB12{B, GPIO_PIN_12, 0b0111110111111011}; +constexpr GPIODomain::Pin PB13{B, GPIO_PIN_13, 0b0111110111111011}; +constexpr GPIODomain::Pin PB14{B, GPIO_PIN_14, 0b0111110011111011}; +constexpr GPIODomain::Pin PB15{B, GPIO_PIN_15, 0b0111110011111011}; // Port C -constexpr GPIODomain::Pin PC0{C, GPIO_PIN_0}; -constexpr GPIODomain::Pin PC1{C, GPIO_PIN_1}; -constexpr GPIODomain::Pin PC2{C, GPIO_PIN_2}; -constexpr GPIODomain::Pin PC3{C, GPIO_PIN_3}; -constexpr GPIODomain::Pin PC4{C, GPIO_PIN_4}; -constexpr GPIODomain::Pin PC5{C, GPIO_PIN_5}; -constexpr GPIODomain::Pin PC6{C, GPIO_PIN_6}; -constexpr GPIODomain::Pin PC7{C, GPIO_PIN_7}; -constexpr GPIODomain::Pin PC8{C, GPIO_PIN_8}; -constexpr GPIODomain::Pin PC9{C, GPIO_PIN_9}; -constexpr GPIODomain::Pin PC10{C, GPIO_PIN_10}; -constexpr GPIODomain::Pin PC11{C, GPIO_PIN_11}; -constexpr GPIODomain::Pin PC12{C, GPIO_PIN_12}; -constexpr GPIODomain::Pin PC13{C, GPIO_PIN_13}; -constexpr GPIODomain::Pin PC14{C, GPIO_PIN_14}; -constexpr GPIODomain::Pin PC15{C, GPIO_PIN_15}; +constexpr GPIODomain::Pin PC0{C, GPIO_PIN_0, 0b0110110110110011}; +constexpr GPIODomain::Pin PC1{C, GPIO_PIN_1, 0b0110111111111111}; +constexpr GPIODomain::Pin PC2{C, GPIO_PIN_2, 0b0110111110110011}; +constexpr GPIODomain::Pin PC3{C, GPIO_PIN_3, 0b0110111110110011}; +constexpr GPIODomain::Pin PC4{C, GPIO_PIN_4, 0b0110110110111011}; +constexpr GPIODomain::Pin PC5{C, GPIO_PIN_5, 0b0110110110111111}; +constexpr GPIODomain::Pin PC6{C, GPIO_PIN_6, 0b0111110011111111}; +constexpr GPIODomain::Pin PC7{C, GPIO_PIN_7, 0b0111110011111111}; +constexpr GPIODomain::Pin PC8{C, GPIO_PIN_8, 0b0111110011011111}; +constexpr GPIODomain::Pin PC9{C, GPIO_PIN_9, 0b0111110110111111}; +constexpr GPIODomain::Pin PC10{C, GPIO_PIN_10, 0b0110111111111111}; +constexpr GPIODomain::Pin PC11{C, GPIO_PIN_11, 0b0110111111111111}; +constexpr GPIODomain::Pin PC12{C, GPIO_PIN_12, 0b0110111111011111}; +constexpr GPIODomain::Pin PC13{C, GPIO_PIN_13, 0b1000000000000001}; +constexpr GPIODomain::Pin PC14{C, GPIO_PIN_14, 0b1000000000000001}; +constexpr GPIODomain::Pin PC15{C, GPIO_PIN_15, 0b1000000000000001}; // Port D -constexpr GPIODomain::Pin PD0{D, GPIO_PIN_0}; -constexpr GPIODomain::Pin PD1{D, GPIO_PIN_1}; -constexpr GPIODomain::Pin PD2{D, GPIO_PIN_2}; -constexpr GPIODomain::Pin PD3{D, GPIO_PIN_3}; -constexpr GPIODomain::Pin PD4{D, GPIO_PIN_4}; -constexpr GPIODomain::Pin PD5{D, GPIO_PIN_5}; -constexpr GPIODomain::Pin PD6{D, GPIO_PIN_6}; -constexpr GPIODomain::Pin PD7{D, GPIO_PIN_7}; -constexpr GPIODomain::Pin PD8{D, GPIO_PIN_8}; -constexpr GPIODomain::Pin PD9{D, GPIO_PIN_9}; -constexpr GPIODomain::Pin PD10{D, GPIO_PIN_10}; -constexpr GPIODomain::Pin PD11{D, GPIO_PIN_11}; -constexpr GPIODomain::Pin PD12{D, GPIO_PIN_12}; -constexpr GPIODomain::Pin PD13{D, GPIO_PIN_13}; -constexpr GPIODomain::Pin PD14{D, GPIO_PIN_14}; -constexpr GPIODomain::Pin PD15{D, GPIO_PIN_15}; +constexpr GPIODomain::Pin PD0{D, GPIO_PIN_0, 0b0111110110011011}; +constexpr GPIODomain::Pin PD1{D, GPIO_PIN_1, 0b0111110110011011}; +constexpr GPIODomain::Pin PD2{D, GPIO_PIN_2, 0b1110110110011011}; +constexpr GPIODomain::Pin PD3{D, GPIO_PIN_3, 0b0110110111110011}; +constexpr GPIODomain::Pin PD4{D, GPIO_PIN_4, 0b0010110010010011}; +constexpr GPIODomain::Pin PD5{D, GPIO_PIN_5, 0b0010110010010011}; +constexpr GPIODomain::Pin PD6{D, GPIO_PIN_6, 0b0111110110111011}; +constexpr GPIODomain::Pin PD7{D, GPIO_PIN_7, 0b0110110111111011}; +constexpr GPIODomain::Pin PD8{D, GPIO_PIN_8, 0b0110110110010011}; +constexpr GPIODomain::Pin PD9{D, GPIO_PIN_9, 0b0110110110010011}; +constexpr GPIODomain::Pin PD10{D, GPIO_PIN_10, 0b0110110110010011}; +constexpr GPIODomain::Pin PD11{D, GPIO_PIN_11, 0b0111100110110011}; +constexpr GPIODomain::Pin PD12{D, GPIO_PIN_12, 0b0111110110110011}; +constexpr GPIODomain::Pin PD13{D, GPIO_PIN_13, 0b0111110110110011}; +constexpr GPIODomain::Pin PD14{D, GPIO_PIN_14, 0b0111010010010011}; +constexpr GPIODomain::Pin PD15{D, GPIO_PIN_15, 0b0111010010010011}; // Port E -constexpr GPIODomain::Pin PE0{E, GPIO_PIN_0}; -constexpr GPIODomain::Pin PE1{E, GPIO_PIN_1}; -constexpr GPIODomain::Pin PE2{E, GPIO_PIN_2}; -constexpr GPIODomain::Pin PE3{E, GPIO_PIN_3}; -constexpr GPIODomain::Pin PE4{E, GPIO_PIN_4}; -constexpr GPIODomain::Pin PE5{E, GPIO_PIN_5}; -constexpr GPIODomain::Pin PE6{E, GPIO_PIN_6}; -constexpr GPIODomain::Pin PE7{E, GPIO_PIN_7}; -constexpr GPIODomain::Pin PE8{E, GPIO_PIN_8}; -constexpr GPIODomain::Pin PE9{E, GPIO_PIN_9}; -constexpr GPIODomain::Pin PE10{E, GPIO_PIN_10}; -constexpr GPIODomain::Pin PE11{E, GPIO_PIN_11}; -constexpr GPIODomain::Pin PE12{E, GPIO_PIN_12}; -constexpr GPIODomain::Pin PE13{E, GPIO_PIN_13}; -constexpr GPIODomain::Pin PE14{E, GPIO_PIN_14}; -constexpr GPIODomain::Pin PE15{E, GPIO_PIN_15}; +constexpr GPIODomain::Pin PE0{E, GPIO_PIN_0, 0b0111110010110011}; +constexpr GPIODomain::Pin PE1{E, GPIO_PIN_1, 0b0111110010011011}; +constexpr GPIODomain::Pin PE2{E, GPIO_PIN_2, 0b0110110111110011}; +constexpr GPIODomain::Pin PE3{E, GPIO_PIN_3, 0b0110110111110011}; +constexpr GPIODomain::Pin PE4{E, GPIO_PIN_4, 0b0110110111111111}; +constexpr GPIODomain::Pin PE5{E, GPIO_PIN_5, 0b0110110111111011}; +constexpr GPIODomain::Pin PE6{E, GPIO_PIN_6, 0b0110110111111111}; +constexpr GPIODomain::Pin PE7{E, GPIO_PIN_7, 0b0111110010010011}; +constexpr GPIODomain::Pin PE8{E, GPIO_PIN_8, 0b0111110010010011}; +constexpr GPIODomain::Pin PE9{E, GPIO_PIN_9, 0b0111110010010011}; +constexpr GPIODomain::Pin PE10{E, GPIO_PIN_10, 0b0111110010010011}; +constexpr GPIODomain::Pin PE11{E, GPIO_PIN_11, 0b0111110010011011}; +constexpr GPIODomain::Pin PE12{E, GPIO_PIN_12, 0b0111110010011011}; +constexpr GPIODomain::Pin PE13{E, GPIO_PIN_13, 0b0111110010011011}; +constexpr GPIODomain::Pin PE14{E, GPIO_PIN_14, 0b0011110010010011}; +constexpr GPIODomain::Pin PE15{E, GPIO_PIN_15, 0b0110110010010011}; // Port F -constexpr GPIODomain::Pin PF0{F, GPIO_PIN_0}; -constexpr GPIODomain::Pin PF1{F, GPIO_PIN_1}; -constexpr GPIODomain::Pin PF2{F, GPIO_PIN_2}; -constexpr GPIODomain::Pin PF3{F, GPIO_PIN_3}; -constexpr GPIODomain::Pin PF4{F, GPIO_PIN_4}; -constexpr GPIODomain::Pin PF5{F, GPIO_PIN_5}; -constexpr GPIODomain::Pin PF6{F, GPIO_PIN_6}; -constexpr GPIODomain::Pin PF7{F, GPIO_PIN_7}; -constexpr GPIODomain::Pin PF8{F, GPIO_PIN_8}; -constexpr GPIODomain::Pin PF9{F, GPIO_PIN_9}; -constexpr GPIODomain::Pin PF10{F, GPIO_PIN_10}; -constexpr GPIODomain::Pin PF11{F, GPIO_PIN_11}; -constexpr GPIODomain::Pin PF12{F, GPIO_PIN_12}; -constexpr GPIODomain::Pin PF13{F, GPIO_PIN_13}; -constexpr GPIODomain::Pin PF14{F, GPIO_PIN_14}; -constexpr GPIODomain::Pin PF15{F, GPIO_PIN_15}; +constexpr GPIODomain::Pin PF0{F, GPIO_PIN_0, 0b0010110010010011}; +constexpr GPIODomain::Pin PF1{F, GPIO_PIN_1, 0b0010110010010011}; +constexpr GPIODomain::Pin PF2{F, GPIO_PIN_2, 0b0010110010010011}; +constexpr GPIODomain::Pin PF3{F, GPIO_PIN_3, 0b0010010010010011}; +constexpr GPIODomain::Pin PF4{F, GPIO_PIN_4, 0b0010010010010011}; +constexpr GPIODomain::Pin PF5{F, GPIO_PIN_5, 0b0010010010010011}; +constexpr GPIODomain::Pin PF6{F, GPIO_PIN_6, 0b0111110010110011}; +constexpr GPIODomain::Pin PF7{F, GPIO_PIN_7, 0b0111110010110011}; +constexpr GPIODomain::Pin PF8{F, GPIO_PIN_8, 0b0111110010111011}; +constexpr GPIODomain::Pin PF9{F, GPIO_PIN_9, 0b0111110010111011}; +constexpr GPIODomain::Pin PF10{F, GPIO_PIN_10, 0b0110110010110011}; +constexpr GPIODomain::Pin PF11{F, GPIO_PIN_11, 0b0010110010010011}; +constexpr GPIODomain::Pin PF12{F, GPIO_PIN_12, 0b0010010010010011}; +constexpr GPIODomain::Pin PF13{F, GPIO_PIN_13, 0b0110110010110011}; +constexpr GPIODomain::Pin PF14{F, GPIO_PIN_14, 0b0110110010110011}; +constexpr GPIODomain::Pin PF15{F, GPIO_PIN_15, 0b0010110010010011}; // Port G -constexpr GPIODomain::Pin PG0{G, GPIO_PIN_0}; -constexpr GPIODomain::Pin PG1{G, GPIO_PIN_1}; -constexpr GPIODomain::Pin PG2{G, GPIO_PIN_2}; -constexpr GPIODomain::Pin PG3{G, GPIO_PIN_3}; -constexpr GPIODomain::Pin PG4{G, GPIO_PIN_4}; -constexpr GPIODomain::Pin PG5{G, GPIO_PIN_5}; -constexpr GPIODomain::Pin PG6{G, GPIO_PIN_6}; -constexpr GPIODomain::Pin PG7{G, GPIO_PIN_7}; -constexpr GPIODomain::Pin PG8{G, GPIO_PIN_8}; -constexpr GPIODomain::Pin PG9{G, GPIO_PIN_9}; -constexpr GPIODomain::Pin PG10{G, GPIO_PIN_10}; -constexpr GPIODomain::Pin PG11{G, GPIO_PIN_11}; -constexpr GPIODomain::Pin PG12{G, GPIO_PIN_12}; -constexpr GPIODomain::Pin PG13{G, GPIO_PIN_13}; -constexpr GPIODomain::Pin PG14{G, GPIO_PIN_14}; -constexpr GPIODomain::Pin PG15{G, GPIO_PIN_15}; +constexpr GPIODomain::Pin PG0{G, GPIO_PIN_0, 0b0010010010010011}; +constexpr GPIODomain::Pin PG1{G, GPIO_PIN_1, 0b0010010010010011}; +constexpr GPIODomain::Pin PG2{G, GPIO_PIN_2, 0b0110010010010011}; +constexpr GPIODomain::Pin PG3{G, GPIO_PIN_3, 0b0110010010010011}; +constexpr GPIODomain::Pin PG4{G, GPIO_PIN_4, 0b0110010010010011}; +constexpr GPIODomain::Pin PG5{G, GPIO_PIN_5, 0b0010010010010011}; +constexpr GPIODomain::Pin PG6{G, GPIO_PIN_6, 0b0111110010110011}; +constexpr GPIODomain::Pin PG7{G, GPIO_PIN_7, 0b0110110010110011}; +constexpr GPIODomain::Pin PG8{G, GPIO_PIN_8, 0b0111110010110011}; +constexpr GPIODomain::Pin PG9{G, GPIO_PIN_9, 0b0110110110110011}; +constexpr GPIODomain::Pin PG10{G, GPIO_PIN_10, 0b0110110110111011}; +constexpr GPIODomain::Pin PG11{G, GPIO_PIN_11, 0b0110110110111011}; +constexpr GPIODomain::Pin PG12{G, GPIO_PIN_12, 0b0111110110111111}; +constexpr GPIODomain::Pin PG13{G, GPIO_PIN_13, 0b0111110110111111}; +constexpr GPIODomain::Pin PG14{G, GPIO_PIN_14, 0b0111110110011111}; +constexpr GPIODomain::Pin PG15{G, GPIO_PIN_15, 0b0110110010010011}; // Port H -constexpr GPIODomain::Pin PH0{H, GPIO_PIN_0}; -constexpr GPIODomain::Pin PH1{H, GPIO_PIN_1}; -constexpr GPIODomain::Pin PH2{H, GPIO_PIN_2}; -constexpr GPIODomain::Pin PH3{H, GPIO_PIN_3}; -constexpr GPIODomain::Pin PH4{H, GPIO_PIN_4}; -constexpr GPIODomain::Pin PH5{H, GPIO_PIN_5}; -constexpr GPIODomain::Pin PH6{H, GPIO_PIN_6}; -constexpr GPIODomain::Pin PH7{H, GPIO_PIN_7}; -constexpr GPIODomain::Pin PH8{H, GPIO_PIN_8}; -constexpr GPIODomain::Pin PH9{H, GPIO_PIN_9}; -constexpr GPIODomain::Pin PH10{H, GPIO_PIN_10}; -constexpr GPIODomain::Pin PH11{H, GPIO_PIN_11}; -constexpr GPIODomain::Pin PH12{H, GPIO_PIN_12}; -constexpr GPIODomain::Pin PH13{H, GPIO_PIN_13}; -constexpr GPIODomain::Pin PH14{H, GPIO_PIN_14}; -constexpr GPIODomain::Pin PH15{H, GPIO_PIN_15}; +constexpr GPIODomain::Pin PH0{H, GPIO_PIN_0, 0b1000000000000001}; +constexpr GPIODomain::Pin PH1{H, GPIO_PIN_1, 0b1000000000000001}; -} // namespace ST_LIB \ No newline at end of file +} // namespace ST_LIB From 4cd2796f8c2ba0a448769da28d331dba45b6ca22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 12:41:27 +0100 Subject: [PATCH 07/76] Added linker script and startup code, and fixed using hal template conf --- .cproject | 1012 ----------------- .mxproject | 12 - .project | 32 - CMakeLists.txt | 16 + ...l_conf.h => stm32h7xx_hal_conf_template.h} | 2 +- STM32H723ZGTX_FLASH.ld | 209 ++++ STM32H723ZGTX_RAM.ld | 173 +++ setup.env | 1 - startup_stm32h723zgtx.s | 756 ++++++++++++ 9 files changed, 1155 insertions(+), 1058 deletions(-) delete mode 100644 .cproject delete mode 100644 .mxproject delete mode 100644 .project rename Inc/{stm32h7xx_hal_conf.h => stm32h7xx_hal_conf_template.h} (99%) create mode 100644 STM32H723ZGTX_FLASH.ld create mode 100644 STM32H723ZGTX_RAM.ld delete mode 100644 setup.env create mode 100644 startup_stm32h723zgtx.s diff --git a/.cproject b/.cproject deleted file mode 100644 index ff4c420e3..000000000 --- a/.cproject +++ /dev/null @@ -1,1012 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.mxproject b/.mxproject deleted file mode 100644 index d59c167e7..000000000 --- a/.mxproject +++ /dev/null @@ -1,12 +0,0 @@ -[PreviousGenFiles] -SourcePath=..\Src -SourceFiles=ST-LIB.c; - -[PreviousLibFiles] -LibFiles=Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h723xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Include\system_stm32h7xx.h;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Drivers\CMSIS\Include\cmsis_armcc.h;Drivers\CMSIS\Include\cmsis_armclang.h;Drivers\CMSIS\Include\cmsis_armclang_ltm.h;Drivers\CMSIS\Include\cmsis_compiler.h;Drivers\CMSIS\Include\cmsis_gcc.h;Drivers\CMSIS\Include\cmsis_iccarm.h;Drivers\CMSIS\Include\cmsis_version.h;Drivers\CMSIS\Include\core_armv81mml.h;Drivers\CMSIS\Include\core_armv8mbl.h;Drivers\CMSIS\Include\core_armv8mml.h;Drivers\CMSIS\Include\core_cm0.h;Drivers\CMSIS\Include\core_cm0plus.h;Drivers\CMSIS\Include\core_cm1.h;Drivers\CMSIS\Include\core_cm23.h;Drivers\CMSIS\Include\core_cm3.h;Drivers\CMSIS\Include\core_cm33.h;Drivers\CMSIS\Include\core_cm35p.h;Drivers\CMSIS\Include\core_cm4.h;Drivers\CMSIS\Include\core_cm7.h;Drivers\CMSIS\Include\core_sc000.h;Drivers\CMSIS\Include\core_sc300.h;Drivers\CMSIS\Include\mpu_armv7.h;Drivers\CMSIS\Include\mpu_armv8.h;Drivers\CMSIS\Include\tz_context.h; - -[PreviousUsedCubeIDEFiles] -SourceFiles=Src\ST-LIB.c;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Src\stm32h7xx_hal_conf_template.h;Drivers\CMSIS\Device\ST\STM32H7xx\Source\Templates\system_stm32h7xx.c;Src\stm32h7xx_hal_conf_template.h;;; -HeaderPath=Drivers\CMSIS\Device\ST\STM32H7xx\Include;Drivers\CMSIS\Include;Inc;Drivers\STM32H7xx_HAL_Driver\Inc;Drivers\STM32H7xx_HAL_Driver\Inc\Legacy; -CDefines=USE_HAL_DRIVER;STM32H723xx;USE_HAL_DRIVER;USE_HAL_DRIVER; - diff --git a/.project b/.project deleted file mode 100644 index 32ef24281..000000000 --- a/.project +++ /dev/null @@ -1,32 +0,0 @@ - - - ST-LIB - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - com.st.stm32cube.ide.mcu.MCUProjectNature - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature - com.st.stm32cube.ide.mcu.MCUCubeProjectNature - com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature - com.st.stm32cube.ide.mcu.MCURootProjectNature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ba062c27..f956d7aba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,6 +313,22 @@ target_include_directories(${STLIB_LIBRARY} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Inc/ST-LIB_HIGH ) +if(PROJECT_IS_TOP_LEVEL) + configure_file( + ${CMAKE_CURRENT_LIST_DIR}/Inc/stm32h7xx_hal_conf_template.h + ${CMAKE_CURRENT_BINARY_DIR}/stm32h7xx_hal_conf.h + COPYONLY + ) + + target_include_directories(${STLIB_LIBRARY} PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + ) +else() + target_include_directories(${STLIB_LIBRARY} PUBLIC + ${CMAKE_SOURCE_DIR}/Core/Inc + ) +endif() + if(PROJECT_IS_TOP_LEVEL) execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink diff --git a/Inc/stm32h7xx_hal_conf.h b/Inc/stm32h7xx_hal_conf_template.h similarity index 99% rename from Inc/stm32h7xx_hal_conf.h rename to Inc/stm32h7xx_hal_conf_template.h index 74fdc0c32..4f41c7d25 100644 --- a/Inc/stm32h7xx_hal_conf.h +++ b/Inc/stm32h7xx_hal_conf_template.h @@ -233,7 +233,7 @@ * @brief Uncomment the line below to expanse the "assert_param" macro in the * HAL drivers code */ -#define USE_FULL_ASSERT 1 +/* #define USE_FULL_ASSERT 1U */ /* Includes ------------------------------------------------------------------*/ diff --git a/STM32H723ZGTX_FLASH.ld b/STM32H723ZGTX_FLASH.ld new file mode 100644 index 000000000..12b8d7793 --- /dev/null +++ b/STM32H723ZGTX_FLASH.ld @@ -0,0 +1,209 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld +** +** Author : STM32CubeIDE +** +** Abstract : Linker script for STM32H7 series +** 1024Kbytes FLASH and 560Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2022 STMicroelectronics. +** All rights reserved. +** +** This software is licensed under terms that can be found in the LICENSE file +** in the root directory of this software component. +** If no LICENSE file comes with this software, it is provided AS-IS. +** +**************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ + ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K + DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K-128K + RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 320K + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 32K + RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 16K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab (READONLY): { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM (READONLY): { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array (READONLY): + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + + .init_array (READONLY): + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + + .fini_array (READONLY): + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM_D1 AT> FLASH + /* + this needs to be the last thing in FLASH + because the preceeding sections are appended after the one preceeding them + this is, if this were the first thing in FLASH + the sections below it would try to be placed afterwards + thus overflowing the FLASH + */ + .metadata_pool : + { + . = ABSOLUTE(0x080DFD00); + . = ALIGN(4); + metadata = .; + KEEP(*(.metadata_pool)) + . += 0x100; + } >FLASH + /* Uninitialized data section */ + . = ALIGN(4); + .bss (NOLOAD) : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + /* ETH_CODE: add placement of RX buffer. STM32H72x/H73x has small D2 RAM, so we need to put it there. + * (NOLOAD) attribute used for .bss section to avoid linker warning (.bss initialized by startup code) + */ + . = ALIGN(32); + *(.Rx_PoolSection) + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM_D1 + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM_D1 + + /* ETH_CODE: add placement of DMA descriptors, rest is used by RX_POOL */ + .lwip_sec (NOLOAD) : + { + . = ABSOLUTE(0x30000000); + *(.RxDecripSection) + + . = ABSOLUTE(0x30000100); + *(.TxDecripSection) + + } >RAM_D2 + .stlib_no_cache_ram_pool : + { + . = ABSOLUTE(0x38000000); + _no_cached_ram_start = .; + + } >RAM_D3 + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/STM32H723ZGTX_RAM.ld b/STM32H723ZGTX_RAM.ld new file mode 100644 index 000000000..4d2e09c43 --- /dev/null +++ b/STM32H723ZGTX_RAM.ld @@ -0,0 +1,173 @@ +/* +****************************************************************************** +** +** File : LinkerScript.ld (debug in RAM dedicated) +** +** Author : STM32CubeIDE +** +** Abstract : Linker script for STM32H7 series +** 320Kbytes RAM_EXEC and 240Kbytes RAM +** +** Set heap size, stack size and stack location according +** to application requirements. +** +** Set memory bank area and size if external memory is used. +** +** Target : STMicroelectronics STM32 +** +** Distribution: The file is distributed as is, without any warranty +** of any kind. +** +***************************************************************************** +** @attention +** +** Copyright (c) 2022 STMicroelectronics. +** All rights reserved. +** +** This software is licensed under terms that can be found in the LICENSE file +** in the root directory of this software component. +** If no LICENSE file comes with this software, it is provided AS-IS. +** +**************************************************************************** +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = ORIGIN(DTCMRAM) + LENGTH(DTCMRAM); /* end of RAM */ +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200 ; /* required amount of heap */ +_Min_Stack_Size = 0x400 ; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ + RAM_EXEC (xrw) : ORIGIN = 0x24000000, LENGTH = 320K + DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K + ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K + RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 32K + RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 16K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into RAM_EXEC */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >RAM_EXEC + + /* The program code and other data goes into RAM_EXEC */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + *(.RamFunc) /* .RamFunc sections */ + *(.RamFunc*) /* .RamFunc* sections */ + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >RAM_EXEC + + /* Constant data goes into RAM_EXEC */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >RAM_EXEC + + .ARM.extab (READONLY): { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM_EXEC + .ARM (READONLY): { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >RAM_EXEC + + .preinit_array (READONLY): + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >RAM_EXEC + + .init_array (READONLY): + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >RAM_EXEC + + .fini_array (READONLY): + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >RAM_EXEC + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >DTCMRAM AT> RAM_EXEC + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >DTCMRAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >DTCMRAM + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/setup.env b/setup.env deleted file mode 100644 index 6d1022f4f..000000000 --- a/setup.env +++ /dev/null @@ -1 +0,0 @@ -export STLIB_PATH=$PWD \ No newline at end of file diff --git a/startup_stm32h723zgtx.s b/startup_stm32h723zgtx.s new file mode 100644 index 000000000..73d8bd295 --- /dev/null +++ b/startup_stm32h723zgtx.s @@ -0,0 +1,756 @@ +/** + ****************************************************************************** + * @file startup_stm32h723xx.s + * @author MCD Application Team + * @brief STM32H723xx Devices vector table for GCC based toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * @attention + * + * Copyright (c) 2019 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m7 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss +/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ + +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr sp, =_estack /* set stack pointer */ + +/* Call the clock system initialization function.*/ + bl SystemInit + +/* Copy the data segment initializers from flash to SRAM */ + ldr r0, =_sdata + ldr r1, =_edata + ldr r2, =_sidata + movs r3, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r4, [r2, r3] + str r4, [r0, r3] + adds r3, r3, #4 + +LoopCopyDataInit: + adds r4, r0, r3 + cmp r4, r1 + bcc CopyDataInit +/* Zero fill the bss segment. */ + ldr r2, =_sbss + ldr r4, =_ebss + movs r3, #0 + b LoopFillZerobss + +FillZerobss: + str r3, [r2] + adds r2, r2, #4 + +LoopFillZerobss: + cmp r2, r4 + bcc FillZerobss + +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * @param None + * @retval None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +*******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + .word _estack + .word Reset_Handler + + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + + /* External Interrupts */ + .word WWDG_IRQHandler /* Window WatchDog */ + .word PVD_AVD_IRQHandler /* PVD/AVD through EXTI Line detection */ + .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ + .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ + .word FLASH_IRQHandler /* FLASH */ + .word RCC_IRQHandler /* RCC */ + .word EXTI0_IRQHandler /* EXTI Line0 */ + .word EXTI1_IRQHandler /* EXTI Line1 */ + .word EXTI2_IRQHandler /* EXTI Line2 */ + .word EXTI3_IRQHandler /* EXTI Line3 */ + .word EXTI4_IRQHandler /* EXTI Line4 */ + .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ + .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ + .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ + .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ + .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ + .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ + .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ + .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ + .word FDCAN1_IT0_IRQHandler /* FDCAN1 interrupt line 0 */ + .word FDCAN2_IT0_IRQHandler /* FDCAN2 interrupt line 0 */ + .word FDCAN1_IT1_IRQHandler /* FDCAN1 interrupt line 1 */ + .word FDCAN2_IT1_IRQHandler /* FDCAN2 interrupt line 1 */ + .word EXTI9_5_IRQHandler /* External Line[9:5]s */ + .word TIM1_BRK_IRQHandler /* TIM1 Break interrupt */ + .word TIM1_UP_IRQHandler /* TIM1 Update interrupt */ + .word TIM1_TRG_COM_IRQHandler /* TIM1 Trigger and Commutation interrupt */ + .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .word TIM2_IRQHandler /* TIM2 */ + .word TIM3_IRQHandler /* TIM3 */ + .word TIM4_IRQHandler /* TIM4 */ + .word I2C1_EV_IRQHandler /* I2C1 Event */ + .word I2C1_ER_IRQHandler /* I2C1 Error */ + .word I2C2_EV_IRQHandler /* I2C2 Event */ + .word I2C2_ER_IRQHandler /* I2C2 Error */ + .word SPI1_IRQHandler /* SPI1 */ + .word SPI2_IRQHandler /* SPI2 */ + .word USART1_IRQHandler /* USART1 */ + .word USART2_IRQHandler /* USART2 */ + .word USART3_IRQHandler /* USART3 */ + .word EXTI15_10_IRQHandler /* External Line[15:10]s */ + .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ + .word 0 /* Reserved */ + .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ + .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ + .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ + .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ + .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ + .word FMC_IRQHandler /* FMC */ + .word SDMMC1_IRQHandler /* SDMMC1 */ + .word TIM5_IRQHandler /* TIM5 */ + .word SPI3_IRQHandler /* SPI3 */ + .word UART4_IRQHandler /* UART4 */ + .word UART5_IRQHandler /* UART5 */ + .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ + .word TIM7_IRQHandler /* TIM7 */ + .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ + .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ + .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ + .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ + .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ + .word ETH_IRQHandler /* Ethernet */ + .word ETH_WKUP_IRQHandler /* Ethernet Wakeup through EXTI line */ + .word FDCAN_CAL_IRQHandler /* FDCAN calibration unit interrupt*/ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ + .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ + .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ + .word USART6_IRQHandler /* USART6 */ + .word I2C3_EV_IRQHandler /* I2C3 event */ + .word I2C3_ER_IRQHandler /* I2C3 error */ + .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ + .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ + .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ + .word OTG_HS_IRQHandler /* USB OTG HS */ + .word DCMI_PSSI_IRQHandler /* DCMI, PSSI */ + .word 0 /* Reserved */ + .word RNG_IRQHandler /* Rng */ + .word FPU_IRQHandler /* FPU */ + .word UART7_IRQHandler /* UART7 */ + .word UART8_IRQHandler /* UART8 */ + .word SPI4_IRQHandler /* SPI4 */ + .word SPI5_IRQHandler /* SPI5 */ + .word SPI6_IRQHandler /* SPI6 */ + .word SAI1_IRQHandler /* SAI1 */ + .word LTDC_IRQHandler /* LTDC */ + .word LTDC_ER_IRQHandler /* LTDC error */ + .word DMA2D_IRQHandler /* DMA2D */ + .word 0 /* Reserved */ + .word OCTOSPI1_IRQHandler /* OCTOSPI1 */ + .word LPTIM1_IRQHandler /* LPTIM1 */ + .word CEC_IRQHandler /* HDMI_CEC */ + .word I2C4_EV_IRQHandler /* I2C4 Event */ + .word I2C4_ER_IRQHandler /* I2C4 Error */ + .word SPDIF_RX_IRQHandler /* SPDIF_RX */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DMAMUX1_OVR_IRQHandler /* DMAMUX1 Overrun interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word DFSDM1_FLT0_IRQHandler /* DFSDM Filter0 Interrupt */ + .word DFSDM1_FLT1_IRQHandler /* DFSDM Filter1 Interrupt */ + .word DFSDM1_FLT2_IRQHandler /* DFSDM Filter2 Interrupt */ + .word DFSDM1_FLT3_IRQHandler /* DFSDM Filter3 Interrupt */ + .word 0 /* Reserved */ + .word SWPMI1_IRQHandler /* Serial Wire Interface 1 global interrupt */ + .word TIM15_IRQHandler /* TIM15 global Interrupt */ + .word TIM16_IRQHandler /* TIM16 global Interrupt */ + .word TIM17_IRQHandler /* TIM17 global Interrupt */ + .word MDIOS_WKUP_IRQHandler /* MDIOS Wakeup Interrupt */ + .word MDIOS_IRQHandler /* MDIOS global Interrupt */ + .word 0 /* Reserved */ + .word MDMA_IRQHandler /* MDMA global Interrupt */ + .word 0 /* Reserved */ + .word SDMMC2_IRQHandler /* SDMMC2 global Interrupt */ + .word HSEM1_IRQHandler /* HSEM1 global Interrupt */ + .word 0 /* Reserved */ + .word ADC3_IRQHandler /* ADC3 global Interrupt */ + .word DMAMUX2_OVR_IRQHandler /* DMAMUX Overrun interrupt */ + .word BDMA_Channel0_IRQHandler /* BDMA Channel 0 global Interrupt */ + .word BDMA_Channel1_IRQHandler /* BDMA Channel 1 global Interrupt */ + .word BDMA_Channel2_IRQHandler /* BDMA Channel 2 global Interrupt */ + .word BDMA_Channel3_IRQHandler /* BDMA Channel 3 global Interrupt */ + .word BDMA_Channel4_IRQHandler /* BDMA Channel 4 global Interrupt */ + .word BDMA_Channel5_IRQHandler /* BDMA Channel 5 global Interrupt */ + .word BDMA_Channel6_IRQHandler /* BDMA Channel 6 global Interrupt */ + .word BDMA_Channel7_IRQHandler /* BDMA Channel 7 global Interrupt */ + .word COMP1_IRQHandler /* COMP1 global Interrupt */ + .word LPTIM2_IRQHandler /* LP TIM2 global interrupt */ + .word LPTIM3_IRQHandler /* LP TIM3 global interrupt */ + .word LPTIM4_IRQHandler /* LP TIM4 global interrupt */ + .word LPTIM5_IRQHandler /* LP TIM5 global interrupt */ + .word LPUART1_IRQHandler /* LP UART1 interrupt */ + .word 0 /* Reserved */ + .word CRS_IRQHandler /* Clock Recovery Global Interrupt */ + .word ECC_IRQHandler /* ECC diagnostic Global Interrupt */ + .word SAI4_IRQHandler /* SAI4 global interrupt */ + .word DTS_IRQHandler /* Digital Temperature Sensor interrupt */ + .word 0 /* Reserved */ + .word WAKEUP_PIN_IRQHandler /* Interrupt for all 6 wake-up pins */ + .word OCTOSPI2_IRQHandler /* OCTOSPI2 Interrupt */ + .word 0 /* Reserved */ + .word 0 /* Reserved */ + .word FMAC_IRQHandler /* FMAC Interrupt */ + .word CORDIC_IRQHandler /* CORDIC Interrupt */ + .word UART9_IRQHandler /* UART9 Interrupt */ + .word USART10_IRQHandler /* UART10 Interrupt */ + .word I2C5_EV_IRQHandler /* I2C5 Event Interrupt */ + .word I2C5_ER_IRQHandler /* I2C5 Error Interrupt */ + .word FDCAN3_IT0_IRQHandler /* FDCAN3 interrupt line 0 */ + .word FDCAN3_IT1_IRQHandler /* FDCAN3 interrupt line 1 */ + .word TIM23_IRQHandler /* TIM23 global interrupt */ + .word TIM24_IRQHandler /* TIM24 global interrupt */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_AVD_IRQHandler + .thumb_set PVD_AVD_IRQHandler,Default_Handler + + .weak TAMP_STAMP_IRQHandler + .thumb_set TAMP_STAMP_IRQHandler,Default_Handler + + .weak RTC_WKUP_IRQHandler + .thumb_set RTC_WKUP_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Stream0_IRQHandler + .thumb_set DMA1_Stream0_IRQHandler,Default_Handler + + .weak DMA1_Stream1_IRQHandler + .thumb_set DMA1_Stream1_IRQHandler,Default_Handler + + .weak DMA1_Stream2_IRQHandler + .thumb_set DMA1_Stream2_IRQHandler,Default_Handler + + .weak DMA1_Stream3_IRQHandler + .thumb_set DMA1_Stream3_IRQHandler,Default_Handler + + .weak DMA1_Stream4_IRQHandler + .thumb_set DMA1_Stream4_IRQHandler,Default_Handler + + .weak DMA1_Stream5_IRQHandler + .thumb_set DMA1_Stream5_IRQHandler,Default_Handler + + .weak DMA1_Stream6_IRQHandler + .thumb_set DMA1_Stream6_IRQHandler,Default_Handler + + .weak ADC_IRQHandler + .thumb_set ADC_IRQHandler,Default_Handler + + .weak FDCAN1_IT0_IRQHandler + .thumb_set FDCAN1_IT0_IRQHandler,Default_Handler + + .weak FDCAN2_IT0_IRQHandler + .thumb_set FDCAN2_IT0_IRQHandler,Default_Handler + + .weak FDCAN1_IT1_IRQHandler + .thumb_set FDCAN1_IT1_IRQHandler,Default_Handler + + .weak FDCAN2_IT1_IRQHandler + .thumb_set FDCAN2_IT1_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_IRQHandler + .thumb_set TIM1_UP_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_IRQHandler + .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak TIM8_BRK_TIM12_IRQHandler + .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler + + .weak TIM8_UP_TIM13_IRQHandler + .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler + + .weak TIM8_TRG_COM_TIM14_IRQHandler + .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler + + .weak TIM8_CC_IRQHandler + .thumb_set TIM8_CC_IRQHandler,Default_Handler + + .weak DMA1_Stream7_IRQHandler + .thumb_set DMA1_Stream7_IRQHandler,Default_Handler + + .weak FMC_IRQHandler + .thumb_set FMC_IRQHandler,Default_Handler + + .weak SDMMC1_IRQHandler + .thumb_set SDMMC1_IRQHandler,Default_Handler + + .weak TIM5_IRQHandler + .thumb_set TIM5_IRQHandler,Default_Handler + + .weak SPI3_IRQHandler + .thumb_set SPI3_IRQHandler,Default_Handler + + .weak UART4_IRQHandler + .thumb_set UART4_IRQHandler,Default_Handler + + .weak UART5_IRQHandler + .thumb_set UART5_IRQHandler,Default_Handler + + .weak TIM6_DAC_IRQHandler + .thumb_set TIM6_DAC_IRQHandler,Default_Handler + + .weak TIM7_IRQHandler + .thumb_set TIM7_IRQHandler,Default_Handler + + .weak DMA2_Stream0_IRQHandler + .thumb_set DMA2_Stream0_IRQHandler,Default_Handler + + .weak DMA2_Stream1_IRQHandler + .thumb_set DMA2_Stream1_IRQHandler,Default_Handler + + .weak DMA2_Stream2_IRQHandler + .thumb_set DMA2_Stream2_IRQHandler,Default_Handler + + .weak DMA2_Stream3_IRQHandler + .thumb_set DMA2_Stream3_IRQHandler,Default_Handler + + .weak DMA2_Stream4_IRQHandler + .thumb_set DMA2_Stream4_IRQHandler,Default_Handler + + .weak ETH_IRQHandler + .thumb_set ETH_IRQHandler,Default_Handler + + .weak ETH_WKUP_IRQHandler + .thumb_set ETH_WKUP_IRQHandler,Default_Handler + + .weak FDCAN_CAL_IRQHandler + .thumb_set FDCAN_CAL_IRQHandler,Default_Handler + + .weak DMA2_Stream5_IRQHandler + .thumb_set DMA2_Stream5_IRQHandler,Default_Handler + + .weak DMA2_Stream6_IRQHandler + .thumb_set DMA2_Stream6_IRQHandler,Default_Handler + + .weak DMA2_Stream7_IRQHandler + .thumb_set DMA2_Stream7_IRQHandler,Default_Handler + + .weak USART6_IRQHandler + .thumb_set USART6_IRQHandler,Default_Handler + + .weak I2C3_EV_IRQHandler + .thumb_set I2C3_EV_IRQHandler,Default_Handler + + .weak I2C3_ER_IRQHandler + .thumb_set I2C3_ER_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_OUT_IRQHandler + .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler + + .weak OTG_HS_EP1_IN_IRQHandler + .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler + + .weak OTG_HS_WKUP_IRQHandler + .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler + + .weak OTG_HS_IRQHandler + .thumb_set OTG_HS_IRQHandler,Default_Handler + + .weak DCMI_PSSI_IRQHandler + .thumb_set DCMI_PSSI_IRQHandler,Default_Handler + + .weak RNG_IRQHandler + .thumb_set RNG_IRQHandler,Default_Handler + + .weak FPU_IRQHandler + .thumb_set FPU_IRQHandler,Default_Handler + + .weak UART7_IRQHandler + .thumb_set UART7_IRQHandler,Default_Handler + + .weak UART8_IRQHandler + .thumb_set UART8_IRQHandler,Default_Handler + + .weak SPI4_IRQHandler + .thumb_set SPI4_IRQHandler,Default_Handler + + .weak SPI5_IRQHandler + .thumb_set SPI5_IRQHandler,Default_Handler + + .weak SPI6_IRQHandler + .thumb_set SPI6_IRQHandler,Default_Handler + + .weak SAI1_IRQHandler + .thumb_set SAI1_IRQHandler,Default_Handler + + .weak LTDC_IRQHandler + .thumb_set LTDC_IRQHandler,Default_Handler + + .weak LTDC_ER_IRQHandler + .thumb_set LTDC_ER_IRQHandler,Default_Handler + + .weak DMA2D_IRQHandler + .thumb_set DMA2D_IRQHandler,Default_Handler + + .weak OCTOSPI1_IRQHandler + .thumb_set OCTOSPI1_IRQHandler,Default_Handler + + .weak LPTIM1_IRQHandler + .thumb_set LPTIM1_IRQHandler,Default_Handler + + .weak CEC_IRQHandler + .thumb_set CEC_IRQHandler,Default_Handler + + .weak I2C4_EV_IRQHandler + .thumb_set I2C4_EV_IRQHandler,Default_Handler + + .weak I2C4_ER_IRQHandler + .thumb_set I2C4_ER_IRQHandler,Default_Handler + + .weak SPDIF_RX_IRQHandler + .thumb_set SPDIF_RX_IRQHandler,Default_Handler + + .weak DMAMUX1_OVR_IRQHandler + .thumb_set DMAMUX1_OVR_IRQHandler,Default_Handler + + .weak DFSDM1_FLT0_IRQHandler + .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler + + .weak DFSDM1_FLT1_IRQHandler + .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler + + .weak DFSDM1_FLT2_IRQHandler + .thumb_set DFSDM1_FLT2_IRQHandler,Default_Handler + + .weak DFSDM1_FLT3_IRQHandler + .thumb_set DFSDM1_FLT3_IRQHandler,Default_Handler + + .weak SWPMI1_IRQHandler + .thumb_set SWPMI1_IRQHandler,Default_Handler + + .weak TIM15_IRQHandler + .thumb_set TIM15_IRQHandler,Default_Handler + + .weak TIM16_IRQHandler + .thumb_set TIM16_IRQHandler,Default_Handler + + .weak TIM17_IRQHandler + .thumb_set TIM17_IRQHandler,Default_Handler + + .weak MDIOS_WKUP_IRQHandler + .thumb_set MDIOS_WKUP_IRQHandler,Default_Handler + + .weak MDIOS_IRQHandler + .thumb_set MDIOS_IRQHandler,Default_Handler + + .weak MDMA_IRQHandler + .thumb_set MDMA_IRQHandler,Default_Handler + + .weak SDMMC2_IRQHandler + .thumb_set SDMMC2_IRQHandler,Default_Handler + + .weak HSEM1_IRQHandler + .thumb_set HSEM1_IRQHandler,Default_Handler + + .weak ADC3_IRQHandler + .thumb_set ADC3_IRQHandler,Default_Handler + + .weak DMAMUX2_OVR_IRQHandler + .thumb_set DMAMUX2_OVR_IRQHandler,Default_Handler + + .weak BDMA_Channel0_IRQHandler + .thumb_set BDMA_Channel0_IRQHandler,Default_Handler + + .weak BDMA_Channel1_IRQHandler + .thumb_set BDMA_Channel1_IRQHandler,Default_Handler + + .weak BDMA_Channel2_IRQHandler + .thumb_set BDMA_Channel2_IRQHandler,Default_Handler + + .weak BDMA_Channel3_IRQHandler + .thumb_set BDMA_Channel3_IRQHandler,Default_Handler + + .weak BDMA_Channel4_IRQHandler + .thumb_set BDMA_Channel4_IRQHandler,Default_Handler + + .weak BDMA_Channel5_IRQHandler + .thumb_set BDMA_Channel5_IRQHandler,Default_Handler + + .weak BDMA_Channel6_IRQHandler + .thumb_set BDMA_Channel6_IRQHandler,Default_Handler + + .weak BDMA_Channel7_IRQHandler + .thumb_set BDMA_Channel7_IRQHandler,Default_Handler + + .weak COMP1_IRQHandler + .thumb_set COMP1_IRQHandler,Default_Handler + + .weak LPTIM2_IRQHandler + .thumb_set LPTIM2_IRQHandler,Default_Handler + + .weak LPTIM3_IRQHandler + .thumb_set LPTIM3_IRQHandler,Default_Handler + + .weak LPTIM4_IRQHandler + .thumb_set LPTIM4_IRQHandler,Default_Handler + + .weak LPTIM5_IRQHandler + .thumb_set LPTIM5_IRQHandler,Default_Handler + + .weak LPUART1_IRQHandler + .thumb_set LPUART1_IRQHandler,Default_Handler + + .weak CRS_IRQHandler + .thumb_set CRS_IRQHandler,Default_Handler + + .weak ECC_IRQHandler + .thumb_set ECC_IRQHandler,Default_Handler + + .weak SAI4_IRQHandler + .thumb_set SAI4_IRQHandler,Default_Handler + + .weak DTS_IRQHandler + .thumb_set DTS_IRQHandler,Default_Handler + + .weak WAKEUP_PIN_IRQHandler + .thumb_set WAKEUP_PIN_IRQHandler,Default_Handler + + .weak OCTOSPI2_IRQHandler + .thumb_set OCTOSPI2_IRQHandler,Default_Handler + + .weak FMAC_IRQHandler + .thumb_set FMAC_IRQHandler,Default_Handler + + .weak CORDIC_IRQHandler + .thumb_set CORDIC_IRQHandler,Default_Handler + + .weak UART9_IRQHandler + .thumb_set UART9_IRQHandler,Default_Handler + + .weak USART10_IRQHandler + .thumb_set USART10_IRQHandler,Default_Handler + + .weak I2C5_EV_IRQHandler + .thumb_set I2C5_EV_IRQHandler,Default_Handler + + .weak I2C5_ER_IRQHandler + .thumb_set I2C5_ER_IRQHandler,Default_Handler + + .weak FDCAN3_IT0_IRQHandler + .thumb_set FDCAN3_IT0_IRQHandler,Default_Handler + + .weak FDCAN3_IT1_IRQHandler + .thumb_set FDCAN3_IT1_IRQHandler,Default_Handler + + .weak TIM23_IRQHandler + .thumb_set TIM23_IRQHandler,Default_Handler + + .weak TIM24_IRQHandler + .thumb_set TIM24_IRQHandler,Default_Handler + + From c4748dd114a1f66a9492c3389e80cd6d66c1953b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Tue, 9 Dec 2025 21:07:28 +0100 Subject: [PATCH 08/76] Added initial GPIO mock --- CMakeLists.txt | 56 ++-- Inc/HALAL/Models/GPIO.hpp | 4 + Inc/MockedDrivers/hal_gpio_interface.h | 388 +++++++++++++++++++++++++ Tests/CMakeLists.txt | 42 +-- 4 files changed, 439 insertions(+), 51 deletions(-) create mode 100644 Inc/MockedDrivers/hal_gpio_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f956d7aba..e015bfde2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,9 @@ if(NOT PROJECT_IS_TOP_LEVEL) set(STLIB_LIBRARY ${STLIB_LIBRARY} PARENT_SCOPE) endif() +include(CTest) +enable_testing() + option(USE_ETHERNET "Enable ethernet peripheral" OFF) option(TARGET_NUCLEO "Targets the STM32H723 Nucleo development board" OFF) @@ -18,22 +21,6 @@ message(STATUS "${PROJECT_NAME} Ethernet: ${USE_ETHERNET}") message(STATUS "${PROJECT_NAME} Nucleo: ${TARGET_NUCLEO}") message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") -# ============================ -# Tests + GTest - Simulator -# ============================ -if((PROJECT_IS_TOP_LEVEL AND (NOT CMAKE_CROSSCOMPILING))) - include(FetchContent) - option(BUILD_GMOCK OFF) - option(INSTALL_GTEST OFF) - FetchContent_Declare( - googletest - GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.15.2 - ) - FetchContent_MakeAvailable(googletest) - add_library(GTest::GTest INTERFACE IMPORTED) - target_link_libraries(GTest::GTest INTERFACE gtest_main) -endif() if(NOT CMAKE_CROSSCOMPILING) message(STATUS "Compiling for simulator") @@ -216,25 +203,29 @@ add_library(${STLIB_LIBRARY} STATIC $<$,$>:${LWIP_SOURCES}> $<$,$>:${USER_LWIP_SOURCES}> - ${HALAL_C_NO_ETH} - ${HALAL_CPP_NO_ETH} - $<$:${HALAL_C_ETH}> - $<$:${HALAL_CPP_ETH}> + $<$:${HALAL_C_NO_ETH}> + $<$:${HALAL_CPP_NO_ETH}> + $<$,$>:${HALAL_C_ETH}> + $<$,$>:${HALAL_CPP_ETH}> + + $<$:${CPP_UTILITIES_C}> + $<$:${CPP_UTILITIES_CPP}> - ${CPP_UTILITIES_C} - ${CPP_UTILITIES_CPP} + $<$:${STLIB_LOW_C_NO_ETH}> + $<$:${STLIB_LOW_CPP_NO_ETH}> + $<$,$>:${STLIB_LOW_C_ETH}> + $<$,$>:${STLIB_LOW_CPP_ETH}> - ${STLIB_LOW_C_NO_ETH} - ${STLIB_LOW_CPP_NO_ETH} - $<$:${STLIB_LOW_C_ETH}> - $<$:${STLIB_LOW_CPP_ETH}> + $<$:${STLIB_HIGH_C_NO_ETH}> + $<$:${STLIB_HIGH_CPP_NO_ETH}> + $<$,$>:${STLIB_HIGH_C_ETH}> + $<$,$>:${STLIB_HIGH_CPP_ETH}> - ${STLIB_HIGH_C_NO_ETH} - ${STLIB_HIGH_CPP_NO_ETH} - $<$:${STLIB_HIGH_C_ETH}> - $<$:${STLIB_HIGH_CPP_ETH}> + $<$:${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp> - ${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/HALAL/Services/Time/Scheduler.cpp> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/mocked_ll_tim.cpp> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) set_target_properties(${STLIB_LIBRARY} PROPERTIES @@ -248,7 +239,7 @@ target_compile_definitions(${STLIB_LIBRARY} PUBLIC $<$:USE_HAL_DRIVER> $<$:STM32H723xx> - $<$>:SIM_ON> + $<$>:TESTING_ENV> $<$:STLIB_ETH> $,NUCLEO,BOARD> @@ -313,6 +304,7 @@ target_include_directories(${STLIB_LIBRARY} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Inc/ST-LIB_HIGH ) + if(PROJECT_IS_TOP_LEVEL) configure_file( ${CMAKE_CURRENT_LIST_DIR}/Inc/stm32h7xx_hal_conf_template.h diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index c19131e37..1988c9785 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -1,6 +1,10 @@ #pragma once +#ifndef TESTING_ENV #include "stm32h7xx_hal.h" +#else +#include "MockedDrivers/hal_gpio_interface.h" +#endif #include #include #include diff --git a/Inc/MockedDrivers/hal_gpio_interface.h b/Inc/MockedDrivers/hal_gpio_interface.h new file mode 100644 index 000000000..579b6ad45 --- /dev/null +++ b/Inc/MockedDrivers/hal_gpio_interface.h @@ -0,0 +1,388 @@ +/** + ****************************************************************************** + * @file stm32h7xx_hal_gpio.h + * @author MCD Application Team + * @brief Header file of GPIO HAL module. + ****************************************************************************** + * @attention + * + * Copyright (c) 2017 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32H7xx_HAL_GPIO_H +#define STM32H7xx_HAL_GPIO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "stm32h7xx_hal_def.h" + +/** @addtogroup STM32H7xx_HAL_Driver + * @{ + */ + +/** @addtogroup GPIO + * @{ + */ + +/* Exported types ------------------------------------------------------------*/ +/** @defgroup GPIO_Exported_Types GPIO Exported Types + * @{ + */ + +/** + * @brief GPIO Init structure definition + */ +typedef struct { + uint32_t Pin; /*!< Specifies the GPIO pins to be configured. + This parameter can be any value of @ref GPIO_pins_define */ + + uint32_t Mode; /*!< Specifies the operating mode for the selected pins. + This parameter can be a value of @ref GPIO_mode_define */ + + uint32_t + Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected + pins. This parameter can be a value of @ref GPIO_pull_define */ + + uint32_t + Speed; /*!< Specifies the speed for the selected pins. + This parameter can be a value of @ref GPIO_speed_define */ + + uint32_t Alternate; /*!< Peripheral to be connected to the selected pins. + This parameter can be a value of @ref + GPIO_Alternate_function_selection */ +} GPIO_InitTypeDef; + +/** + * @brief GPIO Bit SET and Bit RESET enumeration + */ +typedef enum { GPIO_PIN_RESET = 0U, GPIO_PIN_SET } GPIO_PinState; +/** + * @} + */ + +/* Exported constants --------------------------------------------------------*/ + +/** @defgroup GPIO_Exported_Constants GPIO Exported Constants + * @{ + */ + +/** @defgroup GPIO_pins_define GPIO pins define + * @{ + */ +#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */ +#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */ +#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */ +#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */ +#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */ +#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */ +#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */ +#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */ +#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */ +#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */ +#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */ +#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */ +#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */ +#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */ +#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */ +#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */ +#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */ + +#define GPIO_PIN_MASK (0x0000FFFFU) /* PIN mask for assert test */ +/** + * @} + */ + +/** @defgroup GPIO_mode_define GPIO mode define + * @brief GPIO Configuration Mode + * Elements values convention: 0x00WX00YZ + * - W : EXTI trigger detection on 3 bits + * - X : EXTI mode (IT or Event) on 2 bits + * - Y : Output type (Push Pull or Open Drain) on 1 bit + * - Z : GPIO mode (Input, Output, Alternate or Analog) on 2 bits + * @{ + */ +#define GPIO_MODE_INPUT \ + MODE_INPUT /*!< Input Floating Mode */ +#define GPIO_MODE_OUTPUT_PP \ + (MODE_OUTPUT | OUTPUT_PP) /*!< Output Push Pull Mode */ +#define GPIO_MODE_OUTPUT_OD \ + (MODE_OUTPUT | OUTPUT_OD) /*!< Output Open Drain Mode */ +#define GPIO_MODE_AF_PP \ + (MODE_AF | OUTPUT_PP) /*!< Alternate Function Push Pull Mode */ +#define GPIO_MODE_AF_OD \ + (MODE_AF | OUTPUT_OD) /*!< Alternate Function Open Drain Mode */ +#define GPIO_MODE_ANALOG \ + MODE_ANALOG /*!< Analog Mode */ +#define GPIO_MODE_IT_RISING \ + (MODE_INPUT | EXTI_IT | TRIGGER_RISING) /*!< External Interrupt Mode with \ + Rising edge trigger detection */ +#define GPIO_MODE_IT_FALLING \ + (MODE_INPUT | EXTI_IT | \ + TRIGGER_FALLING) /*!< External Interrupt Mode with Falling edge trigger \ + detection */ +#define GPIO_MODE_IT_RISING_FALLING \ + (MODE_INPUT | EXTI_IT | TRIGGER_RISING | \ + TRIGGER_FALLING) /*!< External Interrupt Mode with Rising/Falling edge \ + trigger detection */ + +#define GPIO_MODE_EVT_RISING \ + (MODE_INPUT | EXTI_EVT | TRIGGER_RISING) /*!< External Event Mode with \ + Rising edge trigger detection */ +#define GPIO_MODE_EVT_FALLING \ + (MODE_INPUT | EXTI_EVT | \ + TRIGGER_FALLING) /*!< External Event Mode with Falling edge trigger \ + detection */ +#define GPIO_MODE_EVT_RISING_FALLING \ + (MODE_INPUT | EXTI_EVT | TRIGGER_RISING | \ + TRIGGER_FALLING) /*!< External Event Mode with Rising/Falling edge trigger \ + detection */ +/** + * @} + */ + +/** @defgroup GPIO_speed_define GPIO speed define + * @brief GPIO Output Maximum frequency + * @{ + */ +#define GPIO_SPEED_FREQ_LOW (0x00000000U) /*!< Low speed */ +#define GPIO_SPEED_FREQ_MEDIUM (0x00000001U) /*!< Medium speed */ +#define GPIO_SPEED_FREQ_HIGH (0x00000002U) /*!< Fast speed */ +#define GPIO_SPEED_FREQ_VERY_HIGH (0x00000003U) /*!< High speed */ +/** + * @} + */ + +/** @defgroup GPIO_pull_define GPIO pull define + * @brief GPIO Pull-Up or Pull-Down Activation + * @{ + */ +#define GPIO_NOPULL (0x00000000U) /*!< No Pull-up or Pull-down activation */ +#define GPIO_PULLUP (0x00000001U) /*!< Pull-up activation */ +#define GPIO_PULLDOWN (0x00000002U) /*!< Pull-down activation */ +/** + * @} + */ + +/** + * @} + */ + +/* Exported macro ------------------------------------------------------------*/ +/** @defgroup GPIO_Exported_Macros GPIO Exported Macros + * @{ + */ + +/** + * @brief Checks whether the specified EXTI line flag is set or not. + * @param __EXTI_LINE__: specifies the EXTI line flag to check. + * This parameter can be GPIO_PIN_x where x can be(0..15) + * @retval The new state of __EXTI_LINE__ (SET or RESET). + */ +#define __HAL_GPIO_EXTI_GET_FLAG(__EXTI_LINE__) (EXTI->PR1 & (__EXTI_LINE__)) + +/** + * @brief Clears the EXTI's line pending flags. + * @param __EXTI_LINE__: specifies the EXTI lines flags to clear. + * This parameter can be any combination of GPIO_PIN_x where x can be + * (0..15) + * @retval None + */ +#define __HAL_GPIO_EXTI_CLEAR_FLAG(__EXTI_LINE__) (EXTI->PR1 = (__EXTI_LINE__)) + +/** + * @brief Checks whether the specified EXTI line is asserted or not. + * @param __EXTI_LINE__: specifies the EXTI line to check. + * This parameter can be GPIO_PIN_x where x can be(0..15) + * @retval The new state of __EXTI_LINE__ (SET or RESET). + */ +#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR1 & (__EXTI_LINE__)) + +/** + * @brief Clears the EXTI's line pending bits. + * @param __EXTI_LINE__: specifies the EXTI lines to clear. + * This parameter can be any combination of GPIO_PIN_x where x can be + * (0..15) + * @retval None + */ +#define __HAL_GPIO_EXTI_CLEAR_IT(__EXTI_LINE__) (EXTI->PR1 = (__EXTI_LINE__)) + +#if defined(DUAL_CORE) +/** + * @brief Checks whether the specified EXTI line flag is set or not. + * @param __EXTI_LINE__: specifies the EXTI line flag to check. + * This parameter can be GPIO_PIN_x where x can be(0..15) + * @retval The new state of __EXTI_LINE__ (SET or RESET). + */ +#define __HAL_GPIO_EXTID2_GET_FLAG(__EXTI_LINE__) \ + (EXTI->C2PR1 & (__EXTI_LINE__)) + +/** + * @brief Clears the EXTI's line pending flags. + * @param __EXTI_LINE__: specifies the EXTI lines flags to clear. + * This parameter can be any combination of GPIO_PIN_x where x can be + * (0..15) + * @retval None + */ +#define __HAL_GPIO_EXTID2_CLEAR_FLAG(__EXTI_LINE__) \ + (EXTI->C2PR1 = (__EXTI_LINE__)) + +/** + * @brief Checks whether the specified EXTI line is asserted or not. + * @param __EXTI_LINE__: specifies the EXTI line to check. + * This parameter can be GPIO_PIN_x where x can be(0..15) + * @retval The new state of __EXTI_LINE__ (SET or RESET). + */ +#define __HAL_GPIO_EXTID2_GET_IT(__EXTI_LINE__) (EXTI->C2PR1 & (__EXTI_LINE__)) + +/** + * @brief Clears the EXTI's line pending bits. + * @param __EXTI_LINE__: specifies the EXTI lines to clear. + * This parameter can be any combination of GPIO_PIN_x where x can be + * (0..15) + * @retval None + */ +#define __HAL_GPIO_EXTID2_CLEAR_IT(__EXTI_LINE__) \ + (EXTI->C2PR1 = (__EXTI_LINE__)) +#endif + +/** + * @brief Generates a Software interrupt on selected EXTI line. + * @param __EXTI_LINE__: specifies the EXTI line to check. + * This parameter can be GPIO_PIN_x where x can be(0..15) + * @retval None + */ +#define __HAL_GPIO_EXTI_GENERATE_SWIT(__EXTI_LINE__) \ + (EXTI->SWIER1 |= (__EXTI_LINE__)) +/** + * @} + */ + +/* Include GPIO HAL Extension module */ +#include "stm32h7xx_hal_gpio_ex.h" + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup GPIO_Exported_Functions + * @{ + */ + +/** @addtogroup GPIO_Exported_Functions_Group1 + * @{ + */ +/* Initialization and de-initialization functions *****************************/ +void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, const GPIO_InitTypeDef *GPIO_Init); +void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin); +/** + * @} + */ + +/** @addtogroup GPIO_Exported_Functions_Group2 + * @{ + */ +/* IO operation functions *****************************************************/ +GPIO_PinState HAL_GPIO_ReadPin(const GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); +void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, + GPIO_PinState PinState); +void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); +HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); +void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin); +void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin); + +/** + * @} + */ + +/** + * @} + */ +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/* Private constants ---------------------------------------------------------*/ +/** @defgroup GPIO_Private_Constants GPIO Private Constants + * @{ + */ +#define GPIO_MODE_Pos 0u +#define GPIO_MODE (0x3uL << GPIO_MODE_Pos) +#define MODE_INPUT (0x0uL << GPIO_MODE_Pos) +#define MODE_OUTPUT (0x1uL << GPIO_MODE_Pos) +#define MODE_AF (0x2uL << GPIO_MODE_Pos) +#define MODE_ANALOG (0x3uL << GPIO_MODE_Pos) +#define OUTPUT_TYPE_Pos 4u +#define OUTPUT_TYPE (0x1uL << OUTPUT_TYPE_Pos) +#define OUTPUT_PP (0x0uL << OUTPUT_TYPE_Pos) +#define OUTPUT_OD (0x1uL << OUTPUT_TYPE_Pos) +#define EXTI_MODE_Pos 16u +#define EXTI_MODE (0x3uL << EXTI_MODE_Pos) +#define EXTI_IT (0x1uL << EXTI_MODE_Pos) +#define EXTI_EVT (0x2uL << EXTI_MODE_Pos) +#define TRIGGER_MODE_Pos 20u +#define TRIGGER_MODE (0x7uL << TRIGGER_MODE_Pos) +#define TRIGGER_RISING (0x1uL << TRIGGER_MODE_Pos) +#define TRIGGER_FALLING (0x2uL << TRIGGER_MODE_Pos) +#define TRIGGER_LEVEL (0x4uL << TRIGGER_MODE_Pos) +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup GPIO_Private_Macros GPIO Private Macros + * @{ + */ +#define IS_GPIO_PIN_ACTION(ACTION) \ + (((ACTION) == GPIO_PIN_RESET) || ((ACTION) == GPIO_PIN_SET)) +#define IS_GPIO_PIN(__PIN__) \ + ((((uint32_t)(__PIN__) & GPIO_PIN_MASK) != 0x00U) && \ + (((uint32_t)(__PIN__) & ~GPIO_PIN_MASK) == 0x00U)) +#define IS_GPIO_MODE(MODE) \ + (((MODE) == GPIO_MODE_INPUT) || ((MODE) == GPIO_MODE_OUTPUT_PP) || \ + ((MODE) == GPIO_MODE_OUTPUT_OD) || ((MODE) == GPIO_MODE_AF_PP) || \ + ((MODE) == GPIO_MODE_AF_OD) || ((MODE) == GPIO_MODE_IT_RISING) || \ + ((MODE) == GPIO_MODE_IT_FALLING) || \ + ((MODE) == GPIO_MODE_IT_RISING_FALLING) || \ + ((MODE) == GPIO_MODE_EVT_RISING) || ((MODE) == GPIO_MODE_EVT_FALLING) || \ + ((MODE) == GPIO_MODE_EVT_RISING_FALLING) || ((MODE) == GPIO_MODE_ANALOG)) +#define IS_GPIO_SPEED(SPEED) \ + (((SPEED) == GPIO_SPEED_FREQ_LOW) || ((SPEED) == GPIO_SPEED_FREQ_MEDIUM) || \ + ((SPEED) == GPIO_SPEED_FREQ_HIGH) || \ + ((SPEED) == GPIO_SPEED_FREQ_VERY_HIGH)) + +#define IS_GPIO_PULL(PULL) \ + (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \ + ((PULL) == GPIO_PULLDOWN)) + +/** + * @} + */ + +/* Private functions ---------------------------------------------------------*/ +/** @defgroup GPIO_Private_Functions GPIO Private Functions + * @{ + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32H7xx_HAL_GPIO_H */ diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e677d6bee..c06522432 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -4,33 +4,38 @@ else() set(STLIB_TEST_EXECUTABLE st-lib-test) endif() +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) +FetchContent_MakeAvailable(googletest) + message(STATUS "Generating test executable for ST-LIB") -include(CTest) -enable_testing() + add_executable(${STLIB_TEST_EXECUTABLE} - ${CMAKE_CURRENT_LIST_DIR}/Runes/Pins.cpp - ${CMAKE_CURRENT_LIST_DIR}/Runes/SimRunes.cpp - ${CMAKE_CURRENT_LIST_DIR}/DigitalOutTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/DigitalInTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/Time/test_time.cpp - ${CMAKE_CURRENT_LIST_DIR}/EncoderTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/InputCaptureTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/ADCTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/PWMTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/DualPWMTest.cpp - ${CMAKE_CURRENT_LIST_DIR}/EXTITest.cpp + ${CMAKE_CURRENT_LIST_DIR}/Time/scheduler_test.cpp ) -set_target_properties(${STLIB_TEST_EXECUTABLE} PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED C_STANDARD 11 C_STANDARD_REQUIRED) +set_target_properties(${STLIB_TEST_EXECUTABLE} PROPERTIES + CXX_STANDARD 23 + CXX_STANDARD_REQUIRED YES + C_STANDARD 11 + C_STANDARD_REQUIRED YES +) target_link_libraries( ${STLIB_TEST_EXECUTABLE} - ${STLIB_LIBRARY} GTest::gtest_main + ${STLIB_LIBRARY} ) +if(MINGW OR CYGWIN) + target_link_options(${STLIB_TEST_EXECUTABLE} PRIVATE -static) +endif() + target_compile_definitions(${STLIB_TEST_EXECUTABLE} PRIVATE - SIM_ON + TESTING_ENV ) target_include_directories(${STLIB_TEST_EXECUTABLE} PRIVATE @@ -42,11 +47,10 @@ target_include_directories(${STLIB_TEST_EXECUTABLE} PRIVATE include(GoogleTest) gtest_discover_tests(${STLIB_TEST_EXECUTABLE}) -# Create symlink to test executable for CI/CD to pick it up add_custom_command( TARGET ${STLIB_TEST_EXECUTABLE} POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink - ${CMAKE_CURRENT_BINARY_DIR}/${STLIB_TEST_EXECUTABLE} - ${CMAKE_SOURCE_DIR}/out/build/test.elf + ${CMAKE_CURRENT_BINARY_DIR}/${STLIB_TEST_EXECUTABLE} + ${CMAKE_SOURCE_DIR}/out/build/test.elf ) \ No newline at end of file From c4405406d45c1dd1f2c9f1b6caab17e036aae0cb Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 10 Dec 2025 16:59:10 +0100 Subject: [PATCH 09/76] feat(MPU): Initial structure && design of the API --- Inc/HALAL/Models/MPU.hpp | 220 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 Inc/HALAL/Models/MPU.hpp diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp new file mode 100644 index 000000000..f87d2698b --- /dev/null +++ b/Inc/HALAL/Models/MPU.hpp @@ -0,0 +1,220 @@ +/* + * MPU.hpp + * + * Created on: 10 dic. 2025 + * Author: Boris + */ + +#ifndef MPU_HPP +#define MPU_HPP + +#ifndef HALAL_MPUBUFFERS_MAX_INSTANCES +#define HALAL_MPUBUFFERS_MAX_INSTANCES 100 +#endif + +#include "C++Utilities/CppUtils.hpp" +#include "C++Utilities/CppImports.hpp" +#include "ErrorHandler/ErrorHandler.hpp" +#include "stm32h7xx_hal.h" + + +struct MPUDomain { + + enum class MemoryDomain : uint8_t { + D1 = 1, // AXI SRAM (0x24000000) + D2 = 2, // SRAM 1/2/3 (0x30000000) + D3 = 3 // SRAM 4 (0x38000000) + }; + + enum class MemoryType : bool { + Cached = true, + NonCached = false + }; + + // Buffer Request + struct Entry { + MemoryDomain memory_domain; + MemoryType memory_type; + std::size_t alignment; + std::size_t size_in_bytes; + }; + + // Buffer Request Wrapper + struct Buffer { + using domain = MPUDomain; + Entry e; + + /** + * @brief Constructs a Buffer entry for a type T. + * @tparam T The type for which the buffer is requested. Must be a POD type. + * @param type The memory type (Cached or NonCached). + * @param domain The memory domain where the buffer should be allocated. + * @param force_cache_alignment If true, forces the buffer to be cache line aligned (32 bytes, takes the rest as padding). + */ + template + consteval Buffer(MemoryType type = MemoryType::NonCached, MemoryDomain domain = MemoryDomain::D2, bool force_cache_alignment = false) + requires(std::is_standard_layout_v && std::is_trivial_v) + : e{ + domain, + type, + force_cache_alignment ? std::max(std::size_t(32), alignof(T)) : alignof(T), + sizeof(T)} + { + static_assert(alignof(T) <= 32, "Requested type has alignment greater than cache line size (32 bytes)."); + } + + template + consteval void inscribe(Ctx &ctx) const { + ctx.template add(e); + } + }; + + static constexpr std::size_t max_instances = HALAL_MPUBUFFERS_MAX_INSTANCES; + + struct Config { + uint32_t base_address; + + std::size_t size; + + // MPU Config Data + bool is_mpu_leader; + MPU_Region_InitTypeDef mpu_init; + }; + + // 5. Build compile-time: Entry[] → Config[] + // + // IMPORTANTE: + // - Esta función es consteval: se ejecuta en tiempo de compilación. + // - Aquí es donde se hacen TODAS las validaciones estáticas sobre los Entry. + // + template + static consteval std::array build(std::span entries) { + std::array cfgs{}; + + for (std::size_t i = 0; i < N; i++) { + const Entry &e = entries[i]; + + // Aquí se pueden hacer checks globales y locales: + // - Comprobar que no se repite el mismo recurso. + // - Verificar que el recurso es válido para este dominio. + // - Validar que la combinación de parámetros tiene sentido. + + // Ejemplo de patrón (pseudo-código): + // for (std::size_t j = 0; j < i; ++j) { + // if (entries[j].pin == e.pin && entries[j].port == e.port) { + // struct duplicate_resource {}; + // throw duplicate_resource{}; + // } + // } + + // A partir de 'e' se construye cfgs[i] con los datos necesarios + // para configurar el hardware en tiempo de ejecución. + // cfgs[i] = ...; + } + + return cfgs; + } + + struct Instance { + + /** + * @brief Constructs the object of type T in the allocated MPU memory. + * @param args Arguments to forward to T's constructor. + * @return Pointer to the constructed object of type T. + */ + template + T* construct(Args&&... args) { + is_valid_type(); + return new (ptr) T(std::forward(args)...); // Placement new + } + + /** + * @brief Casts the stored pointer to the desired type T. + * @tparam T The type to cast the pointer to. + * @return Pointer of type T. + */ + template + T* as() { + is_valid_type(); + return static_cast(ptr); + } + + private: + template friend struct Init; + + template + void is_valid_type() { + static_assert(std::is_standard_layout_v && std::is_trivial_v, + "MPU Buffer can only store POD types (standard layout and trivial)."); + if (alignof(T) > alignment) { + ErrorHandler("Type alignment (%d) exceeds MPU buffer alignment (%d).", alignof(T), alignment); + } + } + + void* ptr; + std::size_t size; + Instance() : ptr{nullptr}, size{0} {} + }; + + // 7. Inicialización runtime: aplica Config → crea Instance[] + template + struct Init { + static inline std::array instances{}; + + // Esta función se llama desde Board::init() en TIEMPO DE EJECUCIÓN. + // Aquí ya no se hacen checks de diseño: solo se aplica la configuración + // generada en compile-time y se llama a HAL/LL. + static void init(std::span cfgs) { + for (std::size_t i = 0; i < N; i++) { + const auto &cfg = cfgs[i]; + auto &inst = instances[i]; + + // Inicializar 'inst' a partir de 'cfg': + // - llamadas a HAL/LL + // - set de registros, punteros a periféricos, etc. + } + } + }; + + private: + static consteval uint32_t get_address(MemoryDomain domain, std::size_t offset) { + switch (domain) { + case MemoryDomain::D1: + return 0x24000000 + static_cast(offset); + case MemoryDomain::D2: + return 0x30000000 + static_cast(offset); + case MemoryDomain::D3: + return 0x38000000 + static_cast(offset); + default: + ErrorHandler("Invalid Memory Domain"); + return 0; + } + } + + static consteval uint32_t align_up(uint32_t address, std::size_t alignment) { + uint32_t mask = static_cast(alignment - 1); + return (address + mask) & ~mask; + } + + static consteval std::pair get_size_needed(std::size_t size) { + // Get next power of two + if (popcount(size) == 1) { + return {size, 0}; + } else { + size_t power = 1 + countl_zero(size); + + if (power < 5) { + power = 5; // Minimum MPU region size is 32 bytes + } + + // MPU can divide to 8 subregions, so try to get a closer size + size_t subregion_size = 1U << (power - 3); + size_t num_subregions = (size + subregion_size - 1) / subregion_size; // Round up division + uint8_t subregion_disable = static_cast(~(0xFFU << num_subregions)); + + return {subregion_size * num_subregions, subregion_disable}; + } + } +}; + +#endif // MPU_HPP \ No newline at end of file From 3286140968520f955e2a0e2bef7b5bbe5268a2b0 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 10 Dec 2025 17:41:30 +0100 Subject: [PATCH 10/76] fix(MPU): Bug fixing (MPU subregion calculation, throws and alignment checks) --- Inc/HALAL/Models/MPU.hpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index f87d2698b..d6f933d76 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -146,8 +146,11 @@ struct MPUDomain { void is_valid_type() { static_assert(std::is_standard_layout_v && std::is_trivial_v, "MPU Buffer can only store POD types (standard layout and trivial)."); - if (alignof(T) > alignment) { - ErrorHandler("Type alignment (%d) exceeds MPU buffer alignment (%d).", alignof(T), alignment); + if (sizeof(T) > size) { + ErrorHandler("Requested type size exceeds allocated MPU buffer size."); + } + if (reinterpret_cast(ptr) % alignof(T) != 0) { + ErrorHandler("Requested type alignment is not satisfied by allocated MPU buffer."); } } @@ -186,8 +189,7 @@ struct MPUDomain { case MemoryDomain::D3: return 0x38000000 + static_cast(offset); default: - ErrorHandler("Invalid Memory Domain"); - return 0; + throw "Invalid Memory Domain"; } } @@ -210,7 +212,8 @@ struct MPUDomain { // MPU can divide to 8 subregions, so try to get a closer size size_t subregion_size = 1U << (power - 3); size_t num_subregions = (size + subregion_size - 1) / subregion_size; // Round up division - uint8_t subregion_disable = static_cast(~(0xFFU << num_subregions)); + uint8_t subregion_disable = static_cast(~((0xFFU << num_subregions) - 1)); + static_assert(subregion_disable != 0xFF, "Something isn't working on the MPU region size calculation."); return {subregion_size * num_subregions, subregion_disable}; } From 755fd4ba077904e49db68d0380cd3562db51728c Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 10 Dec 2025 17:53:11 +0100 Subject: [PATCH 11/76] fix(MPU): Minor bug fixes (missing std::, incorrect subregion mask) --- Inc/HALAL/Models/MPU.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index d6f933d76..351165820 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -200,10 +200,10 @@ struct MPUDomain { static consteval std::pair get_size_needed(std::size_t size) { // Get next power of two - if (popcount(size) == 1) { + if (std::popcount(size) == 1) { return {size, 0}; } else { - size_t power = 1 + countl_zero(size); + size_t power = 1 + std::countl_zero(size); if (power < 5) { power = 5; // Minimum MPU region size is 32 bytes @@ -212,7 +212,7 @@ struct MPUDomain { // MPU can divide to 8 subregions, so try to get a closer size size_t subregion_size = 1U << (power - 3); size_t num_subregions = (size + subregion_size - 1) / subregion_size; // Round up division - uint8_t subregion_disable = static_cast(~((0xFFU << num_subregions) - 1)); + uint8_t subregion_disable = static_cast(~((1U << num_subregions) - 1)); static_assert(subregion_disable != 0xFF, "Something isn't working on the MPU region size calculation."); return {subregion_size * num_subregions, subregion_disable}; From 1b5c8fe06dc18efede3875e814fdb6f439c94711 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 10:17:55 +0100 Subject: [PATCH 12/76] feat(MPU): Initial implementation of MPUManager refactor --- Inc/HALAL/Models/MPU.hpp | 407 +++++++++++++++++++++++++++++---------- 1 file changed, 309 insertions(+), 98 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index 351165820..2b43ff998 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -40,8 +40,10 @@ struct MPUDomain { }; // Buffer Request Wrapper + template struct Buffer { using domain = MPUDomain; + using buffer_type = T; Entry e; /** @@ -51,13 +53,12 @@ struct MPUDomain { * @param domain The memory domain where the buffer should be allocated. * @param force_cache_alignment If true, forces the buffer to be cache line aligned (32 bytes, takes the rest as padding). */ - template consteval Buffer(MemoryType type = MemoryType::NonCached, MemoryDomain domain = MemoryDomain::D2, bool force_cache_alignment = false) requires(std::is_standard_layout_v && std::is_trivial_v) : e{ domain, type, - force_cache_alignment ? std::max(std::size_t(32), alignof(T)) : alignof(T), + force_cache_alignment ? 32 : alignof(T), sizeof(T)} { static_assert(alignof(T) <= 32, "Requested type has alignment greater than cache line size (32 bytes)."); @@ -69,155 +70,365 @@ struct MPUDomain { } }; + static constexpr std::size_t max_instances = HALAL_MPUBUFFERS_MAX_INSTANCES; struct Config { - uint32_t base_address; - + uint32_t offset; // Offset relative to the start of the domain buffer std::size_t size; + MemoryDomain domain; + + // MPU Configuration Data + bool is_mpu_leader; // If true, this entry triggers an MPU region config with the below params + uint8_t mpu_number; // MPU Region Number + uint8_t mpu_size; // Encoded Size (e.g. MPU_REGION_SIZE_256B) + uint8_t mpu_subregion; // Subregion Disable Mask + }; + + // Helper to calculate sizes needed for static arrays + struct DomainSizes { + size_t d1_total = 0; + size_t d2_total = 0; + size_t d3_total = 0; - // MPU Config Data - bool is_mpu_leader; - MPU_Region_InitTypeDef mpu_init; + size_t d1_nc_size = 0; + size_t d2_nc_size = 0; + size_t d3_nc_size = 0; }; - // 5. Build compile-time: Entry[] → Config[] - // - // IMPORTANTE: - // - Esta función es consteval: se ejecuta en tiempo de compilación. - // - Aquí es donde se hacen TODAS las validaciones estáticas sobre los Entry. - // + static consteval uint32_t align_up(uint32_t val, size_t align) { + return (val + align - 1) & ~(align - 1); // Align up to 'align' leaving the minimum padding + } + + static consteval DomainSizes calculate_total_sizes(std::span entries) { + DomainSizes sizes; + size_t counters[3] = {}; + + size_t alignments[] = {32, 16, 8, 4, 2, 1}; + + /* Non-Cached Pass */ + for (size_t align : alignments) { + for (const auto& entry : entries) { + if (entry.memory_type == MemoryType::NonCached && entry.alignment == align) { + size_t idx = static_cast(entry.memory_domain) - 1; + counters[idx].val = align_up(counters[idx].val, align); + counters[idx].val += entry.size_in_bytes; + } + } + } + + // Align Non-Cached section end to the actual MPU Region boundary + // This ensures the Cached section starts exactly where the Non-Cached MPU region ends (or effectively ends via subregions) + for(int i=0; i<3; i++) { + if (counters[i] > 0) { + auto [r_size, r_sub] = get_size_needed(counters[i]); + + // Store the raw MPU region size for alignment purposes + if(i==0) sizes.d1_nc_size = r_size; + if(i==1) sizes.d2_nc_size = r_size; + if(i==2) sizes.d3_nc_size = r_size; + + counters[i] = r_size / 8 * (8 - std::popcount(r_sub)); // Effective used size considering subregions disabled + counters[i] = align_up(counters[i], 32); // Align to 32 bytes just in case + } + } + + /* Cached Pass */ + for (size_t align : alignments) { + for (const auto& entry : entries) { // Inneficient but consteval is fine, easier to read + if (entry.memory_type == MemoryType::Cached && entry.alignment == align) { + size_t idx = static_cast(entry.memory_domain) - 1; + counters[idx].val = align_up(counters[idx].val, align); + counters[idx].val += entry.size_in_bytes; + } + } + } + + // Align final total to 32 bytes just in case + sizes.d1_total = align_up(counters[0].val, 32); + sizes.d2_total = align_up(counters[1].val, 32); + sizes.d3_total = align_up(counters[2].val, 32); + return sizes; + } + template static consteval std::array build(std::span entries) { std::array cfgs{}; + + uint32_t offsets[3] = {}; // D1, D2, D3 + uint32_t assigned_offsets[N]; + + size_t alignments[] = {32, 16, 8, 4, 2, 1}; + + /* Non-Cached Offsets */ + for (size_t align : alignments) { + for (size_t i = 0; i < N; i++) { + if (entries[i].memory_type == MemoryType::NonCached && entries[i].alignment == align) { + size_t d_idx = static_cast(entries[i].memory_domain) - 1; + offsets[d_idx] = align_up(offsets[d_idx], align); + assigned_offsets[i] = offsets[d_idx]; + offsets[d_idx] += entries[i].size_in_bytes; + } + } + } + + // Capture Non-Cached Sizes for MPU and adjust offsets for Cached data + size_t nc_sizes[3]; + for(int i=0; i<3; i++) { + if (offsets[i] > 0) { + auto [r_size, r_sub] = get_size_needed(offsets[i]); + nc_sizes[i] = offsets[i]; + + // Move the offset pointer to the end of the MPU region block to have Cached data start after it + offsets[i] = r_size / 8 * (8 - std::popcount(r_sub)); // Effective used size considering subregions disabled + offsets[i] = align_up(offsets[i], 32); // Align to 32 bytes just in case + } else { + nc_sizes[i] = 0; + } + } + + /* Cached Offsets */ + for (size_t align : alignments) { + for (size_t i = 0; i < N; i++) { + if (entries[i].memory_type == MemoryType::Cached && entries[i].alignment == align) { + size_t d_idx = static_cast(entries[i].memory_domain) - 1; + offsets[d_idx] = align_up(offsets[d_idx], align); + assigned_offsets[i] = offsets[d_idx]; + offsets[d_idx] += entries[i].size_in_bytes; + } + } + } + + /* Build Configs */ + bool domain_configured[3] = {false, false, false}; for (std::size_t i = 0; i < N; i++) { - const Entry &e = entries[i]; - - // Aquí se pueden hacer checks globales y locales: - // - Comprobar que no se repite el mismo recurso. - // - Verificar que el recurso es válido para este dominio. - // - Validar que la combinación de parámetros tiene sentido. - - // Ejemplo de patrón (pseudo-código): - // for (std::size_t j = 0; j < i; ++j) { - // if (entries[j].pin == e.pin && entries[j].port == e.port) { - // struct duplicate_resource {}; - // throw duplicate_resource{}; - // } - // } - - // A partir de 'e' se construye cfgs[i] con los datos necesarios - // para configurar el hardware en tiempo de ejecución. - // cfgs[i] = ...; + cfgs[i].size = entries[i].size_in_bytes; + cfgs[i].domain = entries[i].memory_domain; + cfgs[i].offset = assigned_offsets[i]; + cfgs[i].is_mpu_leader = false; + + if (entries[i].memory_type == MemoryType::NonCached) { + size_t d_idx = static_cast(entries[i].memory_domain) - 1; + if (!domain_configured[d_idx]) { + // This entry is the "Leader" responsible for configuring the MPU region for the whole domain + cfgs[i].is_mpu_leader = true; + domain_configured[d_idx] = true; + + auto [r_size, r_sub] = get_size_needed(nc_sizes[d_idx]); + cfgs[i].mpu_size = get_region_size_encoding(r_size); + cfgs[i].mpu_subregion = r_sub; + cfgs[i].mpu_number = (d_idx == 0) ? MPU_REGION_NUMBER3 : + (d_idx == 1) ? MPU_REGION_NUMBER5 : MPU_REGION_NUMBER7; + } + } } return cfgs; } struct Instance { + void* ptr; + std::size_t size; - /** - * @brief Constructs the object of type T in the allocated MPU memory. - * @param args Arguments to forward to T's constructor. - * @return Pointer to the constructed object of type T. - */ template T* construct(Args&&... args) { - is_valid_type(); - return new (ptr) T(std::forward(args)...); // Placement new + validate(); + return new (ptr) T(std::forward(args)...); } - /** - * @brief Casts the stored pointer to the desired type T. - * @tparam T The type to cast the pointer to. - * @return Pointer of type T. - */ template T* as() { - is_valid_type(); + validate(); return static_cast(ptr); } private: - template friend struct Init; - template - void is_valid_type() { - static_assert(std::is_standard_layout_v && std::is_trivial_v, - "MPU Buffer can only store POD types (standard layout and trivial)."); - if (sizeof(T) > size) { - ErrorHandler("Requested type size exceeds allocated MPU buffer size."); - } - if (reinterpret_cast(ptr) % alignof(T) != 0) { - ErrorHandler("Requested type alignment is not satisfied by allocated MPU buffer."); - } + void validate() { + if (sizeof(T) != size) ErrorHandler("MPU: Buffer size mismatch."); + if (reinterpret_cast(ptr) % alignof(T) != 0) ErrorHandler("MPU: Buffer alignment mismatch."); } - - void* ptr; - std::size_t size; - Instance() : ptr{nullptr}, size{0} {} }; - // 7. Inicialización runtime: aplica Config → crea Instance[] + template struct Init { static inline std::array instances{}; + static constexpr auto Sizes = calculate_total_sizes(Entries); + + // --- Actual Storage (Placed by Linker) --- + // These sections must be defined in the Linker Script. + // They will be placed automatically, avoiding conflicts with other data. + // Alignment must match the MPU region size for Non-Cached areas. + static constexpr size_t d1_align = Sizes.d1_nc_size > 0 ? Sizes.d1_nc_size : 32; + static constexpr size_t d2_align = Sizes.d2_nc_size > 0 ? Sizes.d2_nc_size : 32; + static constexpr size_t d3_align = Sizes.d3_nc_size > 0 ? Sizes.d3_nc_size : 32; + + static inline alignas(d1_align) uint8_t d1_nc_buffer[Sizes.d1_total > 0 ? Sizes.d1_total : 1] __attribute__((section(".mpu_ram_d1_nc"))); + static inline alignas(d2_align) uint8_t d2_nc_buffer[Sizes.d2_total > 0 ? Sizes.d2_total : 1] __attribute__((section(".mpu_ram_d2_nc"))); + static inline alignas(d3_align) uint8_t d3_nc_buffer[Sizes.d3_total > 0 ? Sizes.d3_total : 1] __attribute__((section(".mpu_ram_d3_nc"))); - // Esta función se llama desde Board::init() en TIEMPO DE EJECUCIÓN. - // Aquí ya no se hacen checks de diseño: solo se aplica la configuración - // generada en compile-time y se llama a HAL/LL. static void init(std::span cfgs) { + HAL_MPU_Disable(); + configure_static_regions(); + + uint8_t* bases[3] = { &d1_nc_buffer[0], &d2_nc_buffer[0], &d3_nc_buffer[0] }; + for (std::size_t i = 0; i < N; i++) { const auto &cfg = cfgs[i]; auto &inst = instances[i]; - // Inicializar 'inst' a partir de 'cfg': - // - llamadas a HAL/LL - // - set de registros, punteros a periféricos, etc. + if (cfg.domain == MemoryDomain::D1 || cfg.domain == MemoryDomain::D2 || cfg.domain == MemoryDomain::D3) { + size_t d_idx = static_cast(cfg.domain) - 1; + // Calculate absolute address: Base + Offset + inst.ptr = bases[d_idx] + cfg.offset; + inst.size = cfg.size; + + if (cfg.is_mpu_leader) { + MPU_Region_InitTypeDef init = {0}; + init.Enable = MPU_REGION_ENABLE; + init.Number = cfg.mpu_number; + init.BaseAddress = (uint32_t)bases[d_idx]; // Base of the whole buffer + init.Size = cfg.mpu_size; + init.SubRegionDisable = cfg.mpu_subregion; + init.TypeExtField = MPU_TEX_LEVEL1; // Normal, Non-Cached + init.AccessPermission = MPU_REGION_FULL_ACCESS; + init.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + init.IsShareable = MPU_ACCESS_SHAREABLE; + init.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + init.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + HAL_MPU_ConfigRegion(&init); + } + } } + + HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); + SCB_EnableICache(); + SCB_EnableDCache(); } }; private: - static consteval uint32_t get_address(MemoryDomain domain, std::size_t offset) { - switch (domain) { - case MemoryDomain::D1: - return 0x24000000 + static_cast(offset); - case MemoryDomain::D2: - return 0x30000000 + static_cast(offset); - case MemoryDomain::D3: - return 0x38000000 + static_cast(offset); - default: - throw "Invalid Memory Domain"; - } + static consteval std::pair get_size_needed(std::size_t size) { + if (size == 0) return {32, 0xFF}; + size_t power = std::bit_width(size); + if (power < 5) power = 5; // Min 32B + size_t subregion_size = 1U << (power - 3); + size_t num_subregions = (size + subregion_size - 1) / subregion_size; + uint8_t subregion_disable = static_cast(~((1U << num_subregions) - 1)); + return {(1U << power), subregion_disable}; } - static consteval uint32_t align_up(uint32_t address, std::size_t alignment) { - uint32_t mask = static_cast(alignment - 1); - return (address + mask) & ~mask; + static consteval uint8_t get_region_size_encoding(std::size_t size) { + if (size <= 32) return MPU_REGION_SIZE_32B; + if (size <= 64) return MPU_REGION_SIZE_64B; + if (size <= 128) return MPU_REGION_SIZE_128B; + if (size <= 256) return MPU_REGION_SIZE_256B; + if (size <= 512) return MPU_REGION_SIZE_512B; + if (size <= 1024) return MPU_REGION_SIZE_1KB; + if (size <= 2048) return MPU_REGION_SIZE_2KB; + if (size <= 4096) return MPU_REGION_SIZE_4KB; + if (size <= 8192) return MPU_REGION_SIZE_8KB; + if (size <= 16384) return MPU_REGION_SIZE_16KB; + if (size <= 32768) return MPU_REGION_SIZE_32KB; + if (size <= 65536) return MPU_REGION_SIZE_64KB; + if (size <= 131072) return MPU_REGION_SIZE_128KB; + if (size <= 262144) return MPU_REGION_SIZE_256KB; + if (size <= 524288) return MPU_REGION_SIZE_512KB; + if (size <= 1048576) return MPU_REGION_SIZE_1MB; + if (size <= 2097152) return MPU_REGION_SIZE_2MB; + if (size <= 4194304) return MPU_REGION_SIZE_4MB; + return MPU_REGION_SIZE_4GB; } - static consteval std::pair get_size_needed(std::size_t size) { - // Get next power of two - if (std::popcount(size) == 1) { - return {size, 0}; - } else { - size_t power = 1 + std::countl_zero(size); - - if (power < 5) { - power = 5; // Minimum MPU region size is 32 bytes - } + static void configure_static_regions() { + MPU_Region_InitTypeDef MPU_InitStruct = {0}; + + // Background (No Access) + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER0; + MPU_InitStruct.BaseAddress = 0x0; + MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; + MPU_InitStruct.SubRegionDisable = 0x87; + MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + // Flash (Non-cached, Executable) + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER1; + MPU_InitStruct.BaseAddress = 0x08000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_1MB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; // This should be scrutinized to see why it was non-cacheable before changing to cacheable + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + // D1 RAM (Cached) + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER2; + MPU_InitStruct.BaseAddress = 0x24000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; + MPU_InitStruct.SubRegionDisable = 0xE0; // Only 320KB available + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + // D2 RAM (Cached) + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER4; + MPU_InitStruct.BaseAddress = 0x30000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_32KB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + // Ethernet Descriptors (D2 Base) - Legacy, should change Ethernet driver to use MPU buffers + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER8; + MPU_InitStruct.BaseAddress = 0x30000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_512B; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; // Device + HAL_MPU_ConfigRegion(&MPU_InitStruct); + + // D3 RAM (Cached) + MPU_InitStruct.Enable = MPU_REGION_ENABLE; + MPU_InitStruct.Number = MPU_REGION_NUMBER6; // FIX: Changed from 5 to 6 to avoid collision with D2 NC + MPU_InitStruct.BaseAddress = 0x38000000; + MPU_InitStruct.Size = MPU_REGION_SIZE_16KB; + MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; + HAL_MPU_ConfigRegion(&MPU_InitStruct); - // MPU can divide to 8 subregions, so try to get a closer size - size_t subregion_size = 1U << (power - 3); - size_t num_subregions = (size + subregion_size - 1) / subregion_size; // Round up division - uint8_t subregion_disable = static_cast(~((1U << num_subregions) - 1)); - static_assert(subregion_disable != 0xFF, "Something isn't working on the MPU region size calculation."); + /** + * Other regions are: + * 3. D1 RAM (Non-Cached) - Configured dynamically + * 5. D2 RAM (Non-Cached) - Configured dynamically + * 7. D3 RAM (Non-Cached) - Configured dynamically + */ - return {subregion_size * num_subregions, subregion_disable}; - } + /** + * Other memory areas (not configured explicitly): + * - Peripheral space (0x40000000 - 0x5FFFFFFF): Defaults to device memory + */ } }; -#endif // MPU_HPP \ No newline at end of file +#endif // MPU_HPP From ed0a65aa8e607eae9302b744b2ea414102cf076b Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 11:07:40 +0100 Subject: [PATCH 13/76] feat(MPU)!: Bug fixing and changes on the infrastructure to allow proper MPU configuration --- Inc/HALAL/HALAL.hpp | 1 + Inc/HALAL/Models/MPU.hpp | 83 +++++++++++++++------------------------- Inc/ST-LIB.hpp | 8 +++- 3 files changed, 39 insertions(+), 53 deletions(-) diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index 316c9605a..1cab3c0b1 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -36,6 +36,7 @@ #include "HALAL/Services/FMAC/FMAC.hpp" #include "HALAL/Models/MPUManager/MPUManager.hpp" +#include "HALAL/Models/MPU.hpp" #include "HALAL/Services/InfoWarning/InfoWarning.hpp" #include "HALAL/Services/Watchdog/Watchdog.hpp" diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index 2b43ff998..dcaea81dc 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -82,6 +82,7 @@ struct MPUDomain { bool is_mpu_leader; // If true, this entry triggers an MPU region config with the below params uint8_t mpu_number; // MPU Region Number uint8_t mpu_size; // Encoded Size (e.g. MPU_REGION_SIZE_256B) + std::size_t mpu_region_size; // Actual size in bytes of the MPU region uint8_t mpu_subregion; // Subregion Disable Mask }; @@ -100,54 +101,25 @@ struct MPUDomain { return (val + align - 1) & ~(align - 1); // Align up to 'align' leaving the minimum padding } - static consteval DomainSizes calculate_total_sizes(std::span entries) { - DomainSizes sizes; - size_t counters[3] = {}; - - size_t alignments[] = {32, 16, 8, 4, 2, 1}; - - /* Non-Cached Pass */ - for (size_t align : alignments) { - for (const auto& entry : entries) { - if (entry.memory_type == MemoryType::NonCached && entry.alignment == align) { - size_t idx = static_cast(entry.memory_domain) - 1; - counters[idx].val = align_up(counters[idx].val, align); - counters[idx].val += entry.size_in_bytes; - } - } - } - - // Align Non-Cached section end to the actual MPU Region boundary - // This ensures the Cached section starts exactly where the Non-Cached MPU region ends (or effectively ends via subregions) - for(int i=0; i<3; i++) { - if (counters[i] > 0) { - auto [r_size, r_sub] = get_size_needed(counters[i]); - - // Store the raw MPU region size for alignment purposes - if(i==0) sizes.d1_nc_size = r_size; - if(i==1) sizes.d2_nc_size = r_size; - if(i==2) sizes.d3_nc_size = r_size; - counters[i] = r_size / 8 * (8 - std::popcount(r_sub)); // Effective used size considering subregions disabled - counters[i] = align_up(counters[i], 32); // Align to 32 bytes just in case - } - } - - /* Cached Pass */ - for (size_t align : alignments) { - for (const auto& entry : entries) { // Inneficient but consteval is fine, easier to read - if (entry.memory_type == MemoryType::Cached && entry.alignment == align) { - size_t idx = static_cast(entry.memory_domain) - 1; - counters[idx].val = align_up(counters[idx].val, align); - counters[idx].val += entry.size_in_bytes; - } + static consteval DomainSizes calculate_total_sizes(std::span configs) { + DomainSizes sizes; + for (const auto& cfg : configs) { + size_t end = cfg.offset + cfg.size; + if (cfg.domain == MemoryDomain::D1) sizes.d1_total = std::max(sizes.d1_total, end); + else if (cfg.domain == MemoryDomain::D2) sizes.d2_total = std::max(sizes.d2_total, end); + else if (cfg.domain == MemoryDomain::D3) sizes.d3_total = std::max(sizes.d3_total, end); + + if (cfg.is_mpu_leader) { + if (cfg.domain == MemoryDomain::D1) sizes.d1_nc_size = cfg.mpu_region_size; + else if (cfg.domain == MemoryDomain::D2) sizes.d2_nc_size = cfg.mpu_region_size; + else if (cfg.domain == MemoryDomain::D3) sizes.d3_nc_size = cfg.mpu_region_size; } } - - // Align final total to 32 bytes just in case - sizes.d1_total = align_up(counters[0].val, 32); - sizes.d2_total = align_up(counters[1].val, 32); - sizes.d3_total = align_up(counters[2].val, 32); + // Align totals to 32 bytes + sizes.d1_total = align_up(sizes.d1_total, 32); + sizes.d2_total = align_up(sizes.d2_total, 32); + sizes.d3_total = align_up(sizes.d3_total, 32); return sizes; } @@ -207,6 +179,7 @@ struct MPUDomain { cfgs[i].domain = entries[i].memory_domain; cfgs[i].offset = assigned_offsets[i]; cfgs[i].is_mpu_leader = false; + cfgs[i].mpu_region_size = 0; if (entries[i].memory_type == MemoryType::NonCached) { size_t d_idx = static_cast(entries[i].memory_domain) - 1; @@ -218,6 +191,7 @@ struct MPUDomain { auto [r_size, r_sub] = get_size_needed(nc_sizes[d_idx]); cfgs[i].mpu_size = get_region_size_encoding(r_size); cfgs[i].mpu_subregion = r_sub; + cfgs[i].mpu_region_size = r_size; // Store for Init alignment cfgs[i].mpu_number = (d_idx == 0) ? MPU_REGION_NUMBER3 : (d_idx == 1) ? MPU_REGION_NUMBER5 : MPU_REGION_NUMBER7; } @@ -251,11 +225,13 @@ struct MPUDomain { } }; - - template + + template cfgs> struct Init { static inline std::array instances{}; - static constexpr auto Sizes = calculate_total_sizes(Entries); + + // Calculate sizes at compile time from the template parameter + static constexpr auto Sizes = calculate_total_sizes(cfgs); // --- Actual Storage (Placed by Linker) --- // These sections must be defined in the Linker Script. @@ -265,11 +241,14 @@ struct MPUDomain { static constexpr size_t d2_align = Sizes.d2_nc_size > 0 ? Sizes.d2_nc_size : 32; static constexpr size_t d3_align = Sizes.d3_nc_size > 0 ? Sizes.d3_nc_size : 32; - static inline alignas(d1_align) uint8_t d1_nc_buffer[Sizes.d1_total > 0 ? Sizes.d1_total : 1] __attribute__((section(".mpu_ram_d1_nc"))); - static inline alignas(d2_align) uint8_t d2_nc_buffer[Sizes.d2_total > 0 ? Sizes.d2_total : 1] __attribute__((section(".mpu_ram_d2_nc"))); - static inline alignas(d3_align) uint8_t d3_nc_buffer[Sizes.d3_total > 0 ? Sizes.d3_total : 1] __attribute__((section(".mpu_ram_d3_nc"))); + __attribute__((section(".mpu_ram_d1_nc"))) alignas(d1_align) + static inline uint8_t d1_nc_buffer[Sizes.d1_total > 0 ? Sizes.d1_total : 1]; + __attribute__((section(".mpu_ram_d2_nc"))) alignas(d2_align) + static inline uint8_t d2_nc_buffer[Sizes.d2_total > 0 ? Sizes.d2_total : 1]; + __attribute__((section(".mpu_ram_d3_nc"))) alignas(d3_align) + static inline uint8_t d3_nc_buffer[Sizes.d3_total > 0 ? Sizes.d3_total : 1]; - static void init(std::span cfgs) { + static void init() { HAL_MPU_Disable(); configure_static_regions(); diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 32fb54814..0c1017653 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -71,7 +71,7 @@ template struct BuildCtx { }; using DomainsCtx = BuildCtx; + DigitalInputDomain, MPUDomain /*, ADCDomain, PWMDomain, ...*/>; template struct Board { static consteval auto build_ctx() { @@ -90,12 +90,14 @@ template struct Board { constexpr std::size_t gpioN = domain_size(); constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); + constexpr std::size_t mpuN = domain_size(); // ... struct ConfigBundle { std::array gpio_cfgs; std::array dout_cfgs; std::array din_cfgs; + std::array mpu_cfgs; // ... }; @@ -106,6 +108,8 @@ template struct Board { ctx.template span()), .din_cfgs = DigitalInputDomain::template build( ctx.template span()), + .mpu_cfgs = MPUDomain::template build( + ctx.template span()) // ... }; } @@ -116,6 +120,7 @@ template struct Board { constexpr std::size_t gpioN = domain_size(); constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); + constexpr std::size_t mpuN = domain_size(); // ... GPIODomain::Init::init(cfg.gpio_cfgs); @@ -123,6 +128,7 @@ template struct Board { GPIODomain::Init::instances); DigitalInputDomain::Init::init(cfg.din_cfgs, GPIODomain::Init::instances); + MPUDomain::Init::init(); // ... } From aa7dddc3f4c4d6b890b9096767a0d85965a34b45 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 12:52:40 +0100 Subject: [PATCH 14/76] reafactor(MPU): Support legacy MPUManager without conflicts --- Inc/HALAL/Models/MPU.hpp | 28 ++++++++- Inc/HALAL/Models/MPUManager/MPUManager.hpp | 68 +--------------------- 2 files changed, 26 insertions(+), 70 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index dcaea81dc..0898b7d39 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -16,6 +16,7 @@ #include "C++Utilities/CppImports.hpp" #include "ErrorHandler/ErrorHandler.hpp" #include "stm32h7xx_hal.h" +#include "HALAL/Models/MPUManager/MPUManager.hpp" struct MPUDomain { @@ -240,19 +241,40 @@ struct MPUDomain { static constexpr size_t d1_align = Sizes.d1_nc_size > 0 ? Sizes.d1_nc_size : 32; static constexpr size_t d2_align = Sizes.d2_nc_size > 0 ? Sizes.d2_nc_size : 32; static constexpr size_t d3_align = Sizes.d3_nc_size > 0 ? Sizes.d3_nc_size : 32; + static constexpr size_t legacy_size = NO_CACHED_RAM_MAXIMUM_SPACE; __attribute__((section(".mpu_ram_d1_nc"))) alignas(d1_align) static inline uint8_t d1_nc_buffer[Sizes.d1_total > 0 ? Sizes.d1_total : 1]; __attribute__((section(".mpu_ram_d2_nc"))) alignas(d2_align) static inline uint8_t d2_nc_buffer[Sizes.d2_total > 0 ? Sizes.d2_total : 1]; - __attribute__((section(".mpu_ram_d3_nc"))) alignas(d3_align) - static inline uint8_t d3_nc_buffer[Sizes.d3_total > 0 ? Sizes.d3_total : 1]; + __attribute__((section(".mpu_ram_d3_nc"))) alignas(std::max(d3_align, legacy_size)) + static inline uint8_t d3_nc_buffer[(Sizes.d3_total > 0 ? Sizes.d3_total : 0) + legacy_size]; static void init() { HAL_MPU_Disable(); configure_static_regions(); - uint8_t* bases[3] = { &d1_nc_buffer[0], &d2_nc_buffer[0], &d3_nc_buffer[0] }; + // Configure Legacy MPUManager Region (D3 Non-Cached) + // We place it at the beginning of d3_nc_buffer + MPU_Region_InitTypeDef Legacy_InitStruct = {0}; + Legacy_InitStruct.Enable = MPU_REGION_ENABLE; + Legacy_InitStruct.Number = MPU_REGION_NUMBER9; // Use a high region number to override D3 Cached + Legacy_InitStruct.BaseAddress = (uint32_t)&d3_nc_buffer[0]; + Legacy_InitStruct.Size = get_region_size_encoding(legacy_size); + Legacy_InitStruct.SubRegionDisable = 0x0; + Legacy_InitStruct.TypeExtField = MPU_TEX_LEVEL1; + Legacy_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; + Legacy_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + Legacy_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; + Legacy_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; + Legacy_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + HAL_MPU_ConfigRegion(&Legacy_InitStruct); + + // Set the legacy pointer + MPUManager::no_cached_ram_start = &d3_nc_buffer[0]; + + // Adjust bases for new buffers (they start after legacy_size) + uint8_t* bases[3] = { &d1_nc_buffer[0], &d2_nc_buffer[0], &d3_nc_buffer[legacy_size] }; for (std::size_t i = 0; i < N; i++) { const auto &cfg = cfgs[i]; diff --git a/Inc/HALAL/Models/MPUManager/MPUManager.hpp b/Inc/HALAL/Models/MPUManager/MPUManager.hpp index 9b63f46e2..73493fa1b 100644 --- a/Inc/HALAL/Models/MPUManager/MPUManager.hpp +++ b/Inc/HALAL/Models/MPUManager/MPUManager.hpp @@ -5,75 +5,9 @@ #define NO_CACHED_RAM_MAXIMUM_SPACE 2048 -extern unsigned long _no_cached_ram_start; - - class MPUManager{ + friend struct MPUDomain; public: - static struct config{ - bool using_cache = true; - }MPUConfig;/**< MPU configuration defined un Runes.hpp*/ - - static void start(){ - MPU_Region_InitTypeDef MPU_InitStruct = {0}; - HAL_MPU_Disable(); - - MPU_InitStruct.Enable = MPU_REGION_ENABLE; - MPU_InitStruct.Number = MPU_REGION_NUMBER0; - MPU_InitStruct.BaseAddress = 0x0; - MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; - MPU_InitStruct.SubRegionDisable = 0x87; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; - MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; - MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; - MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; - MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - /** Initializes and configures the Region and the memory to be protected - */ - MPU_InitStruct.Number = MPU_REGION_NUMBER1; - MPU_InitStruct.BaseAddress = 0x30000000; - MPU_InitStruct.Size = MPU_REGION_SIZE_32KB; - MPU_InitStruct.SubRegionDisable = 0x0; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - /** Initializes and configures the Region and the memory to be protected - */ - MPU_InitStruct.Number = MPU_REGION_NUMBER2; - MPU_InitStruct.Size = MPU_REGION_SIZE_512B; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; - MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; - MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - /** Initializes and configures the Region and the memory to be protected - */ - MPU_InitStruct.Number = MPU_REGION_NUMBER3; - MPU_InitStruct.BaseAddress = 0x08000000; - MPU_InitStruct.Size = MPU_REGION_SIZE_1MB; - MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; - MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - - MPU_InitStruct.Number = MPU_REGION_NUMBER4; - MPU_InitStruct.BaseAddress = 0x38000000; - MPU_InitStruct.Size = MPU_REGION_SIZE_16KB; - MPU_InitStruct.SubRegionDisable = 0x0; - MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; - MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; - MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; - HAL_MPU_ConfigRegion(&MPU_InitStruct); - /* Enables the MPU */ - HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); - - if(MPUConfig.using_cache){ - SCB_EnableICache(); - SCB_EnableDCache(); - } - } - static void* allocate_non_cached_memory(uint32_t size){ void* buffer = (void*)((uint8_t*)no_cached_ram_start + no_cached_ram_occupied_bytes); no_cached_ram_occupied_bytes = no_cached_ram_occupied_bytes + size; From 3f826bd3a7c50c8d53112b4f26467c9b444bc5e3 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 12:53:47 +0100 Subject: [PATCH 15/76] fix(MPU): Remove MPUManager start call from HALAL init --- Src/HALAL/HALAL.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/HALAL/HALAL.cpp b/Src/HALAL/HALAL.cpp index 2ee470ed9..2a98eb062 100644 --- a/Src/HALAL/HALAL.cpp +++ b/Src/HALAL/HALAL.cpp @@ -20,7 +20,6 @@ static void common_start(UART::Peripheral &printf_peripheral) { Watchdog::check_reset_flag(); #endif - MPUManager::start(); HAL_Init(); HALconfig::system_clock(); HALconfig::peripheral_clock(); From 6c2829483ac6938aea52996123271d47cc79e197 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 21:54:00 +0100 Subject: [PATCH 16/76] feat(MPU): Modify linker scripts for MPU configuration --- STM32H723ZGTX_FLASH.ld | 26 +++++++++++++++++++++----- STM32H723ZGTX_RAM.ld | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/STM32H723ZGTX_FLASH.ld b/STM32H723ZGTX_FLASH.ld index 12b8d7793..a5bf2e7e0 100644 --- a/STM32H723ZGTX_FLASH.ld +++ b/STM32H723ZGTX_FLASH.ld @@ -170,6 +170,13 @@ SECTIONS __bss_end__ = _ebss; } >RAM_D1 + .mpu_ram_d1_nc : + { + . = ALIGN(32); + *(.mpu_ram_d1_nc) + . = ALIGN(32); + } >RAM_D1 + /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : { @@ -191,12 +198,21 @@ SECTIONS *(.TxDecripSection) } >RAM_D2 - .stlib_no_cache_ram_pool : + + .mpu_ram_d2_nc : { - . = ABSOLUTE(0x38000000); - _no_cached_ram_start = .; - + . = ALIGN(32); + *(.mpu_ram_d2_nc) + . = ALIGN(32); + } >RAM_D2 + + .mpu_ram_d3_nc : + { + . = ALIGN(32); + *(.mpu_ram_d3_nc) + . = ALIGN(32); } >RAM_D3 + /* Remove information from the standard libraries */ /DISCARD/ : { @@ -206,4 +222,4 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } -} +} \ No newline at end of file diff --git a/STM32H723ZGTX_RAM.ld b/STM32H723ZGTX_RAM.ld index 4d2e09c43..da990d738 100644 --- a/STM32H723ZGTX_RAM.ld +++ b/STM32H723ZGTX_RAM.ld @@ -119,6 +119,13 @@ SECTIONS PROVIDE_HIDDEN (__fini_array_end = .); } >RAM_EXEC + .mpu_ram_d1_nc : + { + . = ALIGN(32); + *(.mpu_ram_d1_nc) + . = ALIGN(32); + } >RAM_EXEC + /* used by the startup to initialize data */ _sidata = LOADADDR(.data); @@ -161,6 +168,20 @@ SECTIONS . = ALIGN(8); } >DTCMRAM + .mpu_ram_d2_nc : + { + . = ALIGN(32); + *(.mpu_ram_d2_nc) + . = ALIGN(32); + } >RAM_D2 + + .mpu_ram_d3_nc : + { + . = ALIGN(32); + *(.mpu_ram_d3_nc) + . = ALIGN(32); + } >RAM_D3 + /* Remove information from the standard libraries */ /DISCARD/ : { @@ -170,4 +191,4 @@ SECTIONS } .ARM.attributes 0 : { *(.ARM.attributes) } -} +} \ No newline at end of file From 4352de3229e8e61ea08dce8ce61d9ff975a2164a Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 21:54:19 +0100 Subject: [PATCH 17/76] fix(MPU): Remove legacy things --- Src/HALAL/Models/MPUManager/MPUManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/HALAL/Models/MPUManager/MPUManager.cpp b/Src/HALAL/Models/MPUManager/MPUManager.cpp index c9ef34ca5..b45d8d4b2 100644 --- a/Src/HALAL/Models/MPUManager/MPUManager.cpp +++ b/Src/HALAL/Models/MPUManager/MPUManager.cpp @@ -1,4 +1,3 @@ #include "HALAL/Models/MPUManager/MPUManager.hpp" -void* MPUManager::no_cached_ram_start = (void*)&_no_cached_ram_start; uint32_t MPUManager::no_cached_ram_occupied_bytes = 0; From 5d0dbd02b5ea2fe601444fc3f0fc4ec7a065a942 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 22:20:05 +0100 Subject: [PATCH 18/76] fix(MPU): Fix legacy MPUManager --- Src/HALAL/Models/MPUManager/MPUManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/HALAL/Models/MPUManager/MPUManager.cpp b/Src/HALAL/Models/MPUManager/MPUManager.cpp index b45d8d4b2..99bf036d0 100644 --- a/Src/HALAL/Models/MPUManager/MPUManager.cpp +++ b/Src/HALAL/Models/MPUManager/MPUManager.cpp @@ -1,3 +1,4 @@ #include "HALAL/Models/MPUManager/MPUManager.hpp" +void* MPUManager::no_cached_ram_start = nullptr; uint32_t MPUManager::no_cached_ram_occupied_bytes = 0; From a365558a9f7184909c3b3b4938609764c1cbde36 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 22:20:21 +0100 Subject: [PATCH 19/76] fix(MPU): Fix no buffer array of size zero issue --- Inc/HALAL/Models/MPU.hpp | 130 ++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index 0898b7d39..a0ea766f0 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -126,80 +126,84 @@ struct MPUDomain { template static consteval std::array build(std::span entries) { - std::array cfgs{}; - - uint32_t offsets[3] = {}; // D1, D2, D3 - uint32_t assigned_offsets[N]; - - size_t alignments[] = {32, 16, 8, 4, 2, 1}; - - /* Non-Cached Offsets */ - for (size_t align : alignments) { - for (size_t i = 0; i < N; i++) { - if (entries[i].memory_type == MemoryType::NonCached && entries[i].alignment == align) { - size_t d_idx = static_cast(entries[i].memory_domain) - 1; - offsets[d_idx] = align_up(offsets[d_idx], align); - assigned_offsets[i] = offsets[d_idx]; - offsets[d_idx] += entries[i].size_in_bytes; + if constexpr (N == 0) { + return {}; + } else { + std::array cfgs{}; + + uint32_t offsets[3] = {}; // D1, D2, D3 + uint32_t assigned_offsets[N]; + + size_t alignments[] = {32, 16, 8, 4, 2, 1}; + + /* Non-Cached Offsets */ + for (size_t align : alignments) { + for (size_t i = 0; i < N; i++) { + if (entries[i].memory_type == MemoryType::NonCached && entries[i].alignment == align) { + size_t d_idx = static_cast(entries[i].memory_domain) - 1; + offsets[d_idx] = align_up(offsets[d_idx], align); + assigned_offsets[i] = offsets[d_idx]; + offsets[d_idx] += entries[i].size_in_bytes; + } } } - } - // Capture Non-Cached Sizes for MPU and adjust offsets for Cached data - size_t nc_sizes[3]; - for(int i=0; i<3; i++) { - if (offsets[i] > 0) { - auto [r_size, r_sub] = get_size_needed(offsets[i]); - nc_sizes[i] = offsets[i]; - - // Move the offset pointer to the end of the MPU region block to have Cached data start after it - offsets[i] = r_size / 8 * (8 - std::popcount(r_sub)); // Effective used size considering subregions disabled - offsets[i] = align_up(offsets[i], 32); // Align to 32 bytes just in case - } else { - nc_sizes[i] = 0; + // Capture Non-Cached Sizes for MPU and adjust offsets for Cached data + size_t nc_sizes[3]; + for(int i=0; i<3; i++) { + if (offsets[i] > 0) { + auto [r_size, r_sub] = get_size_needed(offsets[i]); + nc_sizes[i] = offsets[i]; + + // Move the offset pointer to the end of the MPU region block to have Cached data start after it + offsets[i] = r_size / 8 * (8 - std::popcount(r_sub)); // Effective used size considering subregions disabled + offsets[i] = align_up(offsets[i], 32); // Align to 32 bytes just in case + } else { + nc_sizes[i] = 0; + } } - } - /* Cached Offsets */ - for (size_t align : alignments) { - for (size_t i = 0; i < N; i++) { - if (entries[i].memory_type == MemoryType::Cached && entries[i].alignment == align) { - size_t d_idx = static_cast(entries[i].memory_domain) - 1; - offsets[d_idx] = align_up(offsets[d_idx], align); - assigned_offsets[i] = offsets[d_idx]; - offsets[d_idx] += entries[i].size_in_bytes; + /* Cached Offsets */ + for (size_t align : alignments) { + for (size_t i = 0; i < N; i++) { + if (entries[i].memory_type == MemoryType::Cached && entries[i].alignment == align) { + size_t d_idx = static_cast(entries[i].memory_domain) - 1; + offsets[d_idx] = align_up(offsets[d_idx], align); + assigned_offsets[i] = offsets[d_idx]; + offsets[d_idx] += entries[i].size_in_bytes; + } } } - } - /* Build Configs */ - bool domain_configured[3] = {false, false, false}; - - for (std::size_t i = 0; i < N; i++) { - cfgs[i].size = entries[i].size_in_bytes; - cfgs[i].domain = entries[i].memory_domain; - cfgs[i].offset = assigned_offsets[i]; - cfgs[i].is_mpu_leader = false; - cfgs[i].mpu_region_size = 0; - - if (entries[i].memory_type == MemoryType::NonCached) { - size_t d_idx = static_cast(entries[i].memory_domain) - 1; - if (!domain_configured[d_idx]) { - // This entry is the "Leader" responsible for configuring the MPU region for the whole domain - cfgs[i].is_mpu_leader = true; - domain_configured[d_idx] = true; - - auto [r_size, r_sub] = get_size_needed(nc_sizes[d_idx]); - cfgs[i].mpu_size = get_region_size_encoding(r_size); - cfgs[i].mpu_subregion = r_sub; - cfgs[i].mpu_region_size = r_size; // Store for Init alignment - cfgs[i].mpu_number = (d_idx == 0) ? MPU_REGION_NUMBER3 : - (d_idx == 1) ? MPU_REGION_NUMBER5 : MPU_REGION_NUMBER7; + /* Build Configs */ + bool domain_configured[3] = {false, false, false}; + + for (std::size_t i = 0; i < N; i++) { + cfgs[i].size = entries[i].size_in_bytes; + cfgs[i].domain = entries[i].memory_domain; + cfgs[i].offset = assigned_offsets[i]; + cfgs[i].is_mpu_leader = false; + cfgs[i].mpu_region_size = 0; + + if (entries[i].memory_type == MemoryType::NonCached) { + size_t d_idx = static_cast(entries[i].memory_domain) - 1; + if (!domain_configured[d_idx]) { + // This entry is the "Leader" responsible for configuring the MPU region for the whole domain + cfgs[i].is_mpu_leader = true; + domain_configured[d_idx] = true; + + auto [r_size, r_sub] = get_size_needed(nc_sizes[d_idx]); + cfgs[i].mpu_size = get_region_size_encoding(r_size); + cfgs[i].mpu_subregion = r_sub; + cfgs[i].mpu_region_size = r_size; // Store for Init alignment + cfgs[i].mpu_number = (d_idx == 0) ? MPU_REGION_NUMBER3 : + (d_idx == 1) ? MPU_REGION_NUMBER5 : MPU_REGION_NUMBER7; + } } } - } - return cfgs; + return cfgs; + } } struct Instance { From d40a2133ff1145e2de180596b0c80ee1f1578424 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 12 Dec 2025 23:33:36 +0100 Subject: [PATCH 20/76] fix(MPU): Fix ST-LIB so that it accepts templated objects for MPU buffers --- Inc/ST-LIB.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 0c1017653..ebb70246c 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -147,7 +147,9 @@ template struct Board { using DevT = std::remove_cvref_t; if constexpr (std::is_same_v) { if (!found) { - if (&devs == &Target) { + auto dev_ptr = reinterpret_cast(&devs); + auto target_ptr = reinterpret_cast(&Target); + if (dev_ptr == target_ptr) { found = true; } else { ++idx; @@ -176,7 +178,11 @@ template struct Board { constexpr std::size_t idx = domain_index_of(); constexpr std::size_t N = domain_size_for_instance(); - return Domain::template Init::instances[idx]; + if constexpr (std::is_same_v) { + return Domain::template Init::instances[idx]; + } else { + return Domain::template Init::instances[idx]; + } } }; From 6e8eac895dada6ea9ebd146d82c8042da7179116 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sat, 13 Dec 2025 11:49:22 +0100 Subject: [PATCH 21/76] feat(MPU): Add concepts and safer interface --- Inc/HALAL/Models/MPU.hpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index a0ea766f0..84d7ed59f 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -19,6 +19,17 @@ #include "HALAL/Models/MPUManager/MPUManager.hpp" +template +concept mpu_buffer_request = requires(typename T::domain d) { + typename T::buffer_type; + { T{ } } -> std::same_as; +}; + +// POD types only +template +concept mpu_buffer_payload = + std::is_standard_layout_v && std::is_trivial_v; + struct MPUDomain { enum class MemoryDomain : uint8_t { @@ -41,7 +52,7 @@ struct MPUDomain { }; // Buffer Request Wrapper - template + template struct Buffer { using domain = MPUDomain; using buffer_type = T; @@ -55,7 +66,6 @@ struct MPUDomain { * @param force_cache_alignment If true, forces the buffer to be cache line aligned (32 bytes, takes the rest as padding). */ consteval Buffer(MemoryType type = MemoryType::NonCached, MemoryDomain domain = MemoryDomain::D2, bool force_cache_alignment = false) - requires(std::is_standard_layout_v && std::is_trivial_v) : e{ domain, type, @@ -210,24 +220,17 @@ struct MPUDomain { void* ptr; std::size_t size; - template - T* construct(Args&&... args) { - validate(); + template + auto* construct(Args&&... args) { + using T = typename std::remove_cvref_t::buffer_type; return new (ptr) T(std::forward(args)...); } - template - T* as() { - validate(); + template + auto* as() { + using T = typename std::remove_cvref_t::buffer_type; return static_cast(ptr); } - - private: - template - void validate() { - if (sizeof(T) != size) ErrorHandler("MPU: Buffer size mismatch."); - if (reinterpret_cast(ptr) % alignof(T) != 0) ErrorHandler("MPU: Buffer alignment mismatch."); - } }; From f0f99ec122df6fefcb482cfda43c8e8611c7791a Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sat, 13 Dec 2025 11:52:57 +0100 Subject: [PATCH 22/76] feat(MPU): Make construct method return a reference instead of pointer --- Inc/HALAL/Models/MPU.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index 84d7ed59f..db0f824d8 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -221,9 +221,9 @@ struct MPUDomain { std::size_t size; template - auto* construct(Args&&... args) { + auto& construct(Args&&... args) { using T = typename std::remove_cvref_t::buffer_type; - return new (ptr) T(std::forward(args)...); + return *new (ptr) T(std::forward(args)...); } template From 6410c72dc5468ffccf5394cc2aa727d8f9ba9f30 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sat, 13 Dec 2025 17:45:56 +0100 Subject: [PATCH 23/76] fix(MPU): Relax constraints on MPU buffers to allow trivially destructible types --- Inc/HALAL/Models/MPU.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index db0f824d8..a1bee8064 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -25,10 +25,10 @@ concept mpu_buffer_request = requires(typename T::domain d) { { T{ } } -> std::same_as; }; -// POD types only +// POD-like buffers that can safely live in static storage without custom destruction. template concept mpu_buffer_payload = - std::is_standard_layout_v && std::is_trivial_v; + std::is_standard_layout_v && std::is_trivially_destructible_v; struct MPUDomain { From 2a291dc9adf783aeb1ff4c3fda07844702174a7d Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sat, 13 Dec 2025 17:46:13 +0100 Subject: [PATCH 24/76] style(MPU): Better wording and documentation --- Inc/HALAL/Models/MPU.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index a1bee8064..45b834d28 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -250,23 +250,24 @@ struct MPUDomain { static constexpr size_t d3_align = Sizes.d3_nc_size > 0 ? Sizes.d3_nc_size : 32; static constexpr size_t legacy_size = NO_CACHED_RAM_MAXIMUM_SPACE; + // Always reserves at least 1 byte to avoid zero-length arrays, could possibly be optimized further, but this is only 3B overhead... __attribute__((section(".mpu_ram_d1_nc"))) alignas(d1_align) - static inline uint8_t d1_nc_buffer[Sizes.d1_total > 0 ? Sizes.d1_total : 1]; + static inline uint8_t d1_buffer[Sizes.d1_total > 0 ? Sizes.d1_total : 1]; __attribute__((section(".mpu_ram_d2_nc"))) alignas(d2_align) - static inline uint8_t d2_nc_buffer[Sizes.d2_total > 0 ? Sizes.d2_total : 1]; + static inline uint8_t d2_buffer[Sizes.d2_total > 0 ? Sizes.d2_total : 1]; __attribute__((section(".mpu_ram_d3_nc"))) alignas(std::max(d3_align, legacy_size)) - static inline uint8_t d3_nc_buffer[(Sizes.d3_total > 0 ? Sizes.d3_total : 0) + legacy_size]; + static inline uint8_t d3_buffer[(Sizes.d3_total > 0 ? Sizes.d3_total : 0) + legacy_size]; static void init() { HAL_MPU_Disable(); configure_static_regions(); // Configure Legacy MPUManager Region (D3 Non-Cached) - // We place it at the beginning of d3_nc_buffer + // We place it at the beginning of d3_buffer MPU_Region_InitTypeDef Legacy_InitStruct = {0}; Legacy_InitStruct.Enable = MPU_REGION_ENABLE; Legacy_InitStruct.Number = MPU_REGION_NUMBER9; // Use a high region number to override D3 Cached - Legacy_InitStruct.BaseAddress = (uint32_t)&d3_nc_buffer[0]; + Legacy_InitStruct.BaseAddress = (uint32_t)&d3_buffer[0]; Legacy_InitStruct.Size = get_region_size_encoding(legacy_size); Legacy_InitStruct.SubRegionDisable = 0x0; Legacy_InitStruct.TypeExtField = MPU_TEX_LEVEL1; @@ -278,10 +279,10 @@ struct MPUDomain { HAL_MPU_ConfigRegion(&Legacy_InitStruct); // Set the legacy pointer - MPUManager::no_cached_ram_start = &d3_nc_buffer[0]; + MPUManager::no_cached_ram_start = &d3_buffer[0]; // Adjust bases for new buffers (they start after legacy_size) - uint8_t* bases[3] = { &d1_nc_buffer[0], &d2_nc_buffer[0], &d3_nc_buffer[legacy_size] }; + uint8_t* bases[3] = { &d1_buffer[0], &d2_buffer[0], &d3_buffer[legacy_size] }; for (std::size_t i = 0; i < N; i++) { const auto &cfg = cfgs[i]; From 846d52deb08e8fba1ffcbdb3320f5077866dee9b Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sat, 13 Dec 2025 18:24:16 +0100 Subject: [PATCH 25/76] feat(MPU): Make MPU ultra restrictive, should check that there's no region outside defined ones --- Inc/HALAL/Models/MPU.hpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index 45b834d28..fc3649f0b 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -354,14 +354,16 @@ struct MPUDomain { static void configure_static_regions() { MPU_Region_InitTypeDef MPU_InitStruct = {0}; - // Background (No Access) + // Background (No Access) - Covers all memory not explicitly defined by a further region MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; - MPU_InitStruct.BaseAddress = 0x0; + MPU_InitStruct.BaseAddress = 0x00; MPU_InitStruct.Size = MPU_REGION_SIZE_4GB; - MPU_InitStruct.SubRegionDisable = 0x87; + MPU_InitStruct.SubRegionDisable = 0x04; // Disable 512MB at 0x40000000 (Peripheral space) + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); @@ -371,11 +373,13 @@ struct MPUDomain { MPU_InitStruct.Number = MPU_REGION_NUMBER1; MPU_InitStruct.BaseAddress = 0x08000000; MPU_InitStruct.Size = MPU_REGION_SIZE_1MB; - MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.SubRegionDisable = 0x00; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; // This should be scrutinized to see why it was non-cacheable before changing to cacheable - MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; + MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; // This should be scrutinized to see why it was non-bufferable before changing to bufferable HAL_MPU_ConfigRegion(&MPU_InitStruct); // D1 RAM (Cached) @@ -384,8 +388,10 @@ struct MPUDomain { MPU_InitStruct.BaseAddress = 0x24000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512KB; MPU_InitStruct.SubRegionDisable = 0xE0; // Only 320KB available + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); @@ -396,8 +402,10 @@ struct MPUDomain { MPU_InitStruct.BaseAddress = 0x30000000; MPU_InitStruct.Size = MPU_REGION_SIZE_32KB; MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); @@ -408,8 +416,10 @@ struct MPUDomain { MPU_InitStruct.BaseAddress = 0x30000000; MPU_InitStruct.Size = MPU_REGION_SIZE_512B; MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; // Device HAL_MPU_ConfigRegion(&MPU_InitStruct); @@ -420,8 +430,10 @@ struct MPUDomain { MPU_InitStruct.BaseAddress = 0x38000000; MPU_InitStruct.Size = MPU_REGION_SIZE_16KB; MPU_InitStruct.SubRegionDisable = 0x0; + MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; + MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); From ae017490679ddef74b0e70fab4f3f96b3b4922d5 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 13:27:55 +0100 Subject: [PATCH 26/76] feat(Sd): Initial implementation of the infrastructure for Sd --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 302 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 Inc/ST-LIB_LOW/Sd/Sd.hpp diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp new file mode 100644 index 000000000..f6950a177 --- /dev/null +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -0,0 +1,302 @@ +/* + * Sd.hpp + * + * Created on: 13 dec. 2025 + * Author: Boris + */ + +#ifndef SD_HPP +#define SD_HPP + +#include "HALAL/HALAL.hpp" +#include "stm32h7xx_hal.h" +#include "ErrorHandler/ErrorHandler.hpp" + +using ST-LIB::DigitalInputDomain; +using ST-LIB::GPIODomain; + +static SD_HandleTypeDef* g_sdmmc1_handle = nullptr; +static SD_HandleTypeDef* g_sdmmc2_handle = nullptr; + +struct SdDomain { + + enum class Peripheral : uint32_t { + SDMMC1 = SDMMC1_BASE, + SDMMC2 = SDMMC2_BASE, + }; + + + struct Entry { + Peripheral peripheral; + std::size_t mpu_buffer0_idx; + std::size_t mpu_buffer1_idx; + std::optional cd_pin_idx; // Card Detect pin index in GPIO domain, if any + std::optional wp_pin_idx; // Write Protect pin index in GPIO domain, if any + std::size_t cmd_pin_idx; + std::size_t ck_pin_idx; + std::size_t d0_pin_idx; // Hardcoded unless SDMMC1 + std::size_t d1_pin_idx; // Hardcoded unless SDMMC1 + std::size_t d2_pin_idx; + std::size_t d3_pin_idx; + }; + + + template + struct SdCard { + using domain = SdDomain; + Entry e; + + Peripheral peripheral; + + MPUDomain::Buffer> buffer0; + MPUDomain::Buffer> buffer1; + + std::optional cd; // Card Detect, if any + std::optional wp; // Write Protect, if any + + GPIODomain::GPIO cmd; + GPIODomain::GPIO ck; + GPIODomain::GPIO d0; + GPIODomain::GPIO d1; + GPIODomain::GPIO d2; + GPIODomain::GPIO d3; + + /** + * @brief Construct a new SdCard + * @tparam buffer_blocks Number of 512-byte blocks for the MPU buffer + * @param sdmmc_peripheral The SDMMC peripheral to use (Peripheral::SDMMC1 or Peripheral::SDMMC2) + * @param card_detect Optional Card Detect pin (DigitalInputDomain::DigitalInput), or null for none + * @param write_protect Optional Write Protect pin (DigitalInputDomain::DigitalInput), or null for none + * @param d0_pin_for_sdmmc1 D0 pin to use if using SDMMC1 (default PC8) + * @param d1_pin_for_sdmmc1 D1 pin to use if using SDMMC1 (default PC9) + * @note The other pins (CMD, CK, D2, D3) are fixed for each peripheral. + */ + consteval SdCard(Peripheral sdmmc_peripheral, + DigitalInputDomain::DigitalInput card_detect = null, DigitalInputDomain::DigitalInput write_protect = null, + GPIODomain::Pin d0_pin_for_sdmmc1 = PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = PC9) { + + e.peripheral = sdmmc_peripheral; + + buffer0 = MPUDomain::Buffer>; + buffer1 = MPUDomain::Buffer>; + + cd = card_detect; + wp = write_protect; + + if (sdmmc_peripheral == Peripheral::SDMMC1) { + cmd = GPIODomain::GPIO(PC6, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + ck = GPIODomain::GPIO(PC12, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d0 = GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d1 = GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d2 = GPIODomain::GPIO(PC10, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d3 = GPIODomain::GPIO(PC11, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + } else if (sdmmc_peripheral == Peripheral::SDMMC2) { + cmd = GPIODomain::GPIO(PD7, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + ck = GPIODomain::GPIO(PD6, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d0 = GPIODomain::GPIO(PB14, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d1 = GPIODomain::GPIO(PB15, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d2 = GPIODomain::GPIO(PG11, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + d3 = GPIODomain::GPIO(PG12, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + } else { + throw "Invalid SDMMC peripheral"; + } + } + + + template + consteval void inscribe(Ctx &ctx) const { + e.mpu_buffer0_idx = ctx.template add(e.mpu_buffer0); + e.mpu_buffer1_idx = ctx.template add(e.mpu_buffer1); + + if (e.cd != null) { + e.cd_idx = ctx.template add(cd); + } + if (e.wp != null) { + e.wp_idx = ctx.template add(wp); + } + + e.cmd_pin_idx = ctx.template add(cmd); + e.ck_pin_idx = ctx.template add(ck); + e.d0_pin_idx = ctx.template add(d0); + e.d1_pin_idx = ctx.template add(d1); + e.d2_pin_idx = ctx.template add(d2); + e.d3_pin_idx = ctx.template add(d3); + + ctx.template add(e); + } + }; + + + static constexpr std::size_t max_instances = 2; + + + struct Config { + Peripheral peripheral; + std::size_t mpu_buffer0_idx; + std::size_t mpu_buffer1_idx; + std::optional cd_pin_idx; + std::optional wp_pin_idx; + std::size_t cmd_pin_idx; + std::size_t ck_pin_idx; + std::size_t d0_pin_idx; + std::size_t d1_pin_idx; + std::size_t d2_pin_idx; + std::size_t d3_pin_idx; + }; + + + template + static consteval std::array build(std::span entries) { + std::array cfgs{}; + bool peripheral_used[2] = {false, false}; // SDMMC1, SDMMC2 + + for (std::size_t i = 0; i < N; i++) { + const Entry &e = entries[i]; + + // Verify uniqueness of peripheral usage + std::size_t peripheral_index = (e.peripheral == Peripheral::SDMMC1) ? 0 : 1; + if (peripheral_used[peripheral_index]) throw "SDMMC peripheral already used"; + peripheral_used[peripheral_index] = true; + + // Fill configuration + cfgs[i].peripheral = e.peripheral; + cfgs[i].mpu_buffer0_idx = e.mpu_buffer0_idx; + cfgs[i].mpu_buffer1_idx = e.mpu_buffer1_idx; + cfgs[i].cd_pin_idx = e.cd_pin_idx; + cfgs[i].wp_pin_idx = e.wp_pin_idx; + cfgs[i].cmd_pin_idx = e.cmd_pin_idx; + cfgs[i].ck_pin_idx = e.ck_pin_idx; + cfgs[i].d0_pin_idx = e.d0_pin_idx; + cfgs[i].d1_pin_idx = e.d1_pin_idx; + cfgs[i].d2_pin_idx = e.d2_pin_idx; + cfgs[i].d3_pin_idx = e.d3_pin_idx; + } + + return cfgs; + } + + + // State holder, logic is in SdCardWrapper + struct Instance { + friend class SdCardWrapper; + friend struct Init; + + private: + SD_HandleTypeDef hsd; + + MPUDomain::Instance* mpu_buffer0_instance; + MPUDomain::Instance* mpu_buffer1_instance; + + std::optional cd_instance; + std::optional wp_instance; + + bool card_initialized; + }; + + struct SdCardWrapperI { + + }; + + template + struct SdCardWrapper : public SdCardWrapperI { + using peripheral = decltype(card_request)::peripheral; + using has_cd = decltype(card_request)::cd != null; + using has_wp = decltype(card_request)::wp != null; + + SdCardWrapper(Instance& instance) : instance(instance) {}; + + // Methods to operate the SD card + + private: + Instance& instance; // Actual State + }; + + + template + struct Init { + static inline std::array instances{}; + + static void init(std::span cfgs, + std::span mpu_buffer_instances, + std::span digital_input_instances) { + + for (std::size_t i = 0; i < N; i++) { + const auto &cfg = cfgs[i]; + auto &inst = instances[i]; + inst.mpu_buffer0_instance = mpu_buffer_instances[cfg.mpu_buffer0_idx]; + inst.mpu_buffer1_instance = mpu_buffer_instances[cfg.mpu_buffer1_idx]; + if (cfg.cd_pin_idx.has_value()) { + inst.cd_instance = &digital_input_instances[cfg.cd_pin_idx.value()]; + } + if (cfg.wp_pin_idx.has_value()) { + inst.wp_instance = &digital_input_instances[cfg.wp_pin_idx.value()]; + } + + inst.hsd.Instance = static_cast(static_cast(cfg.peripheral)); + inst.card_initialized = false; + + // Initialize HAL SD + RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; + RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; + RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { + ErrorHandler("SDMMC1 clock configuration failed"); + } + + if (cfg.peripheral == Peripheral::SDMMC1) { + g_sdmmc1_handle = &inst.hsd; + __HAL_RCC_SDMMC1_CLK_ENABLE(); + HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + } else if (cfg.peripheral == Peripheral::SDMMC2) { + g_sdmmc2_handle = &inst.hsd; + __HAL_RCC_SDMMC2_CLK_ENABLE(); + HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(SDMMC2_IRQn); + } + } + } + }; +}; + + +extern "C" void SDMMC1_IRQHandler(void) { + if (g_sdmmc1_handle != nullptr) { + HAL_SD_IRQHandler(g_sdmmc1_handle); + } +} + +extern "C" void SDMMC2_IRQHandler(void) { + if (g_sdmmc2_handle != nullptr) { + HAL_SD_IRQHandler(g_sdmmc2_handle); + } +} + +void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { + auto sd_instance = reinterpret_cast(hsd->Context); + //SDMMC_CmdStopTransfer(hsd->Instance); +} +void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { + auto sd_instance = reinterpret_cast(hsd->Context); + //SDMMC_CmdStopTransfer(hsd->Instance); +} + +void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { + auto sd_instance = reinterpret_cast(hsd->Context); + //SDMMC_CmdStopTransfer(hsd->Instance); +} +void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { + auto sd_instance = reinterpret_cast(hsd->Context); + //SDMMC_CmdStopTransfer(hsd->Instance); +} + +void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { + auto sd_instance = reinterpret_cast(hsd->Context); +} + +void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { + auto sd_instance = reinterpret_cast(hsd->Context); + ErrorHandler("SD Card error occurred"); +} + +#endif // SD_HPP \ No newline at end of file From 965d7045b4bd97e7895684559620af7241a2de27 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 13:52:51 +0100 Subject: [PATCH 27/76] fix(Sd): Fix syntax errors --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 85 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index f6950a177..6e6ee0403 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -9,11 +9,12 @@ #define SD_HPP #include "HALAL/HALAL.hpp" +#include "ST-LIB_LOW/ST-LIB_LOW.hpp" #include "stm32h7xx_hal.h" #include "ErrorHandler/ErrorHandler.hpp" -using ST-LIB::DigitalInputDomain; -using ST-LIB::GPIODomain; +using ST_LIB::DigitalInputDomain; +using ST_LIB::GPIODomain; static SD_HandleTypeDef* g_sdmmc1_handle = nullptr; static SD_HandleTypeDef* g_sdmmc2_handle = nullptr; @@ -21,8 +22,8 @@ static SD_HandleTypeDef* g_sdmmc2_handle = nullptr; struct SdDomain { enum class Peripheral : uint32_t { - SDMMC1 = SDMMC1_BASE, - SDMMC2 = SDMMC2_BASE, + sdmmc1 = SDMMC1_BASE, + sdmmc2 = SDMMC2_BASE, }; @@ -48,8 +49,8 @@ struct SdDomain { Peripheral peripheral; - MPUDomain::Buffer> buffer0; - MPUDomain::Buffer> buffer1; + MPUDomain::Buffer> buffer0; // Alignment of 32-bit for SDMMC DMA + MPUDomain::Buffer> buffer1; // Alignment of 32-bit for SDMMC DMA std::optional cd; // Card Detect, if any std::optional wp; // Write Protect, if any @@ -64,7 +65,7 @@ struct SdDomain { /** * @brief Construct a new SdCard * @tparam buffer_blocks Number of 512-byte blocks for the MPU buffer - * @param sdmmc_peripheral The SDMMC peripheral to use (Peripheral::SDMMC1 or Peripheral::SDMMC2) + * @param sdmmc_peripheral The SDMMC peripheral to use (Peripheral::sdmmc1 or Peripheral::sdmmc2) * @param card_detect Optional Card Detect pin (DigitalInputDomain::DigitalInput), or null for none * @param write_protect Optional Write Protect pin (DigitalInputDomain::DigitalInput), or null for none * @param d0_pin_for_sdmmc1 D0 pin to use if using SDMMC1 (default PC8) @@ -72,31 +73,31 @@ struct SdDomain { * @note The other pins (CMD, CK, D2, D3) are fixed for each peripheral. */ consteval SdCard(Peripheral sdmmc_peripheral, - DigitalInputDomain::DigitalInput card_detect = null, DigitalInputDomain::DigitalInput write_protect = null, + std::optional card_detect, std::optional write_protect, GPIODomain::Pin d0_pin_for_sdmmc1 = PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = PC9) { e.peripheral = sdmmc_peripheral; - buffer0 = MPUDomain::Buffer>; - buffer1 = MPUDomain::Buffer>; + buffer0 = MPUDomain::Buffer>(); + buffer1 = MPUDomain::Buffer>(); cd = card_detect; wp = write_protect; - if (sdmmc_peripheral == Peripheral::SDMMC1) { - cmd = GPIODomain::GPIO(PC6, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - ck = GPIODomain::GPIO(PC12, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d0 = GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d1 = GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d2 = GPIODomain::GPIO(PC10, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d3 = GPIODomain::GPIO(PC11, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - } else if (sdmmc_peripheral == Peripheral::SDMMC2) { - cmd = GPIODomain::GPIO(PD7, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - ck = GPIODomain::GPIO(PD6, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d0 = GPIODomain::GPIO(PB14, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d1 = GPIODomain::GPIO(PB15, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d2 = GPIODomain::GPIO(PG11, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); - d3 = GPIODomain::GPIO(PG12, GPIODomain::OperationMode::AF, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AF::AF12); + if (sdmmc_peripheral == Peripheral::sdmmc1) { + cmd = GPIODomain::GPIO(PC6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + ck = GPIODomain::GPIO(PC12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d0 = GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d1 = GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d2 = GPIODomain::GPIO(PC10, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d3 = GPIODomain::GPIO(PC11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + } else if (sdmmc_peripheral == Peripheral::sdmmc2) { + cmd = GPIODomain::GPIO(PD7, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + ck = GPIODomain::GPIO(PD6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d0 = GPIODomain::GPIO(PB14, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d1 = GPIODomain::GPIO(PB15, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d2 = GPIODomain::GPIO(PG11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); + d3 = GPIODomain::GPIO(PG12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); } else { throw "Invalid SDMMC peripheral"; } @@ -105,14 +106,14 @@ struct SdDomain { template consteval void inscribe(Ctx &ctx) const { - e.mpu_buffer0_idx = ctx.template add(e.mpu_buffer0); - e.mpu_buffer1_idx = ctx.template add(e.mpu_buffer1); + e.mpu_buffer0_idx = ctx.template add(buffer0); + e.mpu_buffer1_idx = ctx.template add(buffer1); - if (e.cd != null) { - e.cd_idx = ctx.template add(cd); + if (cd.has_value()) { + e.cd_pin_idx = ctx.template add(cd.value()); } - if (e.wp != null) { - e.wp_idx = ctx.template add(wp); + if (wp.has_value()) { + e.wp_pin_idx = ctx.template add(wp.value()); } e.cmd_pin_idx = ctx.template add(cmd); @@ -154,7 +155,7 @@ struct SdDomain { const Entry &e = entries[i]; // Verify uniqueness of peripheral usage - std::size_t peripheral_index = (e.peripheral == Peripheral::SDMMC1) ? 0 : 1; + std::size_t peripheral_index = (e.peripheral == Peripheral::sdmmc1) ? 0 : 1; if (peripheral_used[peripheral_index]) throw "SDMMC peripheral already used"; peripheral_used[peripheral_index] = true; @@ -200,8 +201,8 @@ struct SdDomain { template struct SdCardWrapper : public SdCardWrapperI { using peripheral = decltype(card_request)::peripheral; - using has_cd = decltype(card_request)::cd != null; - using has_wp = decltype(card_request)::wp != null; + static constexpr bool has_cd = decltype(card_request)::cd.has_value(); + static constexpr bool has_wp = decltype(card_request)::wp.has_value(); SdCardWrapper(Instance& instance) : instance(instance) {}; @@ -232,7 +233,7 @@ struct SdDomain { inst.wp_instance = &digital_input_instances[cfg.wp_pin_idx.value()]; } - inst.hsd.Instance = static_cast(static_cast(cfg.peripheral)); + inst.hsd.Instance = reinterpret_cast(static_cast(cfg.peripheral)); inst.card_initialized = false; // Initialize HAL SD @@ -243,12 +244,12 @@ struct SdDomain { ErrorHandler("SDMMC1 clock configuration failed"); } - if (cfg.peripheral == Peripheral::SDMMC1) { + if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; __HAL_RCC_SDMMC1_CLK_ENABLE(); HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); HAL_NVIC_EnableIRQ(SDMMC1_IRQn); - } else if (cfg.peripheral == Peripheral::SDMMC2) { + } else if (cfg.peripheral == Peripheral::sdmmc2) { g_sdmmc2_handle = &inst.hsd; __HAL_RCC_SDMMC2_CLK_ENABLE(); HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); @@ -273,29 +274,29 @@ extern "C" void SDMMC2_IRQHandler(void) { } void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = reinterpret_cast(hsd->Context); //SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = reinterpret_cast(hsd->Context); //SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = reinterpret_cast(hsd->Context); //SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = reinterpret_cast(hsd->Context); //SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = reinterpret_cast(hsd->Context); } void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = reinterpret_cast(hsd->Context); ErrorHandler("SD Card error occurred"); } From a0b09beda0310cdd5058a2d5bee1c5a0dacc430d Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 13:53:18 +0100 Subject: [PATCH 28/76] feat(Sd): Add Sd to ST-LIB --- Inc/ST-LIB.hpp | 13 +++++++++++-- Inc/ST-LIB_LOW/ST-LIB_LOW.hpp | 2 ++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index ebb70246c..4a941a52d 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -71,7 +71,8 @@ template struct BuildCtx { }; using DomainsCtx = BuildCtx; + DigitalInputDomain, MPUDomain, SdDomain + /*, ADCDomain, PWMDomain, ...*/>; template struct Board { static consteval auto build_ctx() { @@ -91,6 +92,7 @@ template struct Board { constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); constexpr std::size_t mpuN = domain_size(); + constexpr std::size_t sdN = domain_size(); // ... struct ConfigBundle { @@ -98,6 +100,7 @@ template struct Board { std::array dout_cfgs; std::array din_cfgs; std::array mpu_cfgs; + std::array sd_cfgs; // ... }; @@ -109,7 +112,9 @@ template struct Board { .din_cfgs = DigitalInputDomain::template build( ctx.template span()), .mpu_cfgs = MPUDomain::template build( - ctx.template span()) + ctx.template span()), + .sd_cfgs = SdDomain::template build( + ctx.template span()), // ... }; } @@ -121,6 +126,7 @@ template struct Board { constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); constexpr std::size_t mpuN = domain_size(); + constexpr std::size_t sdN = domain_size(); // ... GPIODomain::Init::init(cfg.gpio_cfgs); @@ -129,6 +135,9 @@ template struct Board { DigitalInputDomain::Init::init(cfg.din_cfgs, GPIODomain::Init::instances); MPUDomain::Init::init(); + SdDomain::Init::init(cfg.sd_cfgs, + MPUDomain::Init::instances, + DigitalInputDomain::Init::instances); // ... } diff --git a/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp b/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp index b73165c24..bc25ac7ec 100644 --- a/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp +++ b/Inc/ST-LIB_LOW/ST-LIB_LOW.hpp @@ -3,6 +3,8 @@ #include "ST-LIB_LOW/DigitalOutput2.hpp" #include "ST-LIB_LOW/DigitalInput2.hpp" +#include "ST-LIB_LOW/Sd/Sd.hpp" + #include "Clocks/Counter.hpp" #include "Clocks/Stopwatch.hpp" #include "Sensors/LinearSensor/LinearSensor.hpp" From efb806dbceae54b7d078da2ba8173c08f7b1ba71 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 15:17:21 +0100 Subject: [PATCH 29/76] feat(Sd): Receive CD and WP pin active states --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 6e6ee0403..d67a9ad24 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -31,8 +31,8 @@ struct SdDomain { Peripheral peripheral; std::size_t mpu_buffer0_idx; std::size_t mpu_buffer1_idx; - std::optional cd_pin_idx; // Card Detect pin index in GPIO domain, if any - std::optional wp_pin_idx; // Write Protect pin index in GPIO domain, if any + std::optional> cd_pin_idx; // Card Detect pin index in GPIO domain, if any + std::optional> wp_pin_idx; // Write Protect pin index in GPIO domain, if any std::size_t cmd_pin_idx; std::size_t ck_pin_idx; std::size_t d0_pin_idx; // Hardcoded unless SDMMC1 @@ -52,8 +52,8 @@ struct SdDomain { MPUDomain::Buffer> buffer0; // Alignment of 32-bit for SDMMC DMA MPUDomain::Buffer> buffer1; // Alignment of 32-bit for SDMMC DMA - std::optional cd; // Card Detect, if any - std::optional wp; // Write Protect, if any + std::optional> cd; // Card Detect, if any, and its active state + std::optional> wp; // Write Protect, if any, and its active state GPIODomain::GPIO cmd; GPIODomain::GPIO ck; @@ -66,14 +66,14 @@ struct SdDomain { * @brief Construct a new SdCard * @tparam buffer_blocks Number of 512-byte blocks for the MPU buffer * @param sdmmc_peripheral The SDMMC peripheral to use (Peripheral::sdmmc1 or Peripheral::sdmmc2) - * @param card_detect Optional Card Detect pin (DigitalInputDomain::DigitalInput), or null for none - * @param write_protect Optional Write Protect pin (DigitalInputDomain::DigitalInput), or null for none + * @param card_detect_config Optional Card Detect pin (DigitalInputDomain::DigitalInput) and its active state, or null for none + * @param write_protect_config Optional Write Protect pin (DigitalInputDomain::DigitalInput) and its active state, or null for none * @param d0_pin_for_sdmmc1 D0 pin to use if using SDMMC1 (default PC8) * @param d1_pin_for_sdmmc1 D1 pin to use if using SDMMC1 (default PC9) * @note The other pins (CMD, CK, D2, D3) are fixed for each peripheral. */ consteval SdCard(Peripheral sdmmc_peripheral, - std::optional card_detect, std::optional write_protect, + std::optional> card_detect_config, std::optional> write_protect_config, GPIODomain::Pin d0_pin_for_sdmmc1 = PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = PC9) { e.peripheral = sdmmc_peripheral; @@ -81,8 +81,8 @@ struct SdDomain { buffer0 = MPUDomain::Buffer>(); buffer1 = MPUDomain::Buffer>(); - cd = card_detect; - wp = write_protect; + cd = card_detect_config; + wp = write_protect_config; if (sdmmc_peripheral == Peripheral::sdmmc1) { cmd = GPIODomain::GPIO(PC6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); @@ -110,10 +110,10 @@ struct SdDomain { e.mpu_buffer1_idx = ctx.template add(buffer1); if (cd.has_value()) { - e.cd_pin_idx = ctx.template add(cd.value()); + e.cd_pin_idx = {ctx.template add(cd.value().first), cd.value().second}; } if (wp.has_value()) { - e.wp_pin_idx = ctx.template add(wp.value()); + e.wp_pin_idx = {ctx.template add(wp.value().first), wp.value().second}; } e.cmd_pin_idx = ctx.template add(cmd); @@ -176,10 +176,14 @@ struct SdDomain { return cfgs; } + enum class BufferSelect : bool { + Buffer0 = false, + Buffer1 = true + }; // State holder, logic is in SdCardWrapper struct Instance { - friend class SdCardWrapper; + friend struct SdCardWrapper; friend struct Init; private: @@ -188,10 +192,11 @@ struct SdDomain { MPUDomain::Instance* mpu_buffer0_instance; MPUDomain::Instance* mpu_buffer1_instance; - std::optional cd_instance; - std::optional wp_instance; + std::optional> cd_instance; + std::optional> wp_instance; bool card_initialized; + BufferSelect current_buffer; // The one that is currently available for CPU access and not used by IDMA }; struct SdCardWrapperI { @@ -201,6 +206,7 @@ struct SdDomain { template struct SdCardWrapper : public SdCardWrapperI { using peripheral = decltype(card_request)::peripheral; + using buffer_type = typename decltype(card_request.buffer0)::buffer_type; static constexpr bool has_cd = decltype(card_request)::cd.has_value(); static constexpr bool has_wp = decltype(card_request)::wp.has_value(); @@ -227,14 +233,16 @@ struct SdDomain { inst.mpu_buffer0_instance = mpu_buffer_instances[cfg.mpu_buffer0_idx]; inst.mpu_buffer1_instance = mpu_buffer_instances[cfg.mpu_buffer1_idx]; if (cfg.cd_pin_idx.has_value()) { - inst.cd_instance = &digital_input_instances[cfg.cd_pin_idx.value()]; + inst.cd_instance = {&digital_input_instances[cfg.cd_pin_idx.value().first], cfg.cd_pin_idx.value().second}; } if (cfg.wp_pin_idx.has_value()) { - inst.wp_instance = &digital_input_instances[cfg.wp_pin_idx.value()]; + inst.wp_instance = {&digital_input_instances[cfg.wp_pin_idx.value().first], cfg.wp_pin_idx.value().second}; } inst.hsd.Instance = reinterpret_cast(static_cast(cfg.peripheral)); + inst.card_initialized = false; + inst.current_buffer = BufferSelect::Buffer0; // Initialize HAL SD RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; From f2845c17d790debaa0c6f454392d6c7be25a8736 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 16:34:58 +0100 Subject: [PATCH 30/76] feat(Sd): Full implementation of the class --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 369 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 350 insertions(+), 19 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index d67a9ad24..1e4f48617 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -19,6 +19,9 @@ using ST_LIB::GPIODomain; static SD_HandleTypeDef* g_sdmmc1_handle = nullptr; static SD_HandleTypeDef* g_sdmmc2_handle = nullptr; +static void* g_sdmmc1_instance_ptr = nullptr; +static void* g_sdmmc2_instance_ptr = nullptr; + struct SdDomain { enum class Peripheral : uint32_t { @@ -186,6 +189,8 @@ struct SdDomain { friend struct SdCardWrapper; friend struct Init; + bool* operation_flag = nullptr; // External flag to indicate that an operation has finished + private: SD_HandleTypeDef hsd; @@ -197,25 +202,313 @@ struct SdDomain { bool card_initialized; BufferSelect current_buffer; // The one that is currently available for CPU access and not used by IDMA - }; - struct SdCardWrapperI { + // Functions + bool is_card_present() { return cd_instance->first->read() == cd_instance->second; } + bool is_write_protected() { return wp_instance->first->read() == wp_instance->second; } + + bool is_busy() { + return (hsd.State != HAL_SD_STATE_TRANSFER); + } + + bool initialize_card() { + if (card_initialized) { return true; } // Already initialized + + HAL_StatusTypeDef status = HAL_SD_Init(&hsd); + + if (status != HAL_OK) { return false; } + + card_initialized = true; + return true; + } + + bool deinitialize_card() { + if (!card_initialized) { return true; } // Already deinitialized + + HAL_StatusTypeDef status = HAL_SD_DeInit(&hsd); + if (status != HAL_OK) { return false; } + + card_initialized = false; + return true; // Placeholder + } + void switch_buffer() { + current_buffer = (current_buffer == BufferSelect::Buffer0) ? BufferSelect::Buffer1 : BufferSelect::Buffer0; + } + + bool configure_idma() { + HAL_StatusTypeDef status = HAL_SDEx_ConfigDMAMultiBuffer(&hsd, + reinterpret_cast(mpu_buffer0_instance->ptr), + reinterpret_cast(mpu_buffer1_instance->ptr), + mpu_buffer0_instance->size / 512); // Number of 512B-blocks + + if (status != HAL_OK) { return false; } + return true; + } }; template - struct SdCardWrapper : public SdCardWrapperI { - using peripheral = decltype(card_request)::peripheral; - using buffer_type = typename decltype(card_request.buffer0)::buffer_type; + struct SdCardWrapper{ static constexpr bool has_cd = decltype(card_request)::cd.has_value(); static constexpr bool has_wp = decltype(card_request)::wp.has_value(); - SdCardWrapper(Instance& instance) : instance(instance) {}; + SdCardWrapper(Instance& instance) : instance(instance) { + check_cd_wp(); + }; + + void init_card() { + check_cd_wp(); + bool success = instance.initialize_card(); + if (!success) { + ErrorHandler("SD Card initialization failed"); + } + } + + void deinit_card() { + check_cd_wp(); + bool success = instance.deinitialize_card(); + if (!success) { + ErrorHandler("SD Card deinitialization failed"); + } + } + + bool is_card_initialized() { + return instance.card_initialized; + } + + bool read_blocks(uint32_t start_block, uint32_t num_blocks, bool& operation_complete_flag) { + check_cd_wp(); + if (!instance.card_initialized) { + ErrorHandler("SD Card not initialized"); + } + if (instance.is_busy()) { + return false; // Busy + } + + instance.operation_flag = &operation_complete_flag; + operation_complete_flag = false; + + auto& buffer = get_current_buffer(); + + // Won't use HAL_SDEx_ReadBlocksDMAMultiBuffer because it doesn't support double buffering the way we want + HAL_StatusTypeDef status = Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(start_block, num_blocks); + + if (status != HAL_OK) { + ErrorHandler("SD Card read operation failed"); + } + + return true; + } + + bool write_blocks(uint32_t start_block, uint32_t num_blocks, bool& operation_complete_flag) { + check_cd_wp(); + if (!instance.card_initialized) { + ErrorHandler("SD Card not initialized"); + } + if (instance.is_busy()) { + return false; // Busy + } + + instance.operation_flag = &operation_complete_flag; + operation_complete_flag = false; + + auto& buffer = get_current_buffer(); + + // Won't use HAL_SDEx_WriteBlocksDMAMultiBuffer because it doesn't support double buffering the way we want + HAL_StatusTypeDef status = Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); + + if (status != HAL_OK) { + ErrorHandler("SD Card write operation failed"); + } + + return true; + } - // Methods to operate the SD card private: Instance& instance; // Actual State + + + void check_cd_wp() { + if constexpr (has_cd) { + if (!instance.is_card_present()) { ErrorHandler("SD Card not present"); } + } + if constexpr (has_wp) { + if (instance.is_write_protected()) { ErrorHandler("SD Card is write-protected"); } + } + } + + auto& get_current_buffer() { + if (instance.current_buffer == BufferSelect::Buffer0) { + return instance.mpu_buffer0_instance->template as(); + } else { + return instance.mpu_buffer1_instance->template as(); + } + } + + // Variation of HAL_SDEx_ReadBlocksDMAMultiBuffer to fit our needs + HAL_StatusTypeDef Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { + auto* hsd = instance.hsd; + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t DmaBase0_reg; + uint32_t DmaBase1_reg; + uint32_t add = BlockAdd; + + if (hsd->State == HAL_SD_STATE_READY) + { + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + DmaBase0_reg = hsd->Instance->IDMABASE0; + DmaBase1_reg = hsd->Instance->IDMABASE1; + + if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U)) + { + hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + /* Clear old Flags*/ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + hsd->ErrorCode = HAL_SD_ERROR_NONE; + hsd->State = HAL_SD_STATE_BUSY; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= 512U; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST; + + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + if (instance.current_buffer == BufferSelect::Buffer1) { + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + } else { + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; + } + instance.switch_buffer(); + + /* Read Blocks in DMA mode */ + hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA); + + /* Read Multi Block command */ + errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->State = HAL_SD_STATE_READY; + hsd->ErrorCode |= errorstate; + return HAL_ERROR; + } + + __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND | + SDMMC_IT_IDMABTC)); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } + + } + + // Variation of HAL_SDEx_WriteBlocksDMAMultiBuffer to fit our needs + HAL_StatusTypeDef Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { + auto* hsd = instance.hsd; + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t DmaBase0_reg; + uint32_t DmaBase1_reg; + uint32_t add = BlockAdd; + + if (hsd->State == HAL_SD_STATE_READY) + { + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + DmaBase0_reg = hsd->Instance->IDMABASE0; + DmaBase1_reg = hsd->Instance->IDMABASE1; + if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U)) + { + hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0; + + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + hsd->State = HAL_SD_STATE_BUSY; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= 512U; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + //hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST; // I am manually flushing the FIFO here, hal did not do it + + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + //hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + if (instance.current_buffer == BufferSelect::Buffer1) { + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + } else { + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; + } + instance.switch_buffer(); + + /* Write Blocks in DMA mode */ + hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA); + + /* Write Multi Block command */ + errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->State = HAL_SD_STATE_READY; + hsd->ErrorCode |= errorstate; + return HAL_ERROR; + } + + __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND | + SDMMC_IT_IDMABTC)); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } + } }; @@ -230,8 +523,12 @@ struct SdDomain { for (std::size_t i = 0; i < N; i++) { const auto &cfg = cfgs[i]; auto &inst = instances[i]; - inst.mpu_buffer0_instance = mpu_buffer_instances[cfg.mpu_buffer0_idx]; - inst.mpu_buffer1_instance = mpu_buffer_instances[cfg.mpu_buffer1_idx]; + inst.mpu_buffer0_instance = &mpu_buffer_instances[cfg.mpu_buffer0_idx]; + inst.mpu_buffer1_instance = &mpu_buffer_instances[cfg.mpu_buffer1_idx]; + if (!inst.configure_idma()) { + ErrorHandler("SD Card IDMA configuration failed"); + } + if (cfg.cd_pin_idx.has_value()) { inst.cd_instance = {&digital_input_instances[cfg.cd_pin_idx.value().first], cfg.cd_pin_idx.value().second}; } @@ -240,6 +537,12 @@ struct SdDomain { } inst.hsd.Instance = reinterpret_cast(static_cast(cfg.peripheral)); + inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING; + inst.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; + inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + inst.hsd.Init.ClockDiv = 0; + inst.card_initialized = false; inst.current_buffer = BufferSelect::Buffer0; @@ -254,11 +557,13 @@ struct SdDomain { if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; + g_sdmmc1_instance_ptr = &inst; __HAL_RCC_SDMMC1_CLK_ENABLE(); HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); HAL_NVIC_EnableIRQ(SDMMC1_IRQn); } else if (cfg.peripheral == Peripheral::sdmmc2) { g_sdmmc2_handle = &inst.hsd; + g_sdmmc2_instance_ptr = &inst; __HAL_RCC_SDMMC2_CLK_ENABLE(); HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); HAL_NVIC_EnableIRQ(SDMMC2_IRQn); @@ -268,6 +573,11 @@ struct SdDomain { }; }; +static inline SdDomain::Instance* get_sd_instance(SD_HandleTypeDef* hsd) { + if (hsd == g_sdmmc1_handle) return static_cast(g_sdmmc1_instance_ptr); + if (hsd == g_sdmmc2_handle) return static_cast(g_sdmmc2_instance_ptr); + return nullptr; +} extern "C" void SDMMC1_IRQHandler(void) { if (g_sdmmc1_handle != nullptr) { @@ -281,31 +591,52 @@ extern "C" void SDMMC2_IRQHandler(void) { } } +extern "C" { + void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = reinterpret_cast(hsd->Context); - //SDMMC_CmdStopTransfer(hsd->Instance); + auto sd_instance = get_sd_instance(hsd); + if (sd_instance && sd_instance->operation_flag) { + *sd_instance->operation_flag = true; + sd_instance->operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = reinterpret_cast(hsd->Context); - //SDMMC_CmdStopTransfer(hsd->Instance); + auto sd_instance = get_sd_instance(hsd); + if (sd_instance && sd_instance->operation_flag) { + *sd_instance->operation_flag = true; + sd_instance->operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = reinterpret_cast(hsd->Context); - //SDMMC_CmdStopTransfer(hsd->Instance); + auto sd_instance = get_sd_instance(hsd); + if (sd_instance && sd_instance->operation_flag) { + *sd_instance->operation_flag = true; + sd_instance->operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = reinterpret_cast(hsd->Context); - //SDMMC_CmdStopTransfer(hsd->Instance); + auto sd_instance = get_sd_instance(hsd); + if (sd_instance && sd_instance->operation_flag) { + *sd_instance->operation_flag = true; + sd_instance->operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = reinterpret_cast(hsd->Context); + // auto sd_instance = get_sd_instance(hsd); + ErrorHandler("SD Card operation aborted"); } void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = reinterpret_cast(hsd->Context); + //auto sd_instance = get_sd_instance(hsd); ErrorHandler("SD Card error occurred"); } +} // extern "C" + #endif // SD_HPP \ No newline at end of file From a66a8864303eb71db8cbb06424044442043b8fa2 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 18:33:14 +0100 Subject: [PATCH 31/76] fix(Sd): Sd buffers use D1 memory --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 1e4f48617..cb5c80888 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -81,8 +81,8 @@ struct SdDomain { e.peripheral = sdmmc_peripheral; - buffer0 = MPUDomain::Buffer>(); - buffer1 = MPUDomain::Buffer>(); + buffer0 = MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1); + buffer1 = MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1); cd = card_detect_config; wp = write_protect_config; From a78d46af8bd1a060acaa47726434be3578ac514f Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 19:35:48 +0100 Subject: [PATCH 32/76] fix(Sd): Configure card speed --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index cb5c80888..4a2210885 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -218,6 +218,10 @@ struct SdDomain { if (status != HAL_OK) { return false; } + if (HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO) != HAL_OK) { + ErrorHandler("SD Card speed/bus configuration failed"); + } + card_initialized = true; return true; } From 44e9a23fddbd4aaaf040f501852b78906de78bbc Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 19:36:11 +0100 Subject: [PATCH 33/76] feat(Sd): Add debug mode --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 4a2210885..8f1430c16 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -548,6 +548,18 @@ struct SdDomain { inst.hsd.Init.ClockDiv = 0; + #ifdef SD_DEBUG_ENABLE + inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; + // Get a 400 kHz clock for debugging + uint32_t pll1_freq = HAL_RCCEx_GetPLL1ClockFreq(); // SDMMC clock source is PLL1 + uint32_t sdmmc_clk = pll1_freq / 2; // SDMMC clock before divider + uint32_t target_div = sdmmc_clk / 400000; // Target divider + if (target_div < 2) target_div = 2; // Minimum divider is 2 + if (target_div > 256) target_div = 256; // Maximum divider is 256 + inst.hsd.Init.ClockDiv = target_div - 2; // ClockDiv is (divider - 2) + #endif // SD_DEBUG_ENABLE + + inst.card_initialized = false; inst.current_buffer = BufferSelect::Buffer0; From e6d9715884764ea1e1bc04d663698b02b18d85b3 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 20:18:09 +0100 Subject: [PATCH 34/76] fix(Sd): Configure cd and wp pins in init --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 8f1430c16..912df5c93 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -138,8 +138,8 @@ struct SdDomain { Peripheral peripheral; std::size_t mpu_buffer0_idx; std::size_t mpu_buffer1_idx; - std::optional cd_pin_idx; - std::optional wp_pin_idx; + std::optional> cd_pin_idx; + std::optional> wp_pin_idx; std::size_t cmd_pin_idx; std::size_t ck_pin_idx; std::size_t d0_pin_idx; @@ -527,6 +527,10 @@ struct SdDomain { for (std::size_t i = 0; i < N; i++) { const auto &cfg = cfgs[i]; auto &inst = instances[i]; + + inst.cd_instance = {&digital_input_instances[cfg.cd_pin_idx.value().first], cfg.cd_pin_idx.value().second}; + inst.wp_instance = {&digital_input_instances[cfg.wp_pin_idx.value().first], cfg.wp_pin_idx.value().second}; + inst.mpu_buffer0_instance = &mpu_buffer_instances[cfg.mpu_buffer0_idx]; inst.mpu_buffer1_instance = &mpu_buffer_instances[cfg.mpu_buffer1_idx]; if (!inst.configure_idma()) { From 448649c90fd26e640e29dacc0b1115f1390c07d9 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 20:21:48 +0100 Subject: [PATCH 35/76] fix(Sd): Ensure --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 912df5c93..3b68062f0 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -192,7 +192,7 @@ struct SdDomain { bool* operation_flag = nullptr; // External flag to indicate that an operation has finished private: - SD_HandleTypeDef hsd; + SD_HandleTypeDef* hsd; MPUDomain::Instance* mpu_buffer0_instance; MPUDomain::Instance* mpu_buffer1_instance; From fddd13cc0d1a0df4fba98c037114eb55c60b7b7a Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 20:24:22 +0100 Subject: [PATCH 36/76] fix(Sd): Mismatched pointer and handle --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 3b68062f0..2fc647e6a 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -192,7 +192,7 @@ struct SdDomain { bool* operation_flag = nullptr; // External flag to indicate that an operation has finished private: - SD_HandleTypeDef* hsd; + SD_HandleTypeDef hsd; MPUDomain::Instance* mpu_buffer0_instance; MPUDomain::Instance* mpu_buffer1_instance; @@ -352,7 +352,7 @@ struct SdDomain { // Variation of HAL_SDEx_ReadBlocksDMAMultiBuffer to fit our needs HAL_StatusTypeDef Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { - auto* hsd = instance.hsd; + auto* hsd = &instance.hsd; SDMMC_DataInitTypeDef config; uint32_t errorstate; uint32_t DmaBase0_reg; From aaedb2419a8b6a997717b61a19727e5ba48005ce Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 20:27:53 +0100 Subject: [PATCH 37/76] fix(Sd): General small fixes --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 2fc647e6a..fc712f4b9 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -233,7 +233,7 @@ struct SdDomain { if (status != HAL_OK) { return false; } card_initialized = false; - return true; // Placeholder + return true; } void switch_buffer() { @@ -292,8 +292,6 @@ struct SdDomain { instance.operation_flag = &operation_complete_flag; operation_complete_flag = false; - auto& buffer = get_current_buffer(); - // Won't use HAL_SDEx_ReadBlocksDMAMultiBuffer because it doesn't support double buffering the way we want HAL_StatusTypeDef status = Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(start_block, num_blocks); @@ -316,8 +314,6 @@ struct SdDomain { instance.operation_flag = &operation_complete_flag; operation_complete_flag = false; - auto& buffer = get_current_buffer(); - // Won't use HAL_SDEx_WriteBlocksDMAMultiBuffer because it doesn't support double buffering the way we want HAL_StatusTypeDef status = Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); From 628f99881723c45520b152aec7cffec3f4899aa5 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 20:38:26 +0100 Subject: [PATCH 38/76] fix(Sd): General bugfixing --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index fc712f4b9..61ad1a44f 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -69,8 +69,8 @@ struct SdDomain { * @brief Construct a new SdCard * @tparam buffer_blocks Number of 512-byte blocks for the MPU buffer * @param sdmmc_peripheral The SDMMC peripheral to use (Peripheral::sdmmc1 or Peripheral::sdmmc2) - * @param card_detect_config Optional Card Detect pin (DigitalInputDomain::DigitalInput) and its active state, or null for none - * @param write_protect_config Optional Write Protect pin (DigitalInputDomain::DigitalInput) and its active state, or null for none + * @param card_detect_config Optional Card Detect pin (DigitalInputDomain::DigitalInput) and its active state, or nullopt for none + * @param write_protect_config Optional Write Protect pin (DigitalInputDomain::DigitalInput) and its active state, or nullopt for none * @param d0_pin_for_sdmmc1 D0 pin to use if using SDMMC1 (default PC8) * @param d1_pin_for_sdmmc1 D1 pin to use if using SDMMC1 (default PC9) * @note The other pins (CMD, CK, D2, D3) are fixed for each peripheral. @@ -186,7 +186,7 @@ struct SdDomain { // State holder, logic is in SdCardWrapper struct Instance { - friend struct SdCardWrapper; + template friend struct SdCardWrapper; friend struct Init; bool* operation_flag = nullptr; // External flag to indicate that an operation has finished @@ -251,7 +251,7 @@ struct SdDomain { } }; - template + template struct SdCardWrapper{ static constexpr bool has_cd = decltype(card_request)::cd.has_value(); static constexpr bool has_wp = decltype(card_request)::wp.has_value(); @@ -431,7 +431,7 @@ struct SdDomain { // Variation of HAL_SDEx_WriteBlocksDMAMultiBuffer to fit our needs HAL_StatusTypeDef Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { - auto* hsd = instance.hsd; + auto* hsd = &instance.hsd; SDMMC_DataInitTypeDef config; uint32_t errorstate; uint32_t DmaBase0_reg; @@ -475,11 +475,8 @@ struct SdDomain { config.DPSM = SDMMC_DPSM_DISABLE; (void)SDMMC_ConfigData(hsd->Instance, &config); - //hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST; // I am manually flushing the FIFO here, hal did not do it - __SDMMC_CMDTRANS_ENABLE(hsd->Instance); - //hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; if (instance.current_buffer == BufferSelect::Buffer1) { hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; } else { @@ -529,9 +526,6 @@ struct SdDomain { inst.mpu_buffer0_instance = &mpu_buffer_instances[cfg.mpu_buffer0_idx]; inst.mpu_buffer1_instance = &mpu_buffer_instances[cfg.mpu_buffer1_idx]; - if (!inst.configure_idma()) { - ErrorHandler("SD Card IDMA configuration failed"); - } if (cfg.cd_pin_idx.has_value()) { inst.cd_instance = {&digital_input_instances[cfg.cd_pin_idx.value().first], cfg.cd_pin_idx.value().second}; @@ -547,6 +541,10 @@ struct SdDomain { inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; inst.hsd.Init.ClockDiv = 0; + if (!inst.configure_idma()) { + ErrorHandler("SD Card IDMA configuration failed"); + } + #ifdef SD_DEBUG_ENABLE inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; @@ -568,7 +566,7 @@ struct SdDomain { RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { - ErrorHandler("SDMMC1 clock configuration failed"); + ErrorHandler("SDMMC clock configuration failed"); } if (cfg.peripheral == Peripheral::sdmmc1) { From 4879967216eca1f26f243a8e77ada9af7fb30d2e Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Sun, 14 Dec 2025 21:34:04 +0100 Subject: [PATCH 39/76] fix(Sd): Minor fixes --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 61ad1a44f..817d63667 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -289,9 +289,6 @@ struct SdDomain { return false; // Busy } - instance.operation_flag = &operation_complete_flag; - operation_complete_flag = false; - // Won't use HAL_SDEx_ReadBlocksDMAMultiBuffer because it doesn't support double buffering the way we want HAL_StatusTypeDef status = Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(start_block, num_blocks); @@ -299,6 +296,9 @@ struct SdDomain { ErrorHandler("SD Card read operation failed"); } + instance.operation_flag = &operation_complete_flag; + operation_complete_flag = false; + return true; } @@ -311,9 +311,6 @@ struct SdDomain { return false; // Busy } - instance.operation_flag = &operation_complete_flag; - operation_complete_flag = false; - // Won't use HAL_SDEx_WriteBlocksDMAMultiBuffer because it doesn't support double buffering the way we want HAL_StatusTypeDef status = Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); @@ -321,6 +318,9 @@ struct SdDomain { ErrorHandler("SD Card write operation failed"); } + instance.operation_flag = &operation_complete_flag; + operation_complete_flag = false; + return true; } @@ -516,14 +516,19 @@ struct SdDomain { static void init(std::span cfgs, std::span mpu_buffer_instances, std::span digital_input_instances) { + + // Initialize HAL SD + RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; + RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; + RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { + ErrorHandler("SDMMC clock configuration failed"); + } for (std::size_t i = 0; i < N; i++) { const auto &cfg = cfgs[i]; auto &inst = instances[i]; - inst.cd_instance = {&digital_input_instances[cfg.cd_pin_idx.value().first], cfg.cd_pin_idx.value().second}; - inst.wp_instance = {&digital_input_instances[cfg.wp_pin_idx.value().first], cfg.wp_pin_idx.value().second}; - inst.mpu_buffer0_instance = &mpu_buffer_instances[cfg.mpu_buffer0_idx]; inst.mpu_buffer1_instance = &mpu_buffer_instances[cfg.mpu_buffer1_idx]; @@ -561,14 +566,6 @@ struct SdDomain { inst.card_initialized = false; inst.current_buffer = BufferSelect::Buffer0; - // Initialize HAL SD - RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; - RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; - RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; - if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { - ErrorHandler("SDMMC clock configuration failed"); - } - if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; g_sdmmc1_instance_ptr = &inst; From 72f4ff08d8b3e50eed078707baf79d108761133f Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 09:59:50 +0100 Subject: [PATCH 40/76] fix(Sd): Change throw to compile_error for better compile-time checks --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 817d63667..4aa49f33e 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -102,7 +102,7 @@ struct SdDomain { d2 = GPIODomain::GPIO(PG11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); d3 = GPIODomain::GPIO(PG12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); } else { - throw "Invalid SDMMC peripheral"; + ST_LIB::compile_error("Invalid SDMMC peripheral"); } } @@ -152,6 +152,9 @@ struct SdDomain { template static consteval std::array build(std::span entries) { std::array cfgs{}; + if (N == 0 ) { + return cfgs; + } bool peripheral_used[2] = {false, false}; // SDMMC1, SDMMC2 for (std::size_t i = 0; i < N; i++) { @@ -159,7 +162,7 @@ struct SdDomain { // Verify uniqueness of peripheral usage std::size_t peripheral_index = (e.peripheral == Peripheral::sdmmc1) ? 0 : 1; - if (peripheral_used[peripheral_index]) throw "SDMMC peripheral already used"; + if (peripheral_used[peripheral_index]) ST_LIB::compile_error("SDMMC peripheral used multiple times in SdDomain"); peripheral_used[peripheral_index] = true; // Fill configuration From a80582eb2535250d1b5028569cc9b0173e485ea8 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 10:12:28 +0100 Subject: [PATCH 41/76] fix(Sd): Private accesibility things --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 73 ++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 4aa49f33e..68c02a184 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -187,13 +187,41 @@ struct SdDomain { Buffer1 = true }; + template struct SdCardWrapper; + template struct Init; + // State holder, logic is in SdCardWrapper struct Instance { template friend struct SdCardWrapper; - friend struct Init; + template friend struct Init; bool* operation_flag = nullptr; // External flag to indicate that an operation has finished + // Public handlers called from C HAL callbacks (keeps private members encapsulated) + void on_dma_read_complete() { + if (operation_flag) { + *operation_flag = true; + operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd.Instance); + } + + void on_dma_write_complete() { + if (operation_flag) { + *operation_flag = true; + operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd.Instance); + } + + void on_abort() { + ErrorHandler("SD Card operation aborted"); + } + + void on_error() { + ErrorHandler("SD Card error occurred"); + } + private: SD_HandleTypeDef hsd; @@ -256,6 +284,7 @@ struct SdDomain { template struct SdCardWrapper{ + template friend struct Init; static constexpr bool has_cd = decltype(card_request)::cd.has_value(); static constexpr bool has_wp = decltype(card_request)::wp.has_value(); @@ -608,47 +637,41 @@ extern "C" void SDMMC2_IRQHandler(void) { extern "C" { void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = get_sd_instance(hsd); - if (sd_instance && sd_instance->operation_flag) { - *sd_instance->operation_flag = true; - sd_instance->operation_flag = nullptr; + if (auto sd_instance = get_sd_instance(hsd)) { + sd_instance->on_dma_read_complete(); } - SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = get_sd_instance(hsd); - if (sd_instance && sd_instance->operation_flag) { - *sd_instance->operation_flag = true; - sd_instance->operation_flag = nullptr; + if (auto sd_instance = get_sd_instance(hsd)) { + sd_instance->on_dma_read_complete(); } - SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = get_sd_instance(hsd); - if (sd_instance && sd_instance->operation_flag) { - *sd_instance->operation_flag = true; - sd_instance->operation_flag = nullptr; + if (auto sd_instance = get_sd_instance(hsd)) { + sd_instance->on_dma_write_complete(); } - SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - auto sd_instance = get_sd_instance(hsd); - if (sd_instance && sd_instance->operation_flag) { - *sd_instance->operation_flag = true; - sd_instance->operation_flag = nullptr; + if (auto sd_instance = get_sd_instance(hsd)) { + sd_instance->on_dma_write_complete(); } - SDMMC_CmdStopTransfer(hsd->Instance); } void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { - // auto sd_instance = get_sd_instance(hsd); - ErrorHandler("SD Card operation aborted"); + if (auto sd_instance = get_sd_instance(hsd)) { + sd_instance->on_abort(); + } else { + ErrorHandler("SD Card operation aborted"); + } } void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { - //auto sd_instance = get_sd_instance(hsd); - ErrorHandler("SD Card error occurred"); + if (auto sd_instance = get_sd_instance(hsd)) { + sd_instance->on_error(); + } else { + ErrorHandler("SD Card error occurred"); + } } } // extern "C" From ea5344d957176e1d63f75364f6aa45c238855ab0 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 10:13:54 +0100 Subject: [PATCH 42/76] fix(Sd): Fix inline issue and add dependencies to CMakeLists.txt --- CMakeLists.txt | 1 + Inc/ST-LIB_LOW/Sd/Sd.hpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e015bfde2..af432285b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ if(CMAKE_CROSSCOMPILING) # SD ${HAL_DRIVER_SRC_DIR}/stm32h7xx_hal_sd.c ${HAL_DRIVER_SRC_DIR}/stm32h7xx_hal_sd_ex.c + ${HAL_DRIVER_SRC_DIR}/stm32h7xx_ll_sdmmc.c # CAN / FDCAN ${HAL_DRIVER_SRC_DIR}/stm32h7xx_hal_fdcan.c diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 68c02a184..10b63d952 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -622,13 +622,13 @@ static inline SdDomain::Instance* get_sd_instance(SD_HandleTypeDef* hsd) { return nullptr; } -extern "C" void SDMMC1_IRQHandler(void) { +extern "C" inline void SDMMC1_IRQHandler(void) { if (g_sdmmc1_handle != nullptr) { HAL_SD_IRQHandler(g_sdmmc1_handle); } } -extern "C" void SDMMC2_IRQHandler(void) { +extern "C" inline void SDMMC2_IRQHandler(void) { if (g_sdmmc2_handle != nullptr) { HAL_SD_IRQHandler(g_sdmmc2_handle); } @@ -636,29 +636,29 @@ extern "C" void SDMMC2_IRQHandler(void) { extern "C" { -void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { +inline void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = get_sd_instance(hsd)) { sd_instance->on_dma_read_complete(); } } -void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { +inline void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = get_sd_instance(hsd)) { sd_instance->on_dma_read_complete(); } } -void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { +inline void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = get_sd_instance(hsd)) { sd_instance->on_dma_write_complete(); } } -void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { +inline void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = get_sd_instance(hsd)) { sd_instance->on_dma_write_complete(); } } -void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { +inline void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = get_sd_instance(hsd)) { sd_instance->on_abort(); } else { @@ -666,7 +666,7 @@ void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { } } -void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { +inline void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = get_sd_instance(hsd)) { sd_instance->on_error(); } else { From 19ae0ff7a3f8269d5db620eda4192804fb742e84 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 10:30:58 +0100 Subject: [PATCH 43/76] fix(Sd): Fix GPIO configuration for SD card --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 51 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 10b63d952..667996291 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -77,31 +77,32 @@ struct SdDomain { */ consteval SdCard(Peripheral sdmmc_peripheral, std::optional> card_detect_config, std::optional> write_protect_config, - GPIODomain::Pin d0_pin_for_sdmmc1 = PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = PC9) { - - e.peripheral = sdmmc_peripheral; - - buffer0 = MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1); - buffer1 = MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1); - - cd = card_detect_config; - wp = write_protect_config; - - if (sdmmc_peripheral == Peripheral::sdmmc1) { - cmd = GPIODomain::GPIO(PC6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - ck = GPIODomain::GPIO(PC12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d0 = GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d1 = GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d2 = GPIODomain::GPIO(PC10, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d3 = GPIODomain::GPIO(PC11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - } else if (sdmmc_peripheral == Peripheral::sdmmc2) { - cmd = GPIODomain::GPIO(PD7, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - ck = GPIODomain::GPIO(PD6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d0 = GPIODomain::GPIO(PB14, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d1 = GPIODomain::GPIO(PB15, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d2 = GPIODomain::GPIO(PG11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - d3 = GPIODomain::GPIO(PG12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12); - } else { + GPIODomain::Pin d0_pin_for_sdmmc1 = ST_LIB::PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = ST_LIB::PC9) : + e{.peripheral = sdmmc_peripheral}, + buffer0(MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1)), + buffer1(MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1)), + cd(card_detect_config), + wp(write_protect_config), + cmd((sdmmc_peripheral == Peripheral::sdmmc1) ? + GPIODomain::GPIO(ST_LIB::PC6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PD7, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + ck((sdmmc_peripheral == Peripheral::sdmmc1) ? + GPIODomain::GPIO(ST_LIB::PC12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PD6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + d0((sdmmc_peripheral == Peripheral::sdmmc1) ? + GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PB14, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + d1((sdmmc_peripheral == Peripheral::sdmmc1) ? + GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PB15, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + d2((sdmmc_peripheral == Peripheral::sdmmc1) ? + GPIODomain::GPIO(ST_LIB::PC10, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PG11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + d3((sdmmc_peripheral == Peripheral::sdmmc1) ? + GPIODomain::GPIO(ST_LIB::PC11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PG12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)) + { + if (sdmmc_peripheral != Peripheral::sdmmc1 && sdmmc_peripheral != Peripheral::sdmmc2) { ST_LIB::compile_error("Invalid SDMMC peripheral"); } } From 55cb1b4d66dd732b3d49d924592ab5bfa43e7d68 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 12:27:38 +0100 Subject: [PATCH 44/76] fix(Sd): General bug fixing --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 120 +++++++++++++++++++++++++-------------- 1 file changed, 77 insertions(+), 43 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 667996291..26b043421 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -79,28 +79,29 @@ struct SdDomain { std::optional> card_detect_config, std::optional> write_protect_config, GPIODomain::Pin d0_pin_for_sdmmc1 = ST_LIB::PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = ST_LIB::PC9) : e{.peripheral = sdmmc_peripheral}, + peripheral(sdmmc_peripheral), buffer0(MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1)), buffer1(MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1)), cd(card_detect_config), wp(write_protect_config), cmd((sdmmc_peripheral == Peripheral::sdmmc1) ? - GPIODomain::GPIO(ST_LIB::PC6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : - GPIODomain::GPIO(ST_LIB::PD7, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + GPIODomain::GPIO(ST_LIB::PD2, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PD7, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF11)), ck((sdmmc_peripheral == Peripheral::sdmmc1) ? GPIODomain::GPIO(ST_LIB::PC12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : - GPIODomain::GPIO(ST_LIB::PD6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + GPIODomain::GPIO(ST_LIB::PD6, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF11)), d0((sdmmc_peripheral == Peripheral::sdmmc1) ? GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : - GPIODomain::GPIO(ST_LIB::PB14, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + GPIODomain::GPIO(ST_LIB::PB14, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF9)), d1((sdmmc_peripheral == Peripheral::sdmmc1) ? GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : - GPIODomain::GPIO(ST_LIB::PB15, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + GPIODomain::GPIO(ST_LIB::PB15, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF9)), d2((sdmmc_peripheral == Peripheral::sdmmc1) ? GPIODomain::GPIO(ST_LIB::PC10, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : - GPIODomain::GPIO(ST_LIB::PG11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)), + GPIODomain::GPIO(ST_LIB::PG11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF10)), d3((sdmmc_peripheral == Peripheral::sdmmc1) ? GPIODomain::GPIO(ST_LIB::PC11, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : - GPIODomain::GPIO(ST_LIB::PG12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12)) + GPIODomain::GPIO(ST_LIB::PG12, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF10)) { if (sdmmc_peripheral != Peripheral::sdmmc1 && sdmmc_peripheral != Peripheral::sdmmc2) { ST_LIB::compile_error("Invalid SDMMC peripheral"); @@ -110,24 +111,32 @@ struct SdDomain { template consteval void inscribe(Ctx &ctx) const { - e.mpu_buffer0_idx = ctx.template add(buffer0); - e.mpu_buffer1_idx = ctx.template add(buffer1); + Entry local_e = e; + + local_e.mpu_buffer0_idx = ctx.template add(buffer0.e); + local_e.mpu_buffer1_idx = ctx.template add(buffer1.e); if (cd.has_value()) { - e.cd_pin_idx = {ctx.template add(cd.value().first), cd.value().second}; + auto& di = cd.value().first; + auto gpio_idx = ctx.template add(di.gpio.e); + DigitalInputDomain::Entry di_entry{gpio_idx}; + local_e.cd_pin_idx = {ctx.template add(di_entry), cd.value().second}; } if (wp.has_value()) { - e.wp_pin_idx = {ctx.template add(wp.value().first), wp.value().second}; + auto& di = wp.value().first; + auto gpio_idx = ctx.template add(di.gpio.e); + DigitalInputDomain::Entry di_entry{gpio_idx}; + local_e.wp_pin_idx = {ctx.template add(di_entry), wp.value().second}; } - e.cmd_pin_idx = ctx.template add(cmd); - e.ck_pin_idx = ctx.template add(ck); - e.d0_pin_idx = ctx.template add(d0); - e.d1_pin_idx = ctx.template add(d1); - e.d2_pin_idx = ctx.template add(d2); - e.d3_pin_idx = ctx.template add(d3); + local_e.cmd_pin_idx = ctx.template add(cmd.e); + local_e.ck_pin_idx = ctx.template add(ck.e); + local_e.d0_pin_idx = ctx.template add(d0.e); + local_e.d1_pin_idx = ctx.template add(d1.e); + local_e.d2_pin_idx = ctx.template add(d2.e); + local_e.d3_pin_idx = ctx.template add(d3.e); - ctx.template add(e); + ctx.template add(local_e); } }; @@ -250,6 +259,10 @@ struct SdDomain { if (status != HAL_OK) { return false; } + if (!configure_idma()) { + ErrorHandler("SD Card IDMA configuration failed"); + } + if (HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO) != HAL_OK) { ErrorHandler("SD Card speed/bus configuration failed"); } @@ -286,8 +299,8 @@ struct SdDomain { template struct SdCardWrapper{ template friend struct Init; - static constexpr bool has_cd = decltype(card_request)::cd.has_value(); - static constexpr bool has_wp = decltype(card_request)::wp.has_value(); + static constexpr bool has_cd = card_request.cd.has_value(); + static constexpr bool has_wp = card_request.wp.has_value(); SdCardWrapper(Instance& instance) : instance(instance) { check_cd_wp(); @@ -373,9 +386,9 @@ struct SdDomain { auto& get_current_buffer() { if (instance.current_buffer == BufferSelect::Buffer0) { - return instance.mpu_buffer0_instance->template as(); + return *instance.mpu_buffer0_instance->template as(); } else { - return instance.mpu_buffer1_instance->template as(); + return *instance.mpu_buffer1_instance->template as(); } } @@ -550,12 +563,8 @@ struct SdDomain { std::span mpu_buffer_instances, std::span digital_input_instances) { - // Initialize HAL SD - RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; - RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; - RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; - if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { - ErrorHandler("SDMMC clock configuration failed"); + if (N == 0) { + return; } for (std::size_t i = 0; i < N; i++) { @@ -572,17 +581,17 @@ struct SdDomain { inst.wp_instance = {&digital_input_instances[cfg.wp_pin_idx.value().first], cfg.wp_pin_idx.value().second}; } - inst.hsd.Instance = reinterpret_cast(static_cast(cfg.peripheral)); + if (cfg.peripheral == Peripheral::sdmmc1) { + inst.hsd.Instance = SDMMC1; + } else if (cfg.peripheral == Peripheral::sdmmc2) { + inst.hsd.Instance = SDMMC2; + } inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING; inst.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; inst.hsd.Init.ClockDiv = 0; - if (!inst.configure_idma()) { - ErrorHandler("SD Card IDMA configuration failed"); - } - #ifdef SD_DEBUG_ENABLE inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; @@ -595,23 +604,31 @@ struct SdDomain { inst.hsd.Init.ClockDiv = target_div - 2; // ClockDiv is (divider - 2) #endif // SD_DEBUG_ENABLE - - inst.card_initialized = false; - inst.current_buffer = BufferSelect::Buffer0; - if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; g_sdmmc1_instance_ptr = &inst; - __HAL_RCC_SDMMC1_CLK_ENABLE(); - HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); } else if (cfg.peripheral == Peripheral::sdmmc2) { g_sdmmc2_handle = &inst.hsd; g_sdmmc2_instance_ptr = &inst; - __HAL_RCC_SDMMC2_CLK_ENABLE(); - HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(SDMMC2_IRQn); } + + inst.card_initialized = false; + inst.current_buffer = BufferSelect::Buffer0; + } + + // Initialize HAL SD + RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; + RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; + RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; + if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { + ErrorHandler("SDMMC clock configuration failed"); + } + + // Ensure PLL1Q output is enabled (it might be disabled by default if not used by other peripherals) + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ); + + if (HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC) == 0) { + ErrorHandler("SDMMC clock frequency is 0"); } } }; @@ -623,6 +640,23 @@ static inline SdDomain::Instance* get_sd_instance(SD_HandleTypeDef* hsd) { return nullptr; } +extern "C" inline void HAL_SD_MspInit(SD_HandleTypeDef* hsd) { + if (hsd->Instance == SDMMC1) { + __HAL_RCC_SDMMC1_CLK_ENABLE(); + __HAL_RCC_SDMMC1_FORCE_RESET(); + __HAL_RCC_SDMMC1_RELEASE_RESET(); + HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + + } else { + __HAL_RCC_SDMMC2_CLK_ENABLE(); + __HAL_RCC_SDMMC2_FORCE_RESET(); + __HAL_RCC_SDMMC2_RELEASE_RESET(); + HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(SDMMC2_IRQn); + } +} + extern "C" inline void SDMMC1_IRQHandler(void) { if (g_sdmmc1_handle != nullptr) { HAL_SD_IRQHandler(g_sdmmc1_handle); From 40fc2166a518adbd19a01a5d55c6e359aab5f1b2 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 13:13:26 +0100 Subject: [PATCH 45/76] fix(Sd): Move things to cpp and circular dependency fix --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 83 ++++------------------------------------ Src/ST-LIB_LOW/Sd/Sd.cpp | 80 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 76 deletions(-) create mode 100644 Src/ST-LIB_LOW/Sd/Sd.cpp diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 26b043421..e2f04e090 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -9,19 +9,19 @@ #define SD_HPP #include "HALAL/HALAL.hpp" -#include "ST-LIB_LOW/ST-LIB_LOW.hpp" +#include "ST-LIB_LOW/DigitalInput2.hpp" #include "stm32h7xx_hal.h" #include "ErrorHandler/ErrorHandler.hpp" using ST_LIB::DigitalInputDomain; using ST_LIB::GPIODomain; -static SD_HandleTypeDef* g_sdmmc1_handle = nullptr; -static SD_HandleTypeDef* g_sdmmc2_handle = nullptr; - -static void* g_sdmmc1_instance_ptr = nullptr; -static void* g_sdmmc2_instance_ptr = nullptr; +extern SD_HandleTypeDef* g_sdmmc1_handle; +extern SD_HandleTypeDef* g_sdmmc2_handle; +extern void* g_sdmmc1_instance_ptr; +extern void* g_sdmmc2_instance_ptr; +namespace ST_LIB { struct SdDomain { enum class Peripheral : uint32_t { @@ -640,75 +640,6 @@ static inline SdDomain::Instance* get_sd_instance(SD_HandleTypeDef* hsd) { return nullptr; } -extern "C" inline void HAL_SD_MspInit(SD_HandleTypeDef* hsd) { - if (hsd->Instance == SDMMC1) { - __HAL_RCC_SDMMC1_CLK_ENABLE(); - __HAL_RCC_SDMMC1_FORCE_RESET(); - __HAL_RCC_SDMMC1_RELEASE_RESET(); - HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(SDMMC1_IRQn); - - } else { - __HAL_RCC_SDMMC2_CLK_ENABLE(); - __HAL_RCC_SDMMC2_FORCE_RESET(); - __HAL_RCC_SDMMC2_RELEASE_RESET(); - HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); - HAL_NVIC_EnableIRQ(SDMMC2_IRQn); - } -} - -extern "C" inline void SDMMC1_IRQHandler(void) { - if (g_sdmmc1_handle != nullptr) { - HAL_SD_IRQHandler(g_sdmmc1_handle); - } -} - -extern "C" inline void SDMMC2_IRQHandler(void) { - if (g_sdmmc2_handle != nullptr) { - HAL_SD_IRQHandler(g_sdmmc2_handle); - } -} - -extern "C" { - -inline void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = get_sd_instance(hsd)) { - sd_instance->on_dma_read_complete(); - } -} -inline void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = get_sd_instance(hsd)) { - sd_instance->on_dma_read_complete(); - } -} - -inline void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = get_sd_instance(hsd)) { - sd_instance->on_dma_write_complete(); - } -} -inline void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = get_sd_instance(hsd)) { - sd_instance->on_dma_write_complete(); - } -} - -inline void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = get_sd_instance(hsd)) { - sd_instance->on_abort(); - } else { - ErrorHandler("SD Card operation aborted"); - } -} - -inline void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = get_sd_instance(hsd)) { - sd_instance->on_error(); - } else { - ErrorHandler("SD Card error occurred"); - } -} - -} // extern "C" +} // namespace ST_LIB #endif // SD_HPP \ No newline at end of file diff --git a/Src/ST-LIB_LOW/Sd/Sd.cpp b/Src/ST-LIB_LOW/Sd/Sd.cpp new file mode 100644 index 000000000..88ec5c058 --- /dev/null +++ b/Src/ST-LIB_LOW/Sd/Sd.cpp @@ -0,0 +1,80 @@ +#include "ST-LIB_LOW/Sd/Sd.hpp" + +// 1. Define the globals here (Strong definitions) +SD_HandleTypeDef* g_sdmmc1_handle = nullptr; +SD_HandleTypeDef* g_sdmmc2_handle = nullptr; + +void* g_sdmmc1_instance_ptr = nullptr; +void* g_sdmmc2_instance_ptr = nullptr; + +extern "C" { + +void HAL_SD_MspInit(SD_HandleTypeDef* hsd) { + if (hsd->Instance == SDMMC1) { + __HAL_RCC_SDMMC1_CLK_ENABLE(); + __HAL_RCC_SDMMC1_FORCE_RESET(); + __HAL_RCC_SDMMC1_RELEASE_RESET(); + HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(SDMMC1_IRQn); + } else { + __HAL_RCC_SDMMC2_CLK_ENABLE(); + __HAL_RCC_SDMMC2_FORCE_RESET(); + __HAL_RCC_SDMMC2_RELEASE_RESET(); + HAL_NVIC_SetPriority(SDMMC2_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(SDMMC2_IRQn); + } +} + +void SDMMC1_IRQHandler(void) { + if (g_sdmmc1_handle != nullptr) { + HAL_SD_IRQHandler(g_sdmmc1_handle); + } +} + +void SDMMC2_IRQHandler(void) { + if (g_sdmmc2_handle != nullptr) { + HAL_SD_IRQHandler(g_sdmmc2_handle); + } +} + +void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { + if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { + sd_instance->on_dma_read_complete(); + } +} + +void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { + if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { + sd_instance->on_dma_read_complete(); + } +} + +void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { + if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { + sd_instance->on_dma_write_complete(); + } +} + +void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { + if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { + sd_instance->on_dma_write_complete(); + } +} + +void HAL_SD_AbortCallback(SD_HandleTypeDef* hsd) { + if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { + sd_instance->on_abort(); + } else { + ErrorHandler("SD Card operation aborted"); + } +} + +void HAL_SD_ErrorCallback(SD_HandleTypeDef* hsd) { + if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { + sd_instance->on_error(); + } else { + ErrorHandler("SD Card error occurred"); + } +} + +} // extern "C" \ No newline at end of file From c1be258a7f81712e639fb5151f59f272528eead3 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 16:50:26 +0100 Subject: [PATCH 46/76] fix(Sd): General bugfixing, now works --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 59 ++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index e2f04e090..9485b80b6 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -244,12 +244,16 @@ struct SdDomain { bool card_initialized; BufferSelect current_buffer; // The one that is currently available for CPU access and not used by IDMA + HAL_SD_CardInfoTypeDef card_info; + // Functions bool is_card_present() { return cd_instance->first->read() == cd_instance->second; } bool is_write_protected() { return wp_instance->first->read() == wp_instance->second; } bool is_busy() { - return (hsd.State != HAL_SD_STATE_TRANSFER); + if (!card_initialized) return false; + HAL_SD_StateTypeDef state = HAL_SD_GetState(&hsd); + return (state != HAL_SD_STATE_READY && state != HAL_SD_STATE_TRANSFER); } bool initialize_card() { @@ -259,6 +263,10 @@ struct SdDomain { if (status != HAL_OK) { return false; } + if (HAL_SD_GetCardInfo(&hsd, &card_info) != HAL_OK) { + ErrorHandler("Failed to get SD card info"); + } + if (!configure_idma()) { ErrorHandler("SD Card IDMA configuration failed"); } @@ -326,7 +334,7 @@ struct SdDomain { return instance.card_initialized; } - bool read_blocks(uint32_t start_block, uint32_t num_blocks, bool& operation_complete_flag) { + bool read_blocks(uint32_t start_block, uint32_t num_blocks, bool* operation_complete_flag) { check_cd_wp(); if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); @@ -342,13 +350,13 @@ struct SdDomain { ErrorHandler("SD Card read operation failed"); } - instance.operation_flag = &operation_complete_flag; - operation_complete_flag = false; + instance.operation_flag = operation_complete_flag; + *operation_complete_flag = false; return true; } - bool write_blocks(uint32_t start_block, uint32_t num_blocks, bool& operation_complete_flag) { + bool write_blocks(uint32_t start_block, uint32_t num_blocks, bool* operation_complete_flag) { check_cd_wp(); if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); @@ -364,17 +372,27 @@ struct SdDomain { ErrorHandler("SD Card write operation failed"); } - instance.operation_flag = &operation_complete_flag; - operation_complete_flag = false; + instance.operation_flag = operation_complete_flag; + *operation_complete_flag = false; return true; } + auto* get_current_buffer() { + if (instance.current_buffer == BufferSelect::Buffer0) { + return instance.mpu_buffer0_instance->template as(); + } else { + return instance.mpu_buffer1_instance->template as(); + } + } + + bool is_busy() { + return instance.is_busy(); + } private: Instance& instance; // Actual State - void check_cd_wp() { if constexpr (has_cd) { if (!instance.is_card_present()) { ErrorHandler("SD Card not present"); } @@ -384,14 +402,6 @@ struct SdDomain { } } - auto& get_current_buffer() { - if (instance.current_buffer == BufferSelect::Buffer0) { - return *instance.mpu_buffer0_instance->template as(); - } else { - return *instance.mpu_buffer1_instance->template as(); - } - } - // Variation of HAL_SDEx_ReadBlocksDMAMultiBuffer to fit our needs HAL_StatusTypeDef Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { auto* hsd = &instance.hsd; @@ -445,9 +455,9 @@ struct SdDomain { __SDMMC_CMDTRANS_ENABLE(hsd->Instance); if (instance.current_buffer == BufferSelect::Buffer1) { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; } else { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; } instance.switch_buffer(); @@ -524,9 +534,9 @@ struct SdDomain { __SDMMC_CMDTRANS_ENABLE(hsd->Instance); if (instance.current_buffer == BufferSelect::Buffer1) { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; } else { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; } instance.switch_buffer(); @@ -586,17 +596,18 @@ struct SdDomain { } else if (cfg.peripheral == Peripheral::sdmmc2) { inst.hsd.Instance = SDMMC2; } - inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING; + inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; inst.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; - inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; - inst.hsd.Init.ClockDiv = 0; + inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE; + inst.hsd.Init.ClockDiv = 2; #ifdef SD_DEBUG_ENABLE inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; // Get a 400 kHz clock for debugging - uint32_t pll1_freq = HAL_RCCEx_GetPLL1ClockFreq(); // SDMMC clock source is PLL1 + //uint32_t pll1_freq = HAL_RCCEx_GetPLL1ClockFreq(); // SDMMC clock source is PLL1 + uint32_t pll1_freq = 480000000; // Assume PLL1 is at 480 MHz uint32_t sdmmc_clk = pll1_freq / 2; // SDMMC clock before divider uint32_t target_div = sdmmc_clk / 400000; // Target divider if (target_div < 2) target_div = 2; // Minimum divider is 2 From 17a92ba0ee2628f805e7affe135f45def183d078 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Tue, 16 Dec 2025 17:41:01 +0100 Subject: [PATCH 47/76] fix(Sd): The Sd is too finicky, it needs it's freaking time --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 9485b80b6..231e822a6 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -339,11 +339,26 @@ struct SdDomain { if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); } + + // 1. Wait for the CARD (hardware) to be ready, not just the handle + uint32_t timeout = HAL_GetTick() + 1000; + while (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { + if (HAL_GetTick() > timeout) { + // 2. OPTIONAL: If stuck, try forcing a STOP command to reset the state + SDMMC_CmdStopTransfer(instance.hsd.Instance); + HAL_Delay(10); // Give it a moment + if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { + ErrorHandler("Timeout waiting for SD Card to enter TRANSFER state"); + return false; + } + } + } + if (instance.is_busy()) { - return false; // Busy + return false; // Driver busy } - // Won't use HAL_SDEx_ReadBlocksDMAMultiBuffer because it doesn't support double buffering the way we want + // Now it is safe to send CMD18 HAL_StatusTypeDef status = Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(start_block, num_blocks); if (status != HAL_OK) { @@ -361,10 +376,24 @@ struct SdDomain { if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); } + + // 1. Wait for the CARD (hardware) to be ready, not just the handle + uint32_t timeout = HAL_GetTick() + 1000; + while (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { + if (HAL_GetTick() > timeout) { + // 2. OPTIONAL: If stuck, try forcing a STOP command to reset the state + SDMMC_CmdStopTransfer(instance.hsd.Instance); + HAL_Delay(10); // Give it a moment + if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { + ErrorHandler("Timeout waiting for SD Card to enter TRANSFER state"); + return false; + } + } + } + if (instance.is_busy()) { return false; // Busy } - // Won't use HAL_SDEx_WriteBlocksDMAMultiBuffer because it doesn't support double buffering the way we want HAL_StatusTypeDef status = Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); @@ -596,10 +625,10 @@ struct SdDomain { } else if (cfg.peripheral == Peripheral::sdmmc2) { inst.hsd.Instance = SDMMC2; } - inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING; inst.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; - inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE; + inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; inst.hsd.Init.ClockDiv = 2; From ad4bda06247719f5fc715a3360d8abccfd881503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Wed, 17 Dec 2025 00:32:57 +0100 Subject: [PATCH 48/76] fixed getting wrong instance --- Inc/HALAL/Models/GPIO.hpp | 3 ++- Inc/ST-LIB.hpp | 43 ++----------------------------- Inc/ST-LIB_LOW/DigitalInput2.hpp | 3 ++- Inc/ST-LIB_LOW/DigitalOutput2.hpp | 3 ++- 4 files changed, 8 insertions(+), 44 deletions(-) diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index c19131e37..370f46162 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -172,6 +172,7 @@ struct GPIODomain { struct GPIO { using domain = GPIODomain; + size_t index; Entry e; @@ -184,7 +185,7 @@ struct GPIODomain { } template consteval void inscribe(Ctx &ctx) const { - ctx.template add(e); + index = ctx.template add(e); } }; diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 32fb54814..c17d73f5b 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -126,51 +126,12 @@ template struct Board { // ... } - template - static consteval std::size_t domain_size_for_instance() { - return domain_size(); - } - - template - static consteval std::size_t domain_index_of_impl() { - std::size_t idx = 0; - bool found = false; - - ( - [&] { - using DevT = std::remove_cvref_t; - if constexpr (std::is_same_v) { - if (!found) { - if (&devs == &Target) { - found = true; - } else { - ++idx; - } - } - } - }(), - ...); - - if (!found) { - compile_error("Device not found for domain"); - } - - return idx; - } - - template - static consteval std::size_t domain_index_of() { - return domain_index_of_impl(); - } - template static auto &instance_of() { using DevT = std::remove_cvref_t; using Domain = typename DevT::domain; - constexpr std::size_t idx = domain_index_of(); - constexpr std::size_t N = domain_size_for_instance(); - - return Domain::template Init::instances[idx]; + constexpr std::size_t N = domain_size(); + return Domain::template Init::instances[Target.index]; } }; diff --git a/Inc/ST-LIB_LOW/DigitalInput2.hpp b/Inc/ST-LIB_LOW/DigitalInput2.hpp index e161e39a5..66d95ce0e 100644 --- a/Inc/ST-LIB_LOW/DigitalInput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalInput2.hpp @@ -12,6 +12,7 @@ struct DigitalInputDomain { struct DigitalInput { GPIODomain::GPIO gpio; using domain = DigitalInputDomain; + size_t index; consteval DigitalInput(const GPIODomain::Pin &pin, GPIODomain::Pull pull = GPIODomain::Pull::None, @@ -21,7 +22,7 @@ struct DigitalInputDomain { template consteval void inscribe(Ctx &ctx) const { const auto gpio_idx = ctx.template add(gpio.e); Entry e{.gpio_idx = gpio_idx}; - ctx.template add(e); + index = ctx.template add(e); } }; diff --git a/Inc/ST-LIB_LOW/DigitalOutput2.hpp b/Inc/ST-LIB_LOW/DigitalOutput2.hpp index 7dcad5b65..9d817be05 100644 --- a/Inc/ST-LIB_LOW/DigitalOutput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalOutput2.hpp @@ -18,6 +18,7 @@ struct DigitalOutputDomain { struct DigitalOutput { GPIODomain::GPIO gpio; using domain = DigitalOutputDomain; + size_t index; consteval DigitalOutput(const GPIODomain::Pin &pin, OutputMode mode = OutputMode::PUSH_PULL, @@ -29,7 +30,7 @@ struct DigitalOutputDomain { template consteval void inscribe(Ctx &ctx) const { const auto gpio_idx = ctx.template add(gpio.e); Entry e{.gpio_idx = gpio_idx}; - ctx.template add(e); + index = ctx.template add(e); } }; From 328cca0369c020bd0808e6f66276cf449847e757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Wed, 17 Dec 2025 00:39:39 +0100 Subject: [PATCH 49/76] marked indexs as mutable --- Inc/HALAL/Models/GPIO.hpp | 2 +- Inc/ST-LIB_LOW/DigitalInput2.hpp | 2 +- Inc/ST-LIB_LOW/DigitalOutput2.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index 370f46162..953d8b19f 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -172,7 +172,7 @@ struct GPIODomain { struct GPIO { using domain = GPIODomain; - size_t index; + mutable size_t index; Entry e; diff --git a/Inc/ST-LIB_LOW/DigitalInput2.hpp b/Inc/ST-LIB_LOW/DigitalInput2.hpp index 66d95ce0e..a900b924c 100644 --- a/Inc/ST-LIB_LOW/DigitalInput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalInput2.hpp @@ -12,7 +12,7 @@ struct DigitalInputDomain { struct DigitalInput { GPIODomain::GPIO gpio; using domain = DigitalInputDomain; - size_t index; + mutable size_t index; consteval DigitalInput(const GPIODomain::Pin &pin, GPIODomain::Pull pull = GPIODomain::Pull::None, diff --git a/Inc/ST-LIB_LOW/DigitalOutput2.hpp b/Inc/ST-LIB_LOW/DigitalOutput2.hpp index 9d817be05..8889691b4 100644 --- a/Inc/ST-LIB_LOW/DigitalOutput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalOutput2.hpp @@ -18,7 +18,7 @@ struct DigitalOutputDomain { struct DigitalOutput { GPIODomain::GPIO gpio; using domain = DigitalOutputDomain; - size_t index; + mutable size_t index; consteval DigitalOutput(const GPIODomain::Pin &pin, OutputMode mode = OutputMode::PUSH_PULL, From 804e7b9870d96e14f789f00d15daaddad88de58b Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 07:58:19 +0100 Subject: [PATCH 50/76] fix(MPU): Implemente st-lib fix --- Inc/HALAL/Models/MPU.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index fc3649f0b..f447d2d1b 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -57,6 +57,7 @@ struct MPUDomain { using domain = MPUDomain; using buffer_type = T; Entry e; + mutable size_t index; /** * @brief Constructs a Buffer entry for a type T. @@ -77,7 +78,7 @@ struct MPUDomain { template consteval void inscribe(Ctx &ctx) const { - ctx.template add(e); + index = ctx.template add(e); } }; From a58ffdb9ec45cdd09e9a0c4f48f393a45066279d Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 08:10:04 +0100 Subject: [PATCH 51/76] fix(Sd): Implemenent st-lib fix --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 231e822a6..8940320dc 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -49,6 +49,7 @@ struct SdDomain { struct SdCard { using domain = SdDomain; Entry e; + mutable size_t index; Peripheral peripheral; @@ -136,7 +137,7 @@ struct SdDomain { local_e.d2_pin_idx = ctx.template add(d2.e); local_e.d3_pin_idx = ctx.template add(d3.e); - ctx.template add(local_e); + index = ctx.template add(local_e); } }; From e74ed3903eb2b9e6209188cc80800637d1ccd832 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 08:19:15 +0100 Subject: [PATCH 52/76] fix(Sd): Validate pin selection for SDMMC1 --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 8940320dc..68b4b034a 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -72,13 +72,12 @@ struct SdDomain { * @param sdmmc_peripheral The SDMMC peripheral to use (Peripheral::sdmmc1 or Peripheral::sdmmc2) * @param card_detect_config Optional Card Detect pin (DigitalInputDomain::DigitalInput) and its active state, or nullopt for none * @param write_protect_config Optional Write Protect pin (DigitalInputDomain::DigitalInput) and its active state, or nullopt for none - * @param d0_pin_for_sdmmc1 D0 pin to use if using SDMMC1 (default PC8) - * @param d1_pin_for_sdmmc1 D1 pin to use if using SDMMC1 (default PC9) - * @note The other pins (CMD, CK, D2, D3) are fixed for each peripheral. + * @param d0_pin_for_sdmmc1 D0 pin to use if using SDMMC1 (default PC8, can also be PB13). + * @note The other pins (CMD, CK, D1, D2, D3) are fixed for each peripheral. */ consteval SdCard(Peripheral sdmmc_peripheral, std::optional> card_detect_config, std::optional> write_protect_config, - GPIODomain::Pin d0_pin_for_sdmmc1 = ST_LIB::PC8, GPIODomain::Pin d1_pin_for_sdmmc1 = ST_LIB::PC9) : + GPIODomain::Pin d0_pin_for_sdmmc1 = ST_LIB::PC8) : e{.peripheral = sdmmc_peripheral}, peripheral(sdmmc_peripheral), buffer0(MPUDomain::Buffer>(MPUDomain::MemoryType::NonCached, MPUDomain::MemoryDomain::D1)), @@ -107,6 +106,9 @@ struct SdDomain { if (sdmmc_peripheral != Peripheral::sdmmc1 && sdmmc_peripheral != Peripheral::sdmmc2) { ST_LIB::compile_error("Invalid SDMMC peripheral"); } + if (d0_pin_for_sdmmc1 != ST_LIB::PC8 && d0_pin_for_sdmmc1 != ST_LIB::PB13) { + ST_LIB::compile_error("D0 pin can only be PC8 or PB13 for SDMMC1"); + } } From 3edf7d50068172dc9cca9075e860788c95c9e107 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 08:54:47 +0100 Subject: [PATCH 53/76] style(Sd): Move things to .cpp and small style fixes --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 296 +++++---------------------------------- Src/ST-LIB_LOW/Sd/Sd.cpp | 225 ++++++++++++++++++++++++++++- 2 files changed, 256 insertions(+), 265 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 68b4b034a..60841d101 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -94,7 +94,7 @@ struct SdDomain { GPIODomain::GPIO(d0_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : GPIODomain::GPIO(ST_LIB::PB14, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF9)), d1((sdmmc_peripheral == Peripheral::sdmmc1) ? - GPIODomain::GPIO(d1_pin_for_sdmmc1, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : + GPIODomain::GPIO(ST_LIB::PC9, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : GPIODomain::GPIO(ST_LIB::PB15, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF9)), d2((sdmmc_peripheral == Peripheral::sdmmc1) ? GPIODomain::GPIO(ST_LIB::PC10, GPIODomain::OperationMode::ALT_PP, GPIODomain::Pull::None, GPIODomain::Speed::VeryHigh, GPIODomain::AlternateFunction::AF12) : @@ -106,7 +106,9 @@ struct SdDomain { if (sdmmc_peripheral != Peripheral::sdmmc1 && sdmmc_peripheral != Peripheral::sdmmc2) { ST_LIB::compile_error("Invalid SDMMC peripheral"); } - if (d0_pin_for_sdmmc1 != ST_LIB::PC8 && d0_pin_for_sdmmc1 != ST_LIB::PB13) { + if ((d0_pin_for_sdmmc1.pin != ST_LIB::PC8.pin) && (d0_pin_for_sdmmc1.port != ST_LIB::PC8.port) + && + (d0_pin_for_sdmmc1.pin != ST_LIB::PB13.pin) && (d0_pin_for_sdmmc1.port != ST_LIB::PB13.port)) { ST_LIB::compile_error("D0 pin can only be PC8 or PB13 for SDMMC1"); } } @@ -178,7 +180,6 @@ struct SdDomain { if (peripheral_used[peripheral_index]) ST_LIB::compile_error("SDMMC peripheral used multiple times in SdDomain"); peripheral_used[peripheral_index] = true; - // Fill configuration cfgs[i].peripheral = e.peripheral; cfgs[i].mpu_buffer0_idx = e.mpu_buffer0_idx; cfgs[i].mpu_buffer1_idx = e.mpu_buffer1_idx; @@ -208,32 +209,13 @@ struct SdDomain { template friend struct SdCardWrapper; template friend struct Init; - bool* operation_flag = nullptr; // External flag to indicate that an operation has finished - - // Public handlers called from C HAL callbacks (keeps private members encapsulated) - void on_dma_read_complete() { - if (operation_flag) { - *operation_flag = true; - operation_flag = nullptr; - } - SDMMC_CmdStopTransfer(hsd.Instance); - } - - void on_dma_write_complete() { - if (operation_flag) { - *operation_flag = true; - operation_flag = nullptr; - } - SDMMC_CmdStopTransfer(hsd.Instance); - } - - void on_abort() { - ErrorHandler("SD Card operation aborted"); - } - - void on_error() { - ErrorHandler("SD Card error occurred"); - } + bool* operation_flag = nullptr; // External flag to indicate that an operation has finished. Only public so that it can be set in the public handlers below. + + // Public handlers called from C HAL callbacks. Don't use them, don't even think about using them. + void on_dma_read_complete(); + void on_dma_write_complete(); + void on_abort(); + void on_error(); private: SD_HandleTypeDef hsd; @@ -245,71 +227,25 @@ struct SdDomain { std::optional> wp_instance; bool card_initialized; - BufferSelect current_buffer; // The one that is currently available for CPU access and not used by IDMA + BufferSelect current_buffer; // The one that is currently available for CPU access and not being used by IDMA HAL_SD_CardInfoTypeDef card_info; // Functions - bool is_card_present() { return cd_instance->first->read() == cd_instance->second; } - bool is_write_protected() { return wp_instance->first->read() == wp_instance->second; } - - bool is_busy() { - if (!card_initialized) return false; - HAL_SD_StateTypeDef state = HAL_SD_GetState(&hsd); - return (state != HAL_SD_STATE_READY && state != HAL_SD_STATE_TRANSFER); - } - - bool initialize_card() { - if (card_initialized) { return true; } // Already initialized - - HAL_StatusTypeDef status = HAL_SD_Init(&hsd); - - if (status != HAL_OK) { return false; } - - if (HAL_SD_GetCardInfo(&hsd, &card_info) != HAL_OK) { - ErrorHandler("Failed to get SD card info"); - } - - if (!configure_idma()) { - ErrorHandler("SD Card IDMA configuration failed"); - } - - if (HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO) != HAL_OK) { - ErrorHandler("SD Card speed/bus configuration failed"); - } - - card_initialized = true; - return true; - } - - bool deinitialize_card() { - if (!card_initialized) { return true; } // Already deinitialized - - HAL_StatusTypeDef status = HAL_SD_DeInit(&hsd); - if (status != HAL_OK) { return false; } - - card_initialized = false; - return true; - } - - void switch_buffer() { - current_buffer = (current_buffer == BufferSelect::Buffer0) ? BufferSelect::Buffer1 : BufferSelect::Buffer0; - } - - bool configure_idma() { - HAL_StatusTypeDef status = HAL_SDEx_ConfigDMAMultiBuffer(&hsd, - reinterpret_cast(mpu_buffer0_instance->ptr), - reinterpret_cast(mpu_buffer1_instance->ptr), - mpu_buffer0_instance->size / 512); // Number of 512B-blocks - - if (status != HAL_OK) { return false; } - return true; - } + bool is_card_present(); + bool is_write_protected(); + bool is_busy(); + bool initialize_card(); + bool deinitialize_card(); + void switch_buffer(); + bool configure_idma(); + // Variation of HAL_SDEx_ReadBlocksDMAMultiBuffer to fit our needs + HAL_StatusTypeDef Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks); + HAL_StatusTypeDef Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks); }; template struct SdCardWrapper{ - template friend struct Init; static constexpr bool has_cd = card_request.cd.has_value(); static constexpr bool has_wp = card_request.wp.has_value(); @@ -343,11 +279,11 @@ struct SdDomain { ErrorHandler("SD Card not initialized"); } - // 1. Wait for the CARD (hardware) to be ready, not just the handle + // Wait for the CARD (hardware) to be ready, not just the handle uint32_t timeout = HAL_GetTick() + 1000; while (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { if (HAL_GetTick() > timeout) { - // 2. OPTIONAL: If stuck, try forcing a STOP command to reset the state + // Try to force a STOP command to reset the state, just in case SDMMC_CmdStopTransfer(instance.hsd.Instance); HAL_Delay(10); // Give it a moment if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { @@ -357,12 +293,8 @@ struct SdDomain { } } - if (instance.is_busy()) { - return false; // Driver busy - } - - // Now it is safe to send CMD18 - HAL_StatusTypeDef status = Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(start_block, num_blocks); + // Won't use HAL_SDEx_ReadBlocksDMAMultiBuffer because it doesn't support double buffering the way we want + HAL_StatusTypeDef status = instance.Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(start_block, num_blocks); if (status != HAL_OK) { ErrorHandler("SD Card read operation failed"); @@ -380,11 +312,11 @@ struct SdDomain { ErrorHandler("SD Card not initialized"); } - // 1. Wait for the CARD (hardware) to be ready, not just the handle + // Wait for the CARD (hardware) to be ready, not just the handle uint32_t timeout = HAL_GetTick() + 1000; while (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { if (HAL_GetTick() > timeout) { - // 2. OPTIONAL: If stuck, try forcing a STOP command to reset the state + // Try to force a STOP command to reset the state, just in case SDMMC_CmdStopTransfer(instance.hsd.Instance); HAL_Delay(10); // Give it a moment if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { @@ -393,12 +325,8 @@ struct SdDomain { } } } - - if (instance.is_busy()) { - return false; // Busy - } // Won't use HAL_SDEx_WriteBlocksDMAMultiBuffer because it doesn't support double buffering the way we want - HAL_StatusTypeDef status = Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); + HAL_StatusTypeDef status = instance.Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); if (status != HAL_OK) { ErrorHandler("SD Card write operation failed"); @@ -433,167 +361,6 @@ struct SdDomain { if (instance.is_write_protected()) { ErrorHandler("SD Card is write-protected"); } } } - - // Variation of HAL_SDEx_ReadBlocksDMAMultiBuffer to fit our needs - HAL_StatusTypeDef Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { - auto* hsd = &instance.hsd; - SDMMC_DataInitTypeDef config; - uint32_t errorstate; - uint32_t DmaBase0_reg; - uint32_t DmaBase1_reg; - uint32_t add = BlockAdd; - - if (hsd->State == HAL_SD_STATE_READY) - { - if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) - { - hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; - return HAL_ERROR; - } - - DmaBase0_reg = hsd->Instance->IDMABASE0; - DmaBase1_reg = hsd->Instance->IDMABASE1; - - if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U)) - { - hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE; - return HAL_ERROR; - } - - /* Initialize data control register */ - hsd->Instance->DCTRL = 0; - /* Clear old Flags*/ - __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); - - hsd->ErrorCode = HAL_SD_ERROR_NONE; - hsd->State = HAL_SD_STATE_BUSY; - - if (hsd->SdCard.CardType != CARD_SDHC_SDXC) - { - add *= 512U; - } - - /* Configure the SD DPSM (Data Path State Machine) */ - config.DataTimeOut = SDMMC_DATATIMEOUT; - config.DataLength = BLOCKSIZE * NumberOfBlocks; - config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; - config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; - config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; - config.DPSM = SDMMC_DPSM_DISABLE; - (void)SDMMC_ConfigData(hsd->Instance, &config); - - hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST; - - __SDMMC_CMDTRANS_ENABLE(hsd->Instance); - - if (instance.current_buffer == BufferSelect::Buffer1) { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; - } else { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; - } - instance.switch_buffer(); - - /* Read Blocks in DMA mode */ - hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA); - - /* Read Multi Block command */ - errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); - if (errorstate != HAL_SD_ERROR_NONE) - { - hsd->State = HAL_SD_STATE_READY; - hsd->ErrorCode |= errorstate; - return HAL_ERROR; - } - - __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND | - SDMMC_IT_IDMABTC)); - - return HAL_OK; - } - else - { - return HAL_BUSY; - } - - } - - // Variation of HAL_SDEx_WriteBlocksDMAMultiBuffer to fit our needs - HAL_StatusTypeDef Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { - auto* hsd = &instance.hsd; - SDMMC_DataInitTypeDef config; - uint32_t errorstate; - uint32_t DmaBase0_reg; - uint32_t DmaBase1_reg; - uint32_t add = BlockAdd; - - if (hsd->State == HAL_SD_STATE_READY) - { - if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) - { - hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; - return HAL_ERROR; - } - - DmaBase0_reg = hsd->Instance->IDMABASE0; - DmaBase1_reg = hsd->Instance->IDMABASE1; - if ((hsd->Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U)) - { - hsd->ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE; - return HAL_ERROR; - } - - /* Initialize data control register */ - hsd->Instance->DCTRL = 0; - - hsd->ErrorCode = HAL_SD_ERROR_NONE; - - hsd->State = HAL_SD_STATE_BUSY; - - if (hsd->SdCard.CardType != CARD_SDHC_SDXC) - { - add *= 512U; - } - - /* Configure the SD DPSM (Data Path State Machine) */ - config.DataTimeOut = SDMMC_DATATIMEOUT; - config.DataLength = BLOCKSIZE * NumberOfBlocks; - config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; - config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; - config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; - config.DPSM = SDMMC_DPSM_DISABLE; - (void)SDMMC_ConfigData(hsd->Instance, &config); - - __SDMMC_CMDTRANS_ENABLE(hsd->Instance); - - if (instance.current_buffer == BufferSelect::Buffer1) { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; - } else { - hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; - } - instance.switch_buffer(); - - /* Write Blocks in DMA mode */ - hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA); - - /* Write Multi Block command */ - errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); - if (errorstate != HAL_SD_ERROR_NONE) - { - hsd->State = HAL_SD_STATE_READY; - hsd->ErrorCode |= errorstate; - return HAL_ERROR; - } - - __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND | - SDMMC_IT_IDMABTC)); - - return HAL_OK; - } - else - { - return HAL_BUSY; - } - } }; @@ -636,6 +403,7 @@ struct SdDomain { #ifdef SD_DEBUG_ENABLE + // Doesn't really work in this moment, need to actually get the PLL1 frequency somehow inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; // Get a 400 kHz clock for debugging //uint32_t pll1_freq = HAL_RCCEx_GetPLL1ClockFreq(); // SDMMC clock source is PLL1 @@ -664,10 +432,10 @@ struct SdDomain { RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SDMMC; RCC_PeriphCLKInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; if (HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { - ErrorHandler("SDMMC clock configuration failed"); + ErrorHandler("SDMMC clock configuration failed, maybe try with a slower clock or higher divider?"); } - // Ensure PLL1Q output is enabled (it might be disabled by default if not used by other peripherals) + // Ensure PLL1Q output is enabled __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVQ); if (HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SDMMC) == 0) { diff --git a/Src/ST-LIB_LOW/Sd/Sd.cpp b/Src/ST-LIB_LOW/Sd/Sd.cpp index 88ec5c058..806416b58 100644 --- a/Src/ST-LIB_LOW/Sd/Sd.cpp +++ b/Src/ST-LIB_LOW/Sd/Sd.cpp @@ -1,6 +1,229 @@ #include "ST-LIB_LOW/Sd/Sd.hpp" -// 1. Define the globals here (Strong definitions) + +using namespace ST_LIB; + +void SdDomain::Instance::on_dma_read_complete() { + if (operation_flag) { + *operation_flag = true; + operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd.Instance); +} + +void SdDomain::Instance::on_dma_write_complete() { + if (operation_flag) { + *operation_flag = true; + operation_flag = nullptr; + } + SDMMC_CmdStopTransfer(hsd.Instance); +} + +void SdDomain::Instance::on_abort() { ErrorHandler("SD Card operation aborted"); } + +void SdDomain::Instance::on_error() { ErrorHandler("SD Card error occurred"); } + +bool SdDomain::Instance::is_card_present() { return cd_instance->first->read() == cd_instance->second; } +bool SdDomain::Instance::is_write_protected() { return wp_instance->first->read() == wp_instance->second; } + +bool SdDomain::Instance::is_busy() { + if (!card_initialized) return false; + return (hsd.State == HAL_SD_STATE_BUSY) || (hsd.State == HAL_SD_STATE_PROGRAMMING) || (hsd.State == HAL_SD_STATE_RECEIVING); +} + +bool SdDomain::Instance::initialize_card() { + if (card_initialized) { return true; } // Already initialized + + HAL_StatusTypeDef status = HAL_SD_Init(&hsd); + if (status != HAL_OK) { + return false; + } + + if (HAL_SD_GetCardInfo(&hsd, &card_info) != HAL_OK) { + return false; + } + + if (!configure_idma()) { + return false; + } + + if (HAL_SD_ConfigSpeedBusOperation(&hsd, SDMMC_SPEED_MODE_AUTO) != HAL_OK) { + return false; + } + + card_initialized = true; + return true; +} + +bool SdDomain::Instance::deinitialize_card() { + if (!card_initialized) { return true; } // Already deinitialized + + HAL_StatusTypeDef status = HAL_SD_DeInit(&hsd); + if (status != HAL_OK) { + return false; + } + + card_initialized = false; + return true; +} + +void SdDomain::Instance::switch_buffer() { + current_buffer = (current_buffer == BufferSelect::Buffer0) ? BufferSelect::Buffer1 : BufferSelect::Buffer0; +} + +bool SdDomain::Instance::configure_idma() { + HAL_StatusTypeDef status = HAL_SDEx_ConfigDMAMultiBuffer(&hsd, + reinterpret_cast(mpu_buffer0_instance->ptr), + reinterpret_cast(mpu_buffer1_instance->ptr), + mpu_buffer0_instance->size / 512); // Number of 512B-blocks + + if (status != HAL_OK) { return false; } + return true; +} + +HAL_StatusTypeDef SdDomain::Instance::Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t DmaBase0_reg; + uint32_t DmaBase1_reg; + uint32_t add = BlockAdd; + + if (hsd.State == HAL_SD_STATE_READY) { + if ((add + NumberOfBlocks) > (hsd.SdCard.LogBlockNbr)) { + hsd.ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + DmaBase0_reg = hsd.Instance->IDMABASE0; + DmaBase1_reg = hsd.Instance->IDMABASE1; + + if ((hsd.Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U)) { + hsd.ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + /* Initialize data control register */ + hsd.Instance->DCTRL = 0; + /* Clear old Flags*/ + __HAL_SD_CLEAR_FLAG(&hsd, SDMMC_STATIC_DATA_FLAGS); + + hsd.ErrorCode = HAL_SD_ERROR_NONE; + hsd.State = HAL_SD_STATE_BUSY; + + if (hsd.SdCard.CardType != CARD_SDHC_SDXC) { + add *= 512U; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd.Instance, &config); + + hsd.Instance->DCTRL |= SDMMC_DCTRL_FIFORST; + + __SDMMC_CMDTRANS_ENABLE(hsd.Instance); + if (current_buffer == BufferSelect::Buffer1) { + hsd.Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + } else { + hsd.Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; + } + switch_buffer(); + + /* Read Blocks in DMA mode */ + hsd.Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA); + + /* Read Multi Block command */ + errorstate = SDMMC_CmdReadMultiBlock(hsd.Instance, add); + if (errorstate != HAL_SD_ERROR_NONE) { + hsd.State = HAL_SD_STATE_READY; + hsd.ErrorCode |= errorstate; + return HAL_ERROR; + } + + __HAL_SD_ENABLE_IT(&hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND | + SDMMC_IT_IDMABTC)); + + return HAL_OK; + } + else { + return HAL_BUSY; + } +} + +HAL_StatusTypeDef SdDomain::Instance::Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uint32_t BlockAdd, uint32_t NumberOfBlocks) { + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t DmaBase0_reg; + uint32_t DmaBase1_reg; + uint32_t add = BlockAdd; + + if (hsd.State == HAL_SD_STATE_READY) { + if ((add + NumberOfBlocks) > (hsd.SdCard.LogBlockNbr)) { + hsd.ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + DmaBase0_reg = hsd.Instance->IDMABASE0; + DmaBase1_reg = hsd.Instance->IDMABASE1; + if ((hsd.Instance->IDMABSIZE == 0U) || (DmaBase0_reg == 0U) || (DmaBase1_reg == 0U)) { + hsd.ErrorCode = HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + /* Initialize data control register */ + hsd.Instance->DCTRL = 0; + + hsd.ErrorCode = HAL_SD_ERROR_NONE; + + hsd.State = HAL_SD_STATE_BUSY; + if (hsd.SdCard.CardType != CARD_SDHC_SDXC) { + add *= 512U; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd.Instance, &config); + + __SDMMC_CMDTRANS_ENABLE(hsd.Instance); + + if (current_buffer == BufferSelect::Buffer1) { + hsd.Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF1; + } else { + hsd.Instance->IDMACTRL = SDMMC_ENABLE_IDMA_DOUBLE_BUFF0; + } + switch_buffer(); + + /* Write Blocks in DMA mode */ + hsd.Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA); + + /* Write Multi Block command */ + errorstate = SDMMC_CmdWriteMultiBlock(hsd.Instance, add); + if (errorstate != HAL_SD_ERROR_NONE) { + hsd.State = HAL_SD_STATE_READY; + hsd.ErrorCode |= errorstate; + return HAL_ERROR; + } + + __HAL_SD_ENABLE_IT(&hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND | + SDMMC_IT_IDMABTC)); + + return HAL_OK; + } + else { + return HAL_BUSY; + } +} + + SD_HandleTypeDef* g_sdmmc1_handle = nullptr; SD_HandleTypeDef* g_sdmmc2_handle = nullptr; From f47c0ba739d4c1f20834dd1f2e562b41ef7f6160 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 08:58:58 +0100 Subject: [PATCH 54/76] feat(Sd): Don't use a timeout but just return false if sd not ready --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 60841d101..bd94a7664 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -279,18 +279,8 @@ struct SdDomain { ErrorHandler("SD Card not initialized"); } - // Wait for the CARD (hardware) to be ready, not just the handle - uint32_t timeout = HAL_GetTick() + 1000; - while (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { - if (HAL_GetTick() > timeout) { - // Try to force a STOP command to reset the state, just in case - SDMMC_CmdStopTransfer(instance.hsd.Instance); - HAL_Delay(10); // Give it a moment - if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { - ErrorHandler("Timeout waiting for SD Card to enter TRANSFER state"); - return false; - } - } + if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { + return false; // Card not ready for data transfer } // Won't use HAL_SDEx_ReadBlocksDMAMultiBuffer because it doesn't support double buffering the way we want @@ -312,18 +302,8 @@ struct SdDomain { ErrorHandler("SD Card not initialized"); } - // Wait for the CARD (hardware) to be ready, not just the handle - uint32_t timeout = HAL_GetTick() + 1000; - while (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { - if (HAL_GetTick() > timeout) { - // Try to force a STOP command to reset the state, just in case - SDMMC_CmdStopTransfer(instance.hsd.Instance); - HAL_Delay(10); // Give it a moment - if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { - ErrorHandler("Timeout waiting for SD Card to enter TRANSFER state"); - return false; - } - } + if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { + return false; // Card not ready for data transfer } // Won't use HAL_SDEx_WriteBlocksDMAMultiBuffer because it doesn't support double buffering the way we want HAL_StatusTypeDef status = instance.Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(start_block, num_blocks); From 616d579cf0bf656c4fcebef6e1ef7323cfd5d41c Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 09:20:00 +0100 Subject: [PATCH 55/76] fix(Sd): Check that not too many blocks are being requested for write/read --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index bd94a7664..9b90d66d7 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -278,6 +278,9 @@ struct SdDomain { if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); } + if (num_blocs > instance.mpu_buffer0_instance->size / 512) { + ErrorHandler("Too many blocks requested to write in SD"); + } if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { return false; // Card not ready for data transfer @@ -301,6 +304,9 @@ struct SdDomain { if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); } + if (num_blocs > instance.mpu_buffer0_instance->size / 512) { + ErrorHandler("Too many blocks requested to write in SD"); + } if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { return false; // Card not ready for data transfer From 13589f149425b7389ccea8c77c179fc5c5188699 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 10:27:05 +0100 Subject: [PATCH 56/76] fix(Sd): Typo --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 9b90d66d7..f34f761b4 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -278,7 +278,7 @@ struct SdDomain { if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); } - if (num_blocs > instance.mpu_buffer0_instance->size / 512) { + if (num_blocks > instance.mpu_buffer0_instance->size / 512) { ErrorHandler("Too many blocks requested to write in SD"); } @@ -304,7 +304,7 @@ struct SdDomain { if (!instance.card_initialized) { ErrorHandler("SD Card not initialized"); } - if (num_blocs > instance.mpu_buffer0_instance->size / 512) { + if (num_blocks > instance.mpu_buffer0_instance->size / 512) { ErrorHandler("Too many blocks requested to write in SD"); } From c768655ab33a32990c0850b6f81db402468065d6 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 16:18:08 +0100 Subject: [PATCH 57/76] fix(Sd): Check limit of blocks --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index f34f761b4..ea226a80d 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -111,6 +111,11 @@ struct SdDomain { (d0_pin_for_sdmmc1.pin != ST_LIB::PB13.pin) && (d0_pin_for_sdmmc1.port != ST_LIB::PB13.port)) { ST_LIB::compile_error("D0 pin can only be PC8 or PB13 for SDMMC1"); } + if (buffer_blocks == 0) { + ST_LIB::compile_error("Buffer blocks must be greater than 0"); + } else if (buffer_blocks > 15) { + ST_LIB::compile_error("Buffer blocks must be less than or equal to 15"); + } } From 25f1ba839c6bb37639fa74948006962228dd0677 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 17 Dec 2025 16:18:41 +0100 Subject: [PATCH 58/76] fix(Sd): Unnecesary operation --- Src/ST-LIB_LOW/Sd/Sd.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Src/ST-LIB_LOW/Sd/Sd.cpp b/Src/ST-LIB_LOW/Sd/Sd.cpp index 806416b58..178c9021a 100644 --- a/Src/ST-LIB_LOW/Sd/Sd.cpp +++ b/Src/ST-LIB_LOW/Sd/Sd.cpp @@ -123,7 +123,7 @@ HAL_StatusTypeDef SdDomain::Instance::Not_HAL_SDEx_ReadBlocksDMAMultiBuffer(uint config.DPSM = SDMMC_DPSM_DISABLE; (void)SDMMC_ConfigData(hsd.Instance, &config); - hsd.Instance->DCTRL |= SDMMC_DCTRL_FIFORST; + // hsd.Instance->DCTRL |= SDMMC_DCTRL_FIFORST; __SDMMC_CMDTRANS_ENABLE(hsd.Instance); if (current_buffer == BufferSelect::Buffer1) { @@ -193,6 +193,8 @@ HAL_StatusTypeDef SdDomain::Instance::Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uin config.DPSM = SDMMC_DPSM_DISABLE; (void)SDMMC_ConfigData(hsd.Instance, &config); + // hsd.Instance->DCTRL |= SDMMC_DCTRL_FIFORST; + __SDMMC_CMDTRANS_ENABLE(hsd.Instance); if (current_buffer == BufferSelect::Buffer1) { From f27035cc0d9cbef462507fcbc7595dd81a1646e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Thu, 18 Dec 2025 00:04:37 +0100 Subject: [PATCH 59/76] Fixed instance_of method. Now add interface needs the Device --- Inc/HALAL/Models/GPIO.hpp | 3 +-- Inc/ST-LIB.hpp | 33 ++++++++++++++++++++++++++++--- Inc/ST-LIB_LOW/DigitalInput2.hpp | 5 ++--- Inc/ST-LIB_LOW/DigitalOutput2.hpp | 5 ++--- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Inc/HALAL/Models/GPIO.hpp b/Inc/HALAL/Models/GPIO.hpp index 953d8b19f..e69c94c16 100644 --- a/Inc/HALAL/Models/GPIO.hpp +++ b/Inc/HALAL/Models/GPIO.hpp @@ -172,7 +172,6 @@ struct GPIODomain { struct GPIO { using domain = GPIODomain; - mutable size_t index; Entry e; @@ -185,7 +184,7 @@ struct GPIODomain { } template consteval void inscribe(Ctx &ctx) const { - index = ctx.template add(e); + ctx.template add(e, this); } }; diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index c17d73f5b..221035b08 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -32,6 +32,7 @@ template struct BuildCtx { static constexpr std::size_t max_count_v = D::max_instances; std::tuple, max_count_v>...> storage{}; + std::tuple>...> owners{}; std::array sizes{}; template @@ -47,12 +48,17 @@ template struct BuildCtx { } } - template consteval std::size_t add(typename D::Entry e) { + template + consteval std::size_t add(typename D::Entry e, const Owner *owner) { constexpr std::size_t I = domain_index(); auto &arr = std::get(storage); + auto &own = std::get(owners); auto &size = sizes[I]; + const auto idx = size; - arr[size++] = e; + arr[size] = e; + own[size] = owner; + ++size; return idx; } @@ -64,6 +70,13 @@ template struct BuildCtx { return std::span{arr.data(), size}; } + template consteval auto owners_span() const { + constexpr std::size_t I = domain_index(); + auto const &arr = std::get(owners); + auto const size = sizes[I]; + return std::span{arr.data(), size}; + } + template consteval std::size_t size() const { constexpr std::size_t I = domain_index(); return sizes[I]; @@ -126,12 +139,26 @@ template struct Board { // ... } + template + static consteval std::size_t owner_index_of() { + constexpr auto owners = ctx.template owners_span(); + + if constexpr (I >= owners.size()) { + compile_error("Device not registered in domain"); + return 0; + } else { + return owners[I] == &Target ? I : owner_index_of(); + } + } + template static auto &instance_of() { using DevT = std::remove_cvref_t; using Domain = typename DevT::domain; + constexpr std::size_t idx = owner_index_of(); + constexpr std::size_t N = domain_size(); - return Domain::template Init::instances[Target.index]; + return Domain::template Init::instances[idx]; } }; diff --git a/Inc/ST-LIB_LOW/DigitalInput2.hpp b/Inc/ST-LIB_LOW/DigitalInput2.hpp index a900b924c..4dec87413 100644 --- a/Inc/ST-LIB_LOW/DigitalInput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalInput2.hpp @@ -12,7 +12,6 @@ struct DigitalInputDomain { struct DigitalInput { GPIODomain::GPIO gpio; using domain = DigitalInputDomain; - mutable size_t index; consteval DigitalInput(const GPIODomain::Pin &pin, GPIODomain::Pull pull = GPIODomain::Pull::None, @@ -20,9 +19,9 @@ struct DigitalInputDomain { : gpio{pin, GPIODomain::OperationMode::INPUT, pull, speed} {} template consteval void inscribe(Ctx &ctx) const { - const auto gpio_idx = ctx.template add(gpio.e); + const auto gpio_idx = ctx.template add(gpio.e, &gpio); Entry e{.gpio_idx = gpio_idx}; - index = ctx.template add(e); + ctx.template add(e, this); } }; diff --git a/Inc/ST-LIB_LOW/DigitalOutput2.hpp b/Inc/ST-LIB_LOW/DigitalOutput2.hpp index 8889691b4..8c99b9f24 100644 --- a/Inc/ST-LIB_LOW/DigitalOutput2.hpp +++ b/Inc/ST-LIB_LOW/DigitalOutput2.hpp @@ -18,7 +18,6 @@ struct DigitalOutputDomain { struct DigitalOutput { GPIODomain::GPIO gpio; using domain = DigitalOutputDomain; - mutable size_t index; consteval DigitalOutput(const GPIODomain::Pin &pin, OutputMode mode = OutputMode::PUSH_PULL, @@ -28,9 +27,9 @@ struct DigitalOutputDomain { } template consteval void inscribe(Ctx &ctx) const { - const auto gpio_idx = ctx.template add(gpio.e); + const auto gpio_idx = ctx.template add(gpio.e, &gpio); Entry e{.gpio_idx = gpio_idx}; - index = ctx.template add(e); + ctx.template add(e, this); } }; From ae95584dd99842282e94d1ddb5eb8839aa52f198 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Thu, 18 Dec 2025 10:25:19 +0100 Subject: [PATCH 60/76] fix(MPU): Apply the fix of the fix --- Inc/HALAL/Models/MPU.hpp | 3 +-- Inc/ST-LIB.hpp | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index f447d2d1b..3ed5fbbcc 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -57,7 +57,6 @@ struct MPUDomain { using domain = MPUDomain; using buffer_type = T; Entry e; - mutable size_t index; /** * @brief Constructs a Buffer entry for a type T. @@ -78,7 +77,7 @@ struct MPUDomain { template consteval void inscribe(Ctx &ctx) const { - index = ctx.template add(e); + ctx.template add(e, this); } }; diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index d179cdbd9..5fbf706e2 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -164,7 +164,12 @@ template struct Board { constexpr std::size_t idx = owner_index_of(); constexpr std::size_t N = domain_size(); - return Domain::template Init::instances[idx]; + + if constexpr (std::is_same_v) { + return Domain::template Init::instances[idx]; + } else { + return Domain::template Init::instances[idx]; + } } }; From 7cdea707792b93cf910055fd4a398a4027fa80bc Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Thu, 18 Dec 2025 11:06:11 +0100 Subject: [PATCH 61/76] fix(Sd): Use correct callbacks --- Src/ST-LIB_LOW/Sd/Sd.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Src/ST-LIB_LOW/Sd/Sd.cpp b/Src/ST-LIB_LOW/Sd/Sd.cpp index 178c9021a..9d1425b9b 100644 --- a/Src/ST-LIB_LOW/Sd/Sd.cpp +++ b/Src/ST-LIB_LOW/Sd/Sd.cpp @@ -262,27 +262,15 @@ void SDMMC2_IRQHandler(void) { } } -void HAL_SDEx_Read_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { - sd_instance->on_dma_read_complete(); - } -} - -void HAL_SDEx_Read_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { - if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { - sd_instance->on_dma_read_complete(); - } -} - -void HAL_SDEx_Write_DMADoubleBuf0CpltCallback(SD_HandleTypeDef* hsd) { +void HAL_SD_TxCpltCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { sd_instance->on_dma_write_complete(); } } -void HAL_SDEx_Write_DMADoubleBuf1CpltCallback(SD_HandleTypeDef* hsd) { +void HAL_SD_RxCpltCallback(SD_HandleTypeDef* hsd) { if (auto sd_instance = ST_LIB::get_sd_instance(hsd)) { - sd_instance->on_dma_write_complete(); + sd_instance->on_dma_read_complete(); } } From 91ca16f38b0aa33fd7c5420d09e1c34d55128908 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Thu, 18 Dec 2025 16:24:55 +0100 Subject: [PATCH 62/76] fix(Sd): Fix the fix of the st-lib --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index ea226a80d..dfb0803f0 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -49,7 +49,6 @@ struct SdDomain { struct SdCard { using domain = SdDomain; Entry e; - mutable size_t index; Peripheral peripheral; @@ -123,8 +122,8 @@ struct SdDomain { consteval void inscribe(Ctx &ctx) const { Entry local_e = e; - local_e.mpu_buffer0_idx = ctx.template add(buffer0.e); - local_e.mpu_buffer1_idx = ctx.template add(buffer1.e); + local_e.mpu_buffer0_idx = ctx.template add(buffer0.e, this); + local_e.mpu_buffer1_idx = ctx.template add(buffer1.e, this); if (cd.has_value()) { auto& di = cd.value().first; @@ -139,14 +138,14 @@ struct SdDomain { local_e.wp_pin_idx = {ctx.template add(di_entry), wp.value().second}; } - local_e.cmd_pin_idx = ctx.template add(cmd.e); - local_e.ck_pin_idx = ctx.template add(ck.e); - local_e.d0_pin_idx = ctx.template add(d0.e); - local_e.d1_pin_idx = ctx.template add(d1.e); - local_e.d2_pin_idx = ctx.template add(d2.e); - local_e.d3_pin_idx = ctx.template add(d3.e); + local_e.cmd_pin_idx = ctx.template add(cmd.e, this); + local_e.ck_pin_idx = ctx.template add(ck.e, this); + local_e.d0_pin_idx = ctx.template add(d0.e, this); + local_e.d1_pin_idx = ctx.template add(d1.e, this); + local_e.d2_pin_idx = ctx.template add(d2.e, this); + local_e.d3_pin_idx = ctx.template add(d3.e, this); - index = ctx.template add(local_e); + ctx.template add(local_e, this); } }; From 33bb954f4bd52291f6776ad5e0cb9f79782edf89 Mon Sep 17 00:00:00 2001 From: Foniks Date: Thu, 25 Dec 2025 20:28:50 +0100 Subject: [PATCH 63/76] fix(MPU): Make the MPUManager take it's buffer pointer from a linker symbol, to ensure initialization order doesn't matter --- Inc/HALAL/Models/MPU.hpp | 3 --- Inc/HALAL/Models/MPUManager/MPUManager.hpp | 1 - STM32H723ZGTX_FLASH.ld | 1 + Src/HALAL/Models/MPUManager/MPUManager.cpp | 4 +++- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index 3ed5fbbcc..dfeab1cd4 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -278,9 +278,6 @@ struct MPUDomain { Legacy_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; HAL_MPU_ConfigRegion(&Legacy_InitStruct); - // Set the legacy pointer - MPUManager::no_cached_ram_start = &d3_buffer[0]; - // Adjust bases for new buffers (they start after legacy_size) uint8_t* bases[3] = { &d1_buffer[0], &d2_buffer[0], &d3_buffer[legacy_size] }; diff --git a/Inc/HALAL/Models/MPUManager/MPUManager.hpp b/Inc/HALAL/Models/MPUManager/MPUManager.hpp index 73493fa1b..fd3ba8b49 100644 --- a/Inc/HALAL/Models/MPUManager/MPUManager.hpp +++ b/Inc/HALAL/Models/MPUManager/MPUManager.hpp @@ -6,7 +6,6 @@ #define NO_CACHED_RAM_MAXIMUM_SPACE 2048 class MPUManager{ - friend struct MPUDomain; public: static void* allocate_non_cached_memory(uint32_t size){ void* buffer = (void*)((uint8_t*)no_cached_ram_start + no_cached_ram_occupied_bytes); diff --git a/STM32H723ZGTX_FLASH.ld b/STM32H723ZGTX_FLASH.ld index be8018351..ec60f62a6 100644 --- a/STM32H723ZGTX_FLASH.ld +++ b/STM32H723ZGTX_FLASH.ld @@ -209,6 +209,7 @@ SECTIONS .mpu_ram_d3_nc : { . = ALIGN(32); + __mpu_ram_d3_nc_start = .; /* For the legacy MPUManager */ *(.mpu_ram_d3_nc) . = ALIGN(32); } >RAM_D3 diff --git a/Src/HALAL/Models/MPUManager/MPUManager.cpp b/Src/HALAL/Models/MPUManager/MPUManager.cpp index 99bf036d0..759a853c0 100644 --- a/Src/HALAL/Models/MPUManager/MPUManager.cpp +++ b/Src/HALAL/Models/MPUManager/MPUManager.cpp @@ -1,4 +1,6 @@ #include "HALAL/Models/MPUManager/MPUManager.hpp" -void* MPUManager::no_cached_ram_start = nullptr; +extern "C" uint8_t __mpu_ram_d3_nc_start[]; + +void* MPUManager::no_cached_ram_start = __mpu_ram_d3_nc_start; uint32_t MPUManager::no_cached_ram_occupied_bytes = 0; From 471601436ac17a3f7163d359c3fa3df7ee3689e1 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Thu, 25 Dec 2025 20:57:50 +0100 Subject: [PATCH 64/76] fix(Sd): Fix pin validation logic Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index dfb0803f0..0a32b2db1 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -105,9 +105,9 @@ struct SdDomain { if (sdmmc_peripheral != Peripheral::sdmmc1 && sdmmc_peripheral != Peripheral::sdmmc2) { ST_LIB::compile_error("Invalid SDMMC peripheral"); } - if ((d0_pin_for_sdmmc1.pin != ST_LIB::PC8.pin) && (d0_pin_for_sdmmc1.port != ST_LIB::PC8.port) - && - (d0_pin_for_sdmmc1.pin != ST_LIB::PB13.pin) && (d0_pin_for_sdmmc1.port != ST_LIB::PB13.port)) { + if ((d0_pin_for_sdmmc1.pin != ST_LIB::PC8.pin || d0_pin_for_sdmmc1.port != ST_LIB::PC8.port) + && + (d0_pin_for_sdmmc1.pin != ST_LIB::PB13.pin || d0_pin_for_sdmmc1.port != ST_LIB::PB13.port)) { ST_LIB::compile_error("D0 pin can only be PC8 or PB13 for SDMMC1"); } if (buffer_blocks == 0) { From f6852b50a4145e23b6389e17577e2358000bb5b9 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Thu, 25 Dec 2025 20:59:48 +0100 Subject: [PATCH 65/76] fix(Sd): Fix incorrect error message Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 0a32b2db1..c92368edf 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -283,7 +283,7 @@ struct SdDomain { ErrorHandler("SD Card not initialized"); } if (num_blocks > instance.mpu_buffer0_instance->size / 512) { - ErrorHandler("Too many blocks requested to write in SD"); + ErrorHandler("Too many blocks requested to read from SD"); } if (HAL_SD_GetCardState(&instance.hsd) != HAL_SD_CARD_TRANSFER) { From ba51d6ad2aee81c2ecce4b8baeb5ea165fed1d34 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Thu, 25 Dec 2025 21:00:49 +0100 Subject: [PATCH 66/76] style(Sd): Better wording Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index c92368edf..032a97354 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -38,8 +38,8 @@ struct SdDomain { std::optional> wp_pin_idx; // Write Protect pin index in GPIO domain, if any std::size_t cmd_pin_idx; std::size_t ck_pin_idx; - std::size_t d0_pin_idx; // Hardcoded unless SDMMC1 - std::size_t d1_pin_idx; // Hardcoded unless SDMMC1 + std::size_t d0_pin_idx; // Fixed for SDMMC2, configurable for SDMMC1 + std::size_t d1_pin_idx; // Fixed for SDMMC2, configurable for SDMMC1 std::size_t d2_pin_idx; std::size_t d3_pin_idx; }; From 42a3b997aa06f9323849ec89a700417863b8e219 Mon Sep 17 00:00:00 2001 From: Foniks Date: Thu, 25 Dec 2025 22:24:28 +0100 Subject: [PATCH 67/76] style(MPU): Remove comment --- Inc/HALAL/Models/MPU.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/MPU.hpp b/Inc/HALAL/Models/MPU.hpp index dfeab1cd4..8e482bc78 100644 --- a/Inc/HALAL/Models/MPU.hpp +++ b/Inc/HALAL/Models/MPU.hpp @@ -423,7 +423,7 @@ struct MPUDomain { // D3 RAM (Cached) MPU_InitStruct.Enable = MPU_REGION_ENABLE; - MPU_InitStruct.Number = MPU_REGION_NUMBER6; // FIX: Changed from 5 to 6 to avoid collision with D2 NC + MPU_InitStruct.Number = MPU_REGION_NUMBER6; MPU_InitStruct.BaseAddress = 0x38000000; MPU_InitStruct.Size = MPU_REGION_SIZE_16KB; MPU_InitStruct.SubRegionDisable = 0x0; From 8be22d3794555cc0c66f7eba155798d0cd6819a9 Mon Sep 17 00:00:00 2001 From: Foniks Date: Thu, 22 Jan 2026 23:51:22 +0100 Subject: [PATCH 68/76] feat(Sd): Minor update --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 45 +++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 032a97354..2013b7ab4 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -119,33 +119,27 @@ struct SdDomain { template - consteval void inscribe(Ctx &ctx) const { + consteval std::size_t inscribe(Ctx &ctx) const { Entry local_e = e; local_e.mpu_buffer0_idx = ctx.template add(buffer0.e, this); local_e.mpu_buffer1_idx = ctx.template add(buffer1.e, this); if (cd.has_value()) { - auto& di = cd.value().first; - auto gpio_idx = ctx.template add(di.gpio.e); - DigitalInputDomain::Entry di_entry{gpio_idx}; - local_e.cd_pin_idx = {ctx.template add(di_entry), cd.value().second}; + local_e.cd_pin_idx = {cd.value().first.inscribe(ctx), cd.value().second}; } if (wp.has_value()) { - auto& di = wp.value().first; - auto gpio_idx = ctx.template add(di.gpio.e); - DigitalInputDomain::Entry di_entry{gpio_idx}; - local_e.wp_pin_idx = {ctx.template add(di_entry), wp.value().second}; + local_e.wp_pin_idx = {wp.value().first.inscribe(ctx), wp.value().second}; } - local_e.cmd_pin_idx = ctx.template add(cmd.e, this); - local_e.ck_pin_idx = ctx.template add(ck.e, this); - local_e.d0_pin_idx = ctx.template add(d0.e, this); - local_e.d1_pin_idx = ctx.template add(d1.e, this); - local_e.d2_pin_idx = ctx.template add(d2.e, this); - local_e.d3_pin_idx = ctx.template add(d3.e, this); + local_e.cmd_pin_idx = cmd.inscribe(ctx); + local_e.ck_pin_idx = ck.inscribe(ctx); + local_e.d0_pin_idx = d0.inscribe(ctx); + local_e.d1_pin_idx = d1.inscribe(ctx); + local_e.d2_pin_idx = d2.inscribe(ctx); + local_e.d3_pin_idx = d3.inscribe(ctx); - ctx.template add(local_e, this); + return ctx.template add(local_e, this); } }; @@ -389,21 +383,20 @@ struct SdDomain { inst.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; - inst.hsd.Init.ClockDiv = 2; - + uint32_t target_freq = 25000000; // Target frequency 25 MHz #ifdef SD_DEBUG_ENABLE - // Doesn't really work in this moment, need to actually get the PLL1 frequency somehow - inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; - // Get a 400 kHz clock for debugging - //uint32_t pll1_freq = HAL_RCCEx_GetPLL1ClockFreq(); // SDMMC clock source is PLL1 - uint32_t pll1_freq = 480000000; // Assume PLL1 is at 480 MHz - uint32_t sdmmc_clk = pll1_freq / 2; // SDMMC clock before divider - uint32_t target_div = sdmmc_clk / 400000; // Target divider + inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; // For debugging, use 1-bit bus + target_freq = 400000; // For debugging, use 400 kHz + #endif // SD_DEBUG_ENABLE + + PLL1_ClocksTypeDef pll1_clock = HAL_RCCEx_GetPLL1ClockFreq(); + uint32_t sdmmc_clk = pll1_clock.PLL1_Q / 2; // SDMMC clock before divider + uint32_t target_div = sdmmc_clk / target_freq; // Target divider if (target_div < 2) target_div = 2; // Minimum divider is 2 if (target_div > 256) target_div = 256; // Maximum divider is 256 + inst.hsd.Init.ClockDiv = target_div - 2; // ClockDiv is (divider - 2) - #endif // SD_DEBUG_ENABLE if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; From a983f13f17dd4067ab2af8861c2fbf931f14b77a Mon Sep 17 00:00:00 2001 From: Foniks Date: Fri, 23 Jan 2026 01:39:30 +0100 Subject: [PATCH 69/76] fix(Sd): Fix DomainsCtx and reorder MPUDomain things in ST-LIB.hpp --- Inc/ST-LIB.hpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 7ad91a254..cdf5e6707 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -83,9 +83,6 @@ template struct BuildCtx { } }; -using DomainsCtx = BuildCtx; using DomainsCtx = BuildCtx struct Board { } static consteval auto build() { + constexpr std::size_t mpuN = domain_size(); constexpr std::size_t gpioN = domain_size(); constexpr std::size_t timN = domain_size(); constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); - constexpr std::size_t mpuN = domain_size(); constexpr std::size_t sdN = domain_size(); // ... struct ConfigBundle { + std::array mpu_cfgs; std::array gpio_cfgs; std::array tim_cfgs; std::array dout_cfgs; std::array din_cfgs; - std::array mpu_cfgs; std::array sd_cfgs; // ... }; return ConfigBundle{ + .mpu_cfgs = MPUDomain::template build( + ctx.template span()), .gpio_cfgs = GPIODomain::template build(ctx.template span()), .tim_cfgs = @@ -132,8 +131,6 @@ template struct Board { ctx.template span()), .din_cfgs = DigitalInputDomain::template build( ctx.template span()), - .mpu_cfgs = MPUDomain::template build( - ctx.template span()), .sd_cfgs = SdDomain::template build( ctx.template span()), // ... @@ -143,21 +140,21 @@ template struct Board { static constexpr auto cfg = build(); static void init() { + constexpr std::size_t mpuN = domain_size(); constexpr std::size_t gpioN = domain_size(); constexpr std::size_t timN = domain_size(); constexpr std::size_t doutN = domain_size(); constexpr std::size_t dinN = domain_size(); - constexpr std::size_t mpuN = domain_size(); constexpr std::size_t sdN = domain_size(); // ... + MPUDomain::Init::init(); GPIODomain::Init::init(cfg.gpio_cfgs); TimerDomain::Init::init(cfg.tim_cfgs); DigitalOutputDomain::Init::init(cfg.dout_cfgs, GPIODomain::Init::instances); DigitalInputDomain::Init::init(cfg.din_cfgs, GPIODomain::Init::instances); - MPUDomain::Init::init(); SdDomain::Init::init(cfg.sd_cfgs, MPUDomain::Init::instances, DigitalInputDomain::Init::instances); From dc9140004ac39492f23e81c068ff4a52fb92eb7c Mon Sep 17 00:00:00 2001 From: Foniks Date: Fri, 23 Jan 2026 01:46:14 +0100 Subject: [PATCH 70/76] fix(Sd): Fix small things --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 9 +++++---- Src/ST-LIB_LOW/Sd/Sd.cpp | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 2013b7ab4..b209457ab 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -390,13 +390,14 @@ struct SdDomain { target_freq = 400000; // For debugging, use 400 kHz #endif // SD_DEBUG_ENABLE - PLL1_ClocksTypeDef pll1_clock = HAL_RCCEx_GetPLL1ClockFreq(); - uint32_t sdmmc_clk = pll1_clock.PLL1_Q / 2; // SDMMC clock before divider + PLL1_ClocksTypeDef pll1_clock; + HAL_RCCEx_GetPLL1ClockFreq(&pll1_clock); + uint32_t sdmmc_clk = pll1_clock.PLL1_Q_Frequency / 2; // SDMMC clock before divider uint32_t target_div = sdmmc_clk / target_freq; // Target divider if (target_div < 2) target_div = 2; // Minimum divider is 2 - if (target_div > 256) target_div = 256; // Maximum divider is 256 + if (target_div > 2046) target_div = 2046; // Maximum divider is 2046 - inst.hsd.Init.ClockDiv = target_div - 2; // ClockDiv is (divider - 2) + inst.hsd.Init.ClockDiv = target_div / 2; if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; diff --git a/Src/ST-LIB_LOW/Sd/Sd.cpp b/Src/ST-LIB_LOW/Sd/Sd.cpp index 9d1425b9b..944519880 100644 --- a/Src/ST-LIB_LOW/Sd/Sd.cpp +++ b/Src/ST-LIB_LOW/Sd/Sd.cpp @@ -1,5 +1,9 @@ #include "ST-LIB_LOW/Sd/Sd.hpp" +SD_HandleTypeDef* g_sdmmc1_handle = nullptr; +SD_HandleTypeDef* g_sdmmc2_handle = nullptr; +void* g_sdmmc1_instance_ptr = nullptr; +void* g_sdmmc2_instance_ptr = nullptr; using namespace ST_LIB; From f0d76893f15c1eca4333e038d7a533f1c7c86d18 Mon Sep 17 00:00:00 2001 From: Foniks Date: Fri, 23 Jan 2026 01:47:18 +0100 Subject: [PATCH 71/76] fix(Sd): Remove duplicated global variables in Sd.cpp --- Src/ST-LIB_LOW/Sd/Sd.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Src/ST-LIB_LOW/Sd/Sd.cpp b/Src/ST-LIB_LOW/Sd/Sd.cpp index 944519880..e337fd0f0 100644 --- a/Src/ST-LIB_LOW/Sd/Sd.cpp +++ b/Src/ST-LIB_LOW/Sd/Sd.cpp @@ -230,12 +230,6 @@ HAL_StatusTypeDef SdDomain::Instance::Not_HAL_SDEx_WriteBlocksDMAMultiBuffer(uin } -SD_HandleTypeDef* g_sdmmc1_handle = nullptr; -SD_HandleTypeDef* g_sdmmc2_handle = nullptr; - -void* g_sdmmc1_instance_ptr = nullptr; -void* g_sdmmc2_instance_ptr = nullptr; - extern "C" { void HAL_SD_MspInit(SD_HandleTypeDef* hsd) { From f600a434988cdbf5781a4e7eca7d90c692522d31 Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Fri, 23 Jan 2026 18:45:27 +0100 Subject: [PATCH 72/76] fix(MPU): Reorder includes --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index b209457ab..bfde38754 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -8,10 +8,11 @@ #ifndef SD_HPP #define SD_HPP -#include "HALAL/HALAL.hpp" -#include "ST-LIB_LOW/DigitalInput2.hpp" #include "stm32h7xx_hal.h" + #include "ErrorHandler/ErrorHandler.hpp" +#include "HALAL/HALAL.hpp" +#include "ST-LIB_LOW/DigitalInput2.hpp" using ST_LIB::DigitalInputDomain; using ST_LIB::GPIODomain; From 2e2cda98250ca789a2914d044de31fd57ec4624a Mon Sep 17 00:00:00 2001 From: Foniks Date: Sat, 24 Jan 2026 18:30:56 +0100 Subject: [PATCH 73/76] fix(Sd): Correct SDMMC clock divider calculation and enable hardware flow control just in case --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index bfde38754..6312c3b38 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -383,8 +383,8 @@ struct SdDomain { inst.hsd.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING; inst.hsd.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_4B; - inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; - uint32_t target_freq = 25000000; // Target frequency 25 MHz + inst.hsd.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE; + uint32_t target_freq = 50000000; // Target frequency 50 MHz #ifdef SD_DEBUG_ENABLE inst.hsd.Init.BusWide = SDMMC_BUS_WIDE_1B; // For debugging, use 1-bit bus @@ -393,12 +393,17 @@ struct SdDomain { PLL1_ClocksTypeDef pll1_clock; HAL_RCCEx_GetPLL1ClockFreq(&pll1_clock); - uint32_t sdmmc_clk = pll1_clock.PLL1_Q_Frequency / 2; // SDMMC clock before divider - uint32_t target_div = sdmmc_clk / target_freq; // Target divider - if (target_div < 2) target_div = 2; // Minimum divider is 2 - if (target_div > 2046) target_div = 2046; // Maximum divider is 2046 + uint32_t sdmmc_clk = pll1_clock.PLL1_Q_Frequency; + uint32_t target_div = (sdmmc_clk + target_freq - 1) / target_freq; // Target divider rounded up (target_freq is the maximum frequency) + uint32_t translated_clock_div; // sdmmc_ker_ck / [2 * CLKDIV] + if (target_div == 0) translated_clock_div = 0; // Special case for 0 (no division) + else translated_clock_div = (target_div+1) / 2; // Round up to ensure frequency is not higher than target + + if (translated_clock_div > 1023) { + ErrorHandler("SDMMC clock divider too high, cannot achieve target frequency with current PLL1 Q clock"); + } - inst.hsd.Init.ClockDiv = target_div / 2; + inst.hsd.Init.ClockDiv = translated_clock_div; if (cfg.peripheral == Peripheral::sdmmc1) { g_sdmmc1_handle = &inst.hsd; From 141df9f6699d6006ff23c2f4344830bd33b47e94 Mon Sep 17 00:00:00 2001 From: Foniks Date: Tue, 27 Jan 2026 15:48:43 +0100 Subject: [PATCH 74/76] fix(Sd): Use inscribe for MPU buffers --- Inc/ST-LIB_LOW/Sd/Sd.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Inc/ST-LIB_LOW/Sd/Sd.hpp b/Inc/ST-LIB_LOW/Sd/Sd.hpp index 6312c3b38..f946b98e2 100644 --- a/Inc/ST-LIB_LOW/Sd/Sd.hpp +++ b/Inc/ST-LIB_LOW/Sd/Sd.hpp @@ -123,8 +123,8 @@ struct SdDomain { consteval std::size_t inscribe(Ctx &ctx) const { Entry local_e = e; - local_e.mpu_buffer0_idx = ctx.template add(buffer0.e, this); - local_e.mpu_buffer1_idx = ctx.template add(buffer1.e, this); + local_e.mpu_buffer0_idx = buffer0.inscribe(ctx); + local_e.mpu_buffer1_idx = buffer1.inscribe(ctx); if (cd.has_value()) { local_e.cd_pin_idx = {cd.value().first.inscribe(ctx), cd.value().second}; From 479d242d3d1715fc42ce57d4ddf4773145c1d16f Mon Sep 17 00:00:00 2001 From: Boris Mladenov Beslimov Date: Wed, 28 Jan 2026 00:51:49 +0100 Subject: [PATCH 75/76] fix(Sd): Delete artifact file --- Inc/MockedDrivers/hal_gpio_interface.h | 388 ------------------------- 1 file changed, 388 deletions(-) delete mode 100644 Inc/MockedDrivers/hal_gpio_interface.h diff --git a/Inc/MockedDrivers/hal_gpio_interface.h b/Inc/MockedDrivers/hal_gpio_interface.h deleted file mode 100644 index 579b6ad45..000000000 --- a/Inc/MockedDrivers/hal_gpio_interface.h +++ /dev/null @@ -1,388 +0,0 @@ -/** - ****************************************************************************** - * @file stm32h7xx_hal_gpio.h - * @author MCD Application Team - * @brief Header file of GPIO HAL module. - ****************************************************************************** - * @attention - * - * Copyright (c) 2017 STMicroelectronics. - * All rights reserved. - * - * This software is licensed under terms that can be found in the LICENSE file - * in the root directory of this software component. - * If no LICENSE file comes with this software, it is provided AS-IS. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef STM32H7xx_HAL_GPIO_H -#define STM32H7xx_HAL_GPIO_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32h7xx_hal_def.h" - -/** @addtogroup STM32H7xx_HAL_Driver - * @{ - */ - -/** @addtogroup GPIO - * @{ - */ - -/* Exported types ------------------------------------------------------------*/ -/** @defgroup GPIO_Exported_Types GPIO Exported Types - * @{ - */ - -/** - * @brief GPIO Init structure definition - */ -typedef struct { - uint32_t Pin; /*!< Specifies the GPIO pins to be configured. - This parameter can be any value of @ref GPIO_pins_define */ - - uint32_t Mode; /*!< Specifies the operating mode for the selected pins. - This parameter can be a value of @ref GPIO_mode_define */ - - uint32_t - Pull; /*!< Specifies the Pull-up or Pull-Down activation for the selected - pins. This parameter can be a value of @ref GPIO_pull_define */ - - uint32_t - Speed; /*!< Specifies the speed for the selected pins. - This parameter can be a value of @ref GPIO_speed_define */ - - uint32_t Alternate; /*!< Peripheral to be connected to the selected pins. - This parameter can be a value of @ref - GPIO_Alternate_function_selection */ -} GPIO_InitTypeDef; - -/** - * @brief GPIO Bit SET and Bit RESET enumeration - */ -typedef enum { GPIO_PIN_RESET = 0U, GPIO_PIN_SET } GPIO_PinState; -/** - * @} - */ - -/* Exported constants --------------------------------------------------------*/ - -/** @defgroup GPIO_Exported_Constants GPIO Exported Constants - * @{ - */ - -/** @defgroup GPIO_pins_define GPIO pins define - * @{ - */ -#define GPIO_PIN_0 ((uint16_t)0x0001) /* Pin 0 selected */ -#define GPIO_PIN_1 ((uint16_t)0x0002) /* Pin 1 selected */ -#define GPIO_PIN_2 ((uint16_t)0x0004) /* Pin 2 selected */ -#define GPIO_PIN_3 ((uint16_t)0x0008) /* Pin 3 selected */ -#define GPIO_PIN_4 ((uint16_t)0x0010) /* Pin 4 selected */ -#define GPIO_PIN_5 ((uint16_t)0x0020) /* Pin 5 selected */ -#define GPIO_PIN_6 ((uint16_t)0x0040) /* Pin 6 selected */ -#define GPIO_PIN_7 ((uint16_t)0x0080) /* Pin 7 selected */ -#define GPIO_PIN_8 ((uint16_t)0x0100) /* Pin 8 selected */ -#define GPIO_PIN_9 ((uint16_t)0x0200) /* Pin 9 selected */ -#define GPIO_PIN_10 ((uint16_t)0x0400) /* Pin 10 selected */ -#define GPIO_PIN_11 ((uint16_t)0x0800) /* Pin 11 selected */ -#define GPIO_PIN_12 ((uint16_t)0x1000) /* Pin 12 selected */ -#define GPIO_PIN_13 ((uint16_t)0x2000) /* Pin 13 selected */ -#define GPIO_PIN_14 ((uint16_t)0x4000) /* Pin 14 selected */ -#define GPIO_PIN_15 ((uint16_t)0x8000) /* Pin 15 selected */ -#define GPIO_PIN_All ((uint16_t)0xFFFF) /* All pins selected */ - -#define GPIO_PIN_MASK (0x0000FFFFU) /* PIN mask for assert test */ -/** - * @} - */ - -/** @defgroup GPIO_mode_define GPIO mode define - * @brief GPIO Configuration Mode - * Elements values convention: 0x00WX00YZ - * - W : EXTI trigger detection on 3 bits - * - X : EXTI mode (IT or Event) on 2 bits - * - Y : Output type (Push Pull or Open Drain) on 1 bit - * - Z : GPIO mode (Input, Output, Alternate or Analog) on 2 bits - * @{ - */ -#define GPIO_MODE_INPUT \ - MODE_INPUT /*!< Input Floating Mode */ -#define GPIO_MODE_OUTPUT_PP \ - (MODE_OUTPUT | OUTPUT_PP) /*!< Output Push Pull Mode */ -#define GPIO_MODE_OUTPUT_OD \ - (MODE_OUTPUT | OUTPUT_OD) /*!< Output Open Drain Mode */ -#define GPIO_MODE_AF_PP \ - (MODE_AF | OUTPUT_PP) /*!< Alternate Function Push Pull Mode */ -#define GPIO_MODE_AF_OD \ - (MODE_AF | OUTPUT_OD) /*!< Alternate Function Open Drain Mode */ -#define GPIO_MODE_ANALOG \ - MODE_ANALOG /*!< Analog Mode */ -#define GPIO_MODE_IT_RISING \ - (MODE_INPUT | EXTI_IT | TRIGGER_RISING) /*!< External Interrupt Mode with \ - Rising edge trigger detection */ -#define GPIO_MODE_IT_FALLING \ - (MODE_INPUT | EXTI_IT | \ - TRIGGER_FALLING) /*!< External Interrupt Mode with Falling edge trigger \ - detection */ -#define GPIO_MODE_IT_RISING_FALLING \ - (MODE_INPUT | EXTI_IT | TRIGGER_RISING | \ - TRIGGER_FALLING) /*!< External Interrupt Mode with Rising/Falling edge \ - trigger detection */ - -#define GPIO_MODE_EVT_RISING \ - (MODE_INPUT | EXTI_EVT | TRIGGER_RISING) /*!< External Event Mode with \ - Rising edge trigger detection */ -#define GPIO_MODE_EVT_FALLING \ - (MODE_INPUT | EXTI_EVT | \ - TRIGGER_FALLING) /*!< External Event Mode with Falling edge trigger \ - detection */ -#define GPIO_MODE_EVT_RISING_FALLING \ - (MODE_INPUT | EXTI_EVT | TRIGGER_RISING | \ - TRIGGER_FALLING) /*!< External Event Mode with Rising/Falling edge trigger \ - detection */ -/** - * @} - */ - -/** @defgroup GPIO_speed_define GPIO speed define - * @brief GPIO Output Maximum frequency - * @{ - */ -#define GPIO_SPEED_FREQ_LOW (0x00000000U) /*!< Low speed */ -#define GPIO_SPEED_FREQ_MEDIUM (0x00000001U) /*!< Medium speed */ -#define GPIO_SPEED_FREQ_HIGH (0x00000002U) /*!< Fast speed */ -#define GPIO_SPEED_FREQ_VERY_HIGH (0x00000003U) /*!< High speed */ -/** - * @} - */ - -/** @defgroup GPIO_pull_define GPIO pull define - * @brief GPIO Pull-Up or Pull-Down Activation - * @{ - */ -#define GPIO_NOPULL (0x00000000U) /*!< No Pull-up or Pull-down activation */ -#define GPIO_PULLUP (0x00000001U) /*!< Pull-up activation */ -#define GPIO_PULLDOWN (0x00000002U) /*!< Pull-down activation */ -/** - * @} - */ - -/** - * @} - */ - -/* Exported macro ------------------------------------------------------------*/ -/** @defgroup GPIO_Exported_Macros GPIO Exported Macros - * @{ - */ - -/** - * @brief Checks whether the specified EXTI line flag is set or not. - * @param __EXTI_LINE__: specifies the EXTI line flag to check. - * This parameter can be GPIO_PIN_x where x can be(0..15) - * @retval The new state of __EXTI_LINE__ (SET or RESET). - */ -#define __HAL_GPIO_EXTI_GET_FLAG(__EXTI_LINE__) (EXTI->PR1 & (__EXTI_LINE__)) - -/** - * @brief Clears the EXTI's line pending flags. - * @param __EXTI_LINE__: specifies the EXTI lines flags to clear. - * This parameter can be any combination of GPIO_PIN_x where x can be - * (0..15) - * @retval None - */ -#define __HAL_GPIO_EXTI_CLEAR_FLAG(__EXTI_LINE__) (EXTI->PR1 = (__EXTI_LINE__)) - -/** - * @brief Checks whether the specified EXTI line is asserted or not. - * @param __EXTI_LINE__: specifies the EXTI line to check. - * This parameter can be GPIO_PIN_x where x can be(0..15) - * @retval The new state of __EXTI_LINE__ (SET or RESET). - */ -#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR1 & (__EXTI_LINE__)) - -/** - * @brief Clears the EXTI's line pending bits. - * @param __EXTI_LINE__: specifies the EXTI lines to clear. - * This parameter can be any combination of GPIO_PIN_x where x can be - * (0..15) - * @retval None - */ -#define __HAL_GPIO_EXTI_CLEAR_IT(__EXTI_LINE__) (EXTI->PR1 = (__EXTI_LINE__)) - -#if defined(DUAL_CORE) -/** - * @brief Checks whether the specified EXTI line flag is set or not. - * @param __EXTI_LINE__: specifies the EXTI line flag to check. - * This parameter can be GPIO_PIN_x where x can be(0..15) - * @retval The new state of __EXTI_LINE__ (SET or RESET). - */ -#define __HAL_GPIO_EXTID2_GET_FLAG(__EXTI_LINE__) \ - (EXTI->C2PR1 & (__EXTI_LINE__)) - -/** - * @brief Clears the EXTI's line pending flags. - * @param __EXTI_LINE__: specifies the EXTI lines flags to clear. - * This parameter can be any combination of GPIO_PIN_x where x can be - * (0..15) - * @retval None - */ -#define __HAL_GPIO_EXTID2_CLEAR_FLAG(__EXTI_LINE__) \ - (EXTI->C2PR1 = (__EXTI_LINE__)) - -/** - * @brief Checks whether the specified EXTI line is asserted or not. - * @param __EXTI_LINE__: specifies the EXTI line to check. - * This parameter can be GPIO_PIN_x where x can be(0..15) - * @retval The new state of __EXTI_LINE__ (SET or RESET). - */ -#define __HAL_GPIO_EXTID2_GET_IT(__EXTI_LINE__) (EXTI->C2PR1 & (__EXTI_LINE__)) - -/** - * @brief Clears the EXTI's line pending bits. - * @param __EXTI_LINE__: specifies the EXTI lines to clear. - * This parameter can be any combination of GPIO_PIN_x where x can be - * (0..15) - * @retval None - */ -#define __HAL_GPIO_EXTID2_CLEAR_IT(__EXTI_LINE__) \ - (EXTI->C2PR1 = (__EXTI_LINE__)) -#endif - -/** - * @brief Generates a Software interrupt on selected EXTI line. - * @param __EXTI_LINE__: specifies the EXTI line to check. - * This parameter can be GPIO_PIN_x where x can be(0..15) - * @retval None - */ -#define __HAL_GPIO_EXTI_GENERATE_SWIT(__EXTI_LINE__) \ - (EXTI->SWIER1 |= (__EXTI_LINE__)) -/** - * @} - */ - -/* Include GPIO HAL Extension module */ -#include "stm32h7xx_hal_gpio_ex.h" - -/* Exported functions --------------------------------------------------------*/ -/** @addtogroup GPIO_Exported_Functions - * @{ - */ - -/** @addtogroup GPIO_Exported_Functions_Group1 - * @{ - */ -/* Initialization and de-initialization functions *****************************/ -void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, const GPIO_InitTypeDef *GPIO_Init); -void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin); -/** - * @} - */ - -/** @addtogroup GPIO_Exported_Functions_Group2 - * @{ - */ -/* IO operation functions *****************************************************/ -GPIO_PinState HAL_GPIO_ReadPin(const GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); -void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, - GPIO_PinState PinState); -void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); -HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin); -void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin); -void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin); - -/** - * @} - */ - -/** - * @} - */ -/* Private types -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Private constants ---------------------------------------------------------*/ -/** @defgroup GPIO_Private_Constants GPIO Private Constants - * @{ - */ -#define GPIO_MODE_Pos 0u -#define GPIO_MODE (0x3uL << GPIO_MODE_Pos) -#define MODE_INPUT (0x0uL << GPIO_MODE_Pos) -#define MODE_OUTPUT (0x1uL << GPIO_MODE_Pos) -#define MODE_AF (0x2uL << GPIO_MODE_Pos) -#define MODE_ANALOG (0x3uL << GPIO_MODE_Pos) -#define OUTPUT_TYPE_Pos 4u -#define OUTPUT_TYPE (0x1uL << OUTPUT_TYPE_Pos) -#define OUTPUT_PP (0x0uL << OUTPUT_TYPE_Pos) -#define OUTPUT_OD (0x1uL << OUTPUT_TYPE_Pos) -#define EXTI_MODE_Pos 16u -#define EXTI_MODE (0x3uL << EXTI_MODE_Pos) -#define EXTI_IT (0x1uL << EXTI_MODE_Pos) -#define EXTI_EVT (0x2uL << EXTI_MODE_Pos) -#define TRIGGER_MODE_Pos 20u -#define TRIGGER_MODE (0x7uL << TRIGGER_MODE_Pos) -#define TRIGGER_RISING (0x1uL << TRIGGER_MODE_Pos) -#define TRIGGER_FALLING (0x2uL << TRIGGER_MODE_Pos) -#define TRIGGER_LEVEL (0x4uL << TRIGGER_MODE_Pos) -/** - * @} - */ - -/* Private macros ------------------------------------------------------------*/ -/** @defgroup GPIO_Private_Macros GPIO Private Macros - * @{ - */ -#define IS_GPIO_PIN_ACTION(ACTION) \ - (((ACTION) == GPIO_PIN_RESET) || ((ACTION) == GPIO_PIN_SET)) -#define IS_GPIO_PIN(__PIN__) \ - ((((uint32_t)(__PIN__) & GPIO_PIN_MASK) != 0x00U) && \ - (((uint32_t)(__PIN__) & ~GPIO_PIN_MASK) == 0x00U)) -#define IS_GPIO_MODE(MODE) \ - (((MODE) == GPIO_MODE_INPUT) || ((MODE) == GPIO_MODE_OUTPUT_PP) || \ - ((MODE) == GPIO_MODE_OUTPUT_OD) || ((MODE) == GPIO_MODE_AF_PP) || \ - ((MODE) == GPIO_MODE_AF_OD) || ((MODE) == GPIO_MODE_IT_RISING) || \ - ((MODE) == GPIO_MODE_IT_FALLING) || \ - ((MODE) == GPIO_MODE_IT_RISING_FALLING) || \ - ((MODE) == GPIO_MODE_EVT_RISING) || ((MODE) == GPIO_MODE_EVT_FALLING) || \ - ((MODE) == GPIO_MODE_EVT_RISING_FALLING) || ((MODE) == GPIO_MODE_ANALOG)) -#define IS_GPIO_SPEED(SPEED) \ - (((SPEED) == GPIO_SPEED_FREQ_LOW) || ((SPEED) == GPIO_SPEED_FREQ_MEDIUM) || \ - ((SPEED) == GPIO_SPEED_FREQ_HIGH) || \ - ((SPEED) == GPIO_SPEED_FREQ_VERY_HIGH)) - -#define IS_GPIO_PULL(PULL) \ - (((PULL) == GPIO_NOPULL) || ((PULL) == GPIO_PULLUP) || \ - ((PULL) == GPIO_PULLDOWN)) - -/** - * @} - */ - -/* Private functions ---------------------------------------------------------*/ -/** @defgroup GPIO_Private_Functions GPIO Private Functions - * @{ - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* STM32H7xx_HAL_GPIO_H */ From b877df4df7f3c778e9889813353bf36e841a8e37 Mon Sep 17 00:00:00 2001 From: Foniks Date: Wed, 28 Jan 2026 00:53:24 +0100 Subject: [PATCH 76/76] fix(Sd): Remove artifact of merge --- STM32H723ZGTX_FLASH.ld | 7 ------- 1 file changed, 7 deletions(-) diff --git a/STM32H723ZGTX_FLASH.ld b/STM32H723ZGTX_FLASH.ld index 6275ab6d9..4e1345425 100644 --- a/STM32H723ZGTX_FLASH.ld +++ b/STM32H723ZGTX_FLASH.ld @@ -208,13 +208,6 @@ SECTIONS __bss_end__ = _ebss; } >DTCMRAM - .mpu_ram_d1_nc : - { - . = ALIGN(32); - *(.mpu_ram_d1_nc) - . = ALIGN(32); - } >RAM_D1 - /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : {