diff --git a/Inc/HALAL/Services/EXTI/EXTI.hpp b/Inc/HALAL/Services/EXTI/EXTI.hpp index 217788d9..77daaefd 100644 --- a/Inc/HALAL/Services/EXTI/EXTI.hpp +++ b/Inc/HALAL/Services/EXTI/EXTI.hpp @@ -5,32 +5,148 @@ * Author: alejandro */ -#pragma once -#include "HALAL/Models/PinModel/Pin.hpp" +#ifndef EXTI_HPP +#define EXTI_HPP +#include "HALAL/Models/GPIO.hpp" +#include "HALAL/Models/Pin.hpp" -#ifdef HAL_EXTI_MODULE_ENABLED +extern "C" void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin); -class ExternalInterrupt { -public: - class Instance { - public: - IRQn_Type interrupt_request_number; +namespace ST_LIB { - function action = nullptr; - bool is_on = true; +struct EXTIDomain { - Instance() = default; - Instance(IRQn_Type interrupt_request_number); + static constexpr uint8_t get_pin_index(uint16_t pin_mask) { + for (uint8_t i = 0; i < 16; i++) { + if (pin_mask & (1 << i)) + return i; + } + return 0xFF; + } + + enum class Trigger : uint8_t { + RISING_EDGE = static_cast(ST_LIB::GPIODomain::OperationMode::EXTI_RISING), + FALLING_EDGE = static_cast(ST_LIB::GPIODomain::OperationMode::EXTI_FALLING), + BOTH_EDGES = static_cast(ST_LIB::GPIODomain::OperationMode::EXTI_RISING_FALLING) + }; + + struct Entry { + std::size_t pin_idx; + uint16_t pin_mask; + void (*action)(); }; - static map service_ids; - static map instances; - static uint8_t id_counter; + struct Device { + using domain = EXTIDomain; + ST_LIB::GPIODomain::GPIO pin; + void (*action)(); - static uint8_t inscribe(Pin& pin, function&& action, TRIGGER trigger = RISING_EDGE); - static void start(); - static void turn_on(uint8_t id); - static void turn_off(uint8_t id); - static bool get_pin_value(uint8_t id); -}; + consteval Device(ST_LIB::GPIODomain::Pin pin, Trigger trigger, void (*action)()) + : pin(pin, + static_cast(trigger), + ST_LIB::GPIODomain::Pull::None, + ST_LIB::GPIODomain::Speed::Low), + action(action) { +#ifndef HAL_EXTI_MODULE_ENABLED + ST_LIB::compile_error("EXTI module not enabled in HAL"); #endif + } + + template consteval std::size_t inscribe(Ctx& ctx) const { + Entry e; + e.pin_idx = pin.inscribe(ctx); + e.pin_mask = pin.e.pin; + e.action = action; + return ctx.template add(e, this); + } + }; + + static constexpr std::size_t max_instances = 16; + + struct Config { + std::size_t pin_idx; + uint8_t interrupt_num; + void (*action)(); + }; + + template + static consteval std::array build(std::span entries) { + std::array cfgs{}; + + uint16_t used_lines_mask = 0; + + for (std::size_t i = 0; i < N; i++) { + const Entry& e = entries[i]; + + cfgs[i].pin_idx = e.pin_idx; + uint8_t pin_num = get_pin_index(e.pin_mask); + + if (pin_num >= 16) { + ST_LIB::compile_error("Invalid Pin for EXTI"); + } + + uint16_t line_mask = (1 << pin_num); + if (used_lines_mask & line_mask) { + ST_LIB::compile_error("EXTI line already used (Hardware Conflict: Pins with same " + "number share EXTI Line)"); + } + + used_lines_mask |= line_mask; + cfgs[i].interrupt_num = pin_num; + cfgs[i].action = e.action; + } + + return cfgs; + } + + template struct Init; + + struct Instance { + friend void ::HAL_GPIO_EXTI_Callback(uint16_t); + template friend struct Init; + void turn_off() { is_on = false; } + void turn_on() { is_on = true; } + GPIO_PinState read() { return gpio->read(); } + + private: + bool is_on = false; + void (*action)() = nullptr; + GPIODomain::Instance* gpio = nullptr; + }; + + static Instance* g_instances[EXTIDomain::max_instances]; + + 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& cfg = cfgs[i]; + auto& inst = instances[i]; + + uint8_t id = cfg.interrupt_num; + g_instances[id] = &inst; + inst.action = cfg.action; + inst.gpio = &gpio_instances[cfg.pin_idx]; + + IRQn_Type irq_n; + if (id <= 4) + irq_n = (IRQn_Type)(EXTI0_IRQn + id); + else if (id <= 9) + irq_n = EXTI9_5_IRQn; + else + irq_n = EXTI15_10_IRQn; + + HAL_NVIC_SetPriority(irq_n, 0, 0); + HAL_NVIC_EnableIRQ(irq_n); + + inst.turn_on(); + } + } + }; +}; + +} // namespace ST_LIB + +#endif // EXTI_HPP \ No newline at end of file diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 7126130c..726e225f 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -93,7 +93,8 @@ using DomainsCtx = BuildCtx< MdmaPacketDomain, SdDomain, EthernetDomain, - ADCDomain /*, PWMDomain, ...*/>; + ADCDomain, + EXTIDomain /* PWMDomain, ...*/>; template struct Board { static consteval auto build_ctx() { @@ -120,6 +121,7 @@ template struct Board { constexpr std::size_t sdN = domain_size(); constexpr std::size_t ethN = domain_size(); constexpr std::size_t adcN = domain_size(); + constexpr std::size_t extiN = domain_size(); // ... struct ConfigBundle { @@ -134,6 +136,7 @@ template struct Board { std::array sd_cfgs; std::array eth_cfgs; std::array adc_cfgs; + std::array exti_cfgs; // ... }; @@ -154,6 +157,7 @@ template struct Board { .sd_cfgs = SdDomain::template build(ctx.template span()), .eth_cfgs = EthernetDomain::template build(ctx.template span()), .adc_cfgs = ADCDomain::template build(ctx.template span()), + .exti_cfgs = EXTIDomain::template build(ctx.template span()), // ... }; } @@ -172,6 +176,7 @@ template struct Board { constexpr std::size_t sdN = domain_size(); constexpr std::size_t ethN = domain_size(); constexpr std::size_t adcN = domain_size(); + constexpr std::size_t extiN = domain_size(); // ... #ifdef HAL_IWDG_MODULE_ENABLED @@ -203,7 +208,8 @@ template struct Board { ); EthernetDomain::Init::init(cfg.eth_cfgs, DigitalOutputDomain::Init::instances); ADCDomain::Init::init(cfg.adc_cfgs, GPIODomain::Init::instances); - // ... + EXTIDomain::Init::init(cfg.exti_cfgs, + GPIODomain::Init::instances); // ... } template diff --git a/Inc/ST-LIB_LOW/Sensors/Sensor/Sensor.hpp b/Inc/ST-LIB_LOW/Sensors/Sensor/Sensor.hpp index 3e1071c5..edf917b7 100644 --- a/Inc/ST-LIB_LOW/Sensors/Sensor/Sensor.hpp +++ b/Inc/ST-LIB_LOW/Sensors/Sensor/Sensor.hpp @@ -12,6 +12,5 @@ class Sensor { public: static void start(); - static std::vector EXTI_id_list; static std::vector inputcapture_id_list; }; diff --git a/Inc/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.hpp b/Inc/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.hpp index ef3d629e..e23d25d1 100644 --- a/Inc/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.hpp +++ b/Inc/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.hpp @@ -15,22 +15,11 @@ class SensorInterrupt { public: SensorInterrupt() = default; - SensorInterrupt( - Pin& pin, - std::function&& action, - PinState* value, - TRIGGER trigger = TRIGGER::RISING_EDGE - ); - SensorInterrupt( - Pin& pin, - std::function&& action, - PinState& value, - TRIGGER trigger = TRIGGER::RISING_EDGE - ); + SensorInterrupt(ST_LIB::EXTIDomain::Instance& exti, GPIO_PinState* value); + SensorInterrupt(ST_LIB::EXTIDomain::Instance& exti, GPIO_PinState& value); void read(); - uint8_t get_id(); protected: - uint8_t id; - PinState* value; + ST_LIB::EXTIDomain::Instance* exti; + GPIO_PinState* value; }; diff --git a/Src/HALAL/HALAL.cpp b/Src/HALAL/HALAL.cpp index c56e3795..bc38c060 100644 --- a/Src/HALAL/HALAL.cpp +++ b/Src/HALAL/HALAL.cpp @@ -75,10 +75,6 @@ static void common_start(UART::Peripheral& printf_peripheral) { // Time::start(); #endif -#ifdef HAL_EXTI_MODULE_ENABLED - ExternalInterrupt::start(); -#endif - #ifdef NDEBUG #ifdef HAL_IWDG_MODULE_ENABLED Watchdog::start(); diff --git a/Src/HALAL/Services/EXTI/EXTI.cpp b/Src/HALAL/Services/EXTI/EXTI.cpp index 11a38f73..f4a4b779 100644 --- a/Src/HALAL/Services/EXTI/EXTI.cpp +++ b/Src/HALAL/Services/EXTI/EXTI.cpp @@ -7,68 +7,38 @@ #include "HALAL/Services/EXTI/EXTI.hpp" -#include "ErrorHandler/ErrorHandler.hpp" +ST_LIB::EXTIDomain::Instance* ST_LIB::EXTIDomain::g_instances[ST_LIB::EXTIDomain::max_instances]; -uint8_t ExternalInterrupt::id_counter = 0; -map ExternalInterrupt::service_ids = {}; - -ExternalInterrupt::Instance::Instance(IRQn_Type interrupt_request_number) - : interrupt_request_number(interrupt_request_number) {} +extern "C" { void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { - ExternalInterrupt::Instance& exti = ExternalInterrupt::instances[GPIO_Pin]; - if (exti.is_on) { - exti.action(); + auto index = ST_LIB::EXTIDomain::get_pin_index(GPIO_Pin); + if (index >= ST_LIB::EXTIDomain::max_instances) + return; + auto* exti = ST_LIB::EXTIDomain::g_instances[index]; + if (exti && exti->is_on && exti->action) { + exti->action(); } } -uint8_t ExternalInterrupt::inscribe(Pin& pin, function&& action, TRIGGER trigger) { - if (not instances.contains(pin.gpio_pin)) { - ErrorHandler( - " The pin %s is already used or isn t available for EXTI usage", - pin.to_string().c_str() - ); - return 0; - } - - if (trigger == TRIGGER::RISING_EDGE) { - Pin::inscribe(pin, EXTERNAL_INTERRUPT_RISING); - } else if (trigger == TRIGGER::FAILING_EDGE) { - Pin::inscribe(pin, EXTERNAL_INTERRUPT_FALLING); - } else if (trigger == TRIGGER::BOTH_EDGES) { - Pin::inscribe(pin, EXTERNAL_INTERRUPT_RISING_FALLING); +void EXTI0_IRQHandler() { HAL_GPIO_EXTI_IRQHandler(0x0001); } + +void EXTI1_IRQHandler() { HAL_GPIO_EXTI_IRQHandler(0x0002); } +void EXTI2_IRQHandler() { HAL_GPIO_EXTI_IRQHandler(0x0004); } +void EXTI3_IRQHandler() { HAL_GPIO_EXTI_IRQHandler(0x0008); } +void EXTI4_IRQHandler() { HAL_GPIO_EXTI_IRQHandler(0x0010); } +void EXTI9_5_IRQHandler() { + for (uint32_t pin_mask = 0x0020; pin_mask <= 0x0200; pin_mask <<= 1) { + if (__HAL_GPIO_EXTI_GET_IT(pin_mask) != 0x00U) { + HAL_GPIO_EXTI_IRQHandler(pin_mask); + } } - - service_ids[id_counter] = pin; - instances[pin.gpio_pin].action = action; - - return id_counter++; } - -void ExternalInterrupt::start() { - for (auto id_instance : instances) { - Instance& instance = id_instance.second; - HAL_NVIC_SetPriority(instance.interrupt_request_number, 0, 0); - HAL_NVIC_EnableIRQ(instance.interrupt_request_number); +void EXTI15_10_IRQHandler() { + for (uint32_t pin_mask = 0x0400; pin_mask <= 0x8000; pin_mask <<= 1) { + if (__HAL_GPIO_EXTI_GET_IT(pin_mask) != 0x00U) { + HAL_GPIO_EXTI_IRQHandler(pin_mask); + } } } - -void ExternalInterrupt::turn_on(uint8_t id) { - if (not service_ids.contains(id)) { - ErrorHandler("ID %d is not registered as an active instance", id); - return; - } - - Instance& instance = instances[service_ids[id].gpio_pin]; - instance.is_on = true; -} - -bool ExternalInterrupt::get_pin_value(uint8_t id) { - if (not service_ids.contains(id)) { - ErrorHandler("ID %d is not registered as an active instance", id); - return false; - } - - Pin& pin = service_ids[id]; - return HAL_GPIO_ReadPin(pin.port, pin.gpio_pin); } diff --git a/Src/ST-LIB_LOW/Sensors/Sensor/Sensor.cpp b/Src/ST-LIB_LOW/Sensors/Sensor/Sensor.cpp index 1bfd7456..251dc361 100644 --- a/Src/ST-LIB_LOW/Sensors/Sensor/Sensor.cpp +++ b/Src/ST-LIB_LOW/Sensors/Sensor/Sensor.cpp @@ -1,15 +1,10 @@ #include "Sensors/Sensor/Sensor.hpp" -#include "HALAL/Services/EXTI/EXTI.hpp" #include "HALAL/Services/InputCapture/InputCapture.hpp" -std::vector Sensor::EXTI_id_list{}; std::vector Sensor::inputcapture_id_list{}; void Sensor::start() { - for (uint8_t exti_id : EXTI_id_list) { - ExternalInterrupt::turn_on(exti_id); - } for (uint8_t inputcapture_id : inputcapture_id_list) { InputCapture::turn_on(inputcapture_id); diff --git a/Src/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.cpp b/Src/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.cpp index a70a6161..5c940ddb 100644 --- a/Src/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.cpp +++ b/Src/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.cpp @@ -1,31 +1,9 @@ #include "Sensors/SensorInterrupt/SensorInterrupt.hpp" -#include "Sensors/Sensor/Sensor.hpp" -SensorInterrupt::SensorInterrupt( - Pin& pin, - std::function&& action, - PinState* value, - TRIGGER trigger -) - : value(value) { - id = ExternalInterrupt::inscribe(pin, std::forward>(action), trigger); +SensorInterrupt::SensorInterrupt(ST_LIB::EXTIDomain::Instance& exti, GPIO_PinState* value) + : exti(&exti), value(value) {} - Sensor::EXTI_id_list.insert(Sensor::EXTI_id_list.begin(), id); -} +SensorInterrupt::SensorInterrupt(ST_LIB::EXTIDomain::Instance& exti, GPIO_PinState& value) + : SensorInterrupt::SensorInterrupt(exti, &value) {} -SensorInterrupt::SensorInterrupt( - Pin& pin, - std::function&& action, - PinState& value, - TRIGGER trigger -) - : SensorInterrupt::SensorInterrupt( - pin, - std::forward>(action), - &value, - trigger - ) {} - -void SensorInterrupt::read() { *value = (PinState)ExternalInterrupt::get_pin_value(id); } - -uint8_t SensorInterrupt::get_id() { return id; } +void SensorInterrupt::read() { *value = exti->read(); }