Skip to content
158 changes: 137 additions & 21 deletions Inc/HALAL/Services/EXTI/EXTI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void()> 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<uint8_t>(ST_LIB::GPIODomain::OperationMode::EXTI_RISING),
FALLING_EDGE = static_cast<uint8_t>(ST_LIB::GPIODomain::OperationMode::EXTI_FALLING),
BOTH_EDGES = static_cast<uint8_t>(ST_LIB::GPIODomain::OperationMode::EXTI_RISING_FALLING)
};

struct Entry {
std::size_t pin_idx;
uint16_t pin_mask;
void (*action)();
};

static map<uint8_t, Pin> service_ids;
static map<uint16_t, Instance> 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<void()>&& 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<ST_LIB::GPIODomain::OperationMode>(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 <class Ctx> 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<EXTIDomain>(e, this);
}
};

static constexpr std::size_t max_instances = 16;

struct Config {
std::size_t pin_idx;
uint8_t interrupt_num;
void (*action)();
};

template <std::size_t N>
static consteval std::array<Config, N> build(std::span<const Entry> entries) {
std::array<Config, N> 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 <std::size_t N> struct Init;

struct Instance {
friend void ::HAL_GPIO_EXTI_Callback(uint16_t);
template <std::size_t> 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 <std::size_t N> struct Init {
static inline std::array<Instance, N> instances{};

static void
init(std::span<const Config, N> cfgs, std::span<GPIODomain::Instance> 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
10 changes: 8 additions & 2 deletions Inc/ST-LIB.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ using DomainsCtx = BuildCtx<
MdmaPacketDomain,
SdDomain,
EthernetDomain,
ADCDomain /*, PWMDomain, ...*/>;
ADCDomain,
EXTIDomain /* PWMDomain, ...*/>;

template <auto&... devs> struct Board {
static consteval auto build_ctx() {
Expand All @@ -120,6 +121,7 @@ template <auto&... devs> struct Board {
constexpr std::size_t sdN = domain_size<SdDomain>();
constexpr std::size_t ethN = domain_size<EthernetDomain>();
constexpr std::size_t adcN = domain_size<ADCDomain>();
constexpr std::size_t extiN = domain_size<EXTIDomain>();
// ...

struct ConfigBundle {
Expand All @@ -134,6 +136,7 @@ template <auto&... devs> struct Board {
std::array<SdDomain::Config, sdN> sd_cfgs;
std::array<EthernetDomain::Config, ethN> eth_cfgs;
std::array<ADCDomain::Config, adcN> adc_cfgs;
std::array<EXTIDomain::Config, extiN> exti_cfgs;
// ...
};

Expand All @@ -154,6 +157,7 @@ template <auto&... devs> struct Board {
.sd_cfgs = SdDomain::template build<sdN>(ctx.template span<SdDomain>()),
.eth_cfgs = EthernetDomain::template build<ethN>(ctx.template span<EthernetDomain>()),
.adc_cfgs = ADCDomain::template build<adcN>(ctx.template span<ADCDomain>()),
.exti_cfgs = EXTIDomain::template build<extiN>(ctx.template span<EXTIDomain>()),
// ...
};
}
Expand All @@ -172,6 +176,7 @@ template <auto&... devs> struct Board {
constexpr std::size_t sdN = domain_size<SdDomain>();
constexpr std::size_t ethN = domain_size<EthernetDomain>();
constexpr std::size_t adcN = domain_size<ADCDomain>();
constexpr std::size_t extiN = domain_size<EXTIDomain>();
// ...

#ifdef HAL_IWDG_MODULE_ENABLED
Expand Down Expand Up @@ -203,7 +208,8 @@ template <auto&... devs> struct Board {
);
EthernetDomain::Init<ethN>::init(cfg.eth_cfgs, DigitalOutputDomain::Init<doutN>::instances);
ADCDomain::Init<adcN>::init(cfg.adc_cfgs, GPIODomain::Init<gpioN>::instances);
// ...
EXTIDomain::Init<extiN>::init(cfg.exti_cfgs,
GPIODomain::Init<gpioN>::instances); // ...
}

template <typename Domain, auto& Target, std::size_t I = 0>
Expand Down
1 change: 0 additions & 1 deletion Inc/ST-LIB_LOW/Sensors/Sensor/Sensor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,5 @@
class Sensor {
public:
static void start();
static std::vector<uint8_t> EXTI_id_list;
static std::vector<uint8_t> inputcapture_id_list;
};
19 changes: 4 additions & 15 deletions Inc/ST-LIB_LOW/Sensors/SensorInterrupt/SensorInterrupt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,11 @@
class SensorInterrupt {
public:
SensorInterrupt() = default;
SensorInterrupt(
Pin& pin,
std::function<void()>&& action,
PinState* value,
TRIGGER trigger = TRIGGER::RISING_EDGE
);
SensorInterrupt(
Pin& pin,
std::function<void()>&& 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;
};
4 changes: 0 additions & 4 deletions Src/HALAL/HALAL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
78 changes: 24 additions & 54 deletions Src/HALAL/Services/EXTI/EXTI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<uint8_t, Pin> 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<void()>&& 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);
}
5 changes: 0 additions & 5 deletions Src/ST-LIB_LOW/Sensors/Sensor/Sensor.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
#include "Sensors/Sensor/Sensor.hpp"

#include "HALAL/Services/EXTI/EXTI.hpp"
#include "HALAL/Services/InputCapture/InputCapture.hpp"

std::vector<uint8_t> Sensor::EXTI_id_list{};
std::vector<uint8_t> 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);
Expand Down
Loading