diff --git a/CMakeLists.txt b/CMakeLists.txt index 23a2c3a9..834d657d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,7 +285,6 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE $<$:-w> $<$:-Wall> - $<$:-Wpedantic> $<$:-Werror> $<$:-Wno-gnu-zero-variadic-macro-arguments> $<$:-Wno-inconsistent-missing-override> diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index c0a15798..2fece23f 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -20,7 +20,6 @@ #include #include -#include #include "ErrorHandler/ErrorHandler.hpp" @@ -51,6 +50,11 @@ TimerXList #undef X +#if !defined(glue) +#define glue_(a,b) a##b +#define glue(a,b) glue_(a,b) +#endif // !defined(glue) + /* Tim1 & Tim8 are advanced-control timers * their ARR & prescaler are 16bit * they have up to 6 independent channels for: @@ -66,7 +70,6 @@ TimerXList * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) */ - /* Tim6 & Tim7 are basic timers. Features: - 16-bit ARR upcounter - 16-bit PSC @@ -151,8 +154,8 @@ struct TimerPin { ST_LIB::TimerChannel channel; }; -constexpr std::array create_timer_idxmap() { - std::array result{}; +constexpr std::array create_timer_idxmap() { + std::array result{}; // invalid timers that don't exist result[0] = -1; @@ -178,7 +181,7 @@ constexpr std::array create_timer_idxmap() { return result; } -static constexpr std::array timer_idxmap = create_timer_idxmap(); +static constexpr std::array timer_idxmap = create_timer_idxmap(); struct TimerDomain { // There are 16 timers @@ -201,20 +204,12 @@ struct TimerDomain { struct Entry { std::array name; /* max length = 7 */ TimerRequest request; - TimerDomain::CountingMode counting_mode; - uint32_t deadtime; - uint32_t polarity; - uint32_t negated_polarity; uint8_t pin_count; - std::array pins; + std::array pins; /* this won't be read in Timer constructor */ }; struct Config { - uint16_t timer_idx; - TimerDomain::CountingMode counting_mode; - uint32_t deadtime; - uint32_t polarity; - uint32_t negated_polarity; + uint8_t timer_idx; }; static constexpr TIM_HandleTypeDef *hal_handles[16] = { @@ -274,83 +269,118 @@ struct TimerDomain { #undef X } - static constexpr Config DoTimer(const Entry request, int reqint, int reqidx) { - Config cfg; - cfg.timer_idx = timer_idxmap[reqint]; - cfg.deadtime = request.deadtime; - cfg.polarity = request.polarity; - cfg.negated_polarity = request.negated_polarity; - - // Do any compile time checks needed for the timers... - if(!(reqint == 1 || reqint == 8 || - reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || - reqint == 3 || reqint == 4)) + static constexpr std::array EMPTY_TIMER_NAME = {0,0,0,0, 0,0,0,0}; + + struct Timer { + using domain = TimerDomain; + //GPIODomain::GPIO gpios[4]; + Entry e; + GPIODomain::GPIO gpio0; + GPIODomain::GPIO gpio1; + GPIODomain::GPIO gpio2; + GPIODomain::GPIO gpio3; + + static consteval GPIODomain::AlternateFunction get_gpio_af(ST_LIB::TimerRequest req, ST_LIB::TimerPin pin); + + // TODO: check what this really needs to be for each + static consteval GPIODomain::OperationMode get_operation_mode(ST_LIB::TimerAF af) { - if(request.counting_mode != CountingMode::UP) { - ST_LIB::compile_error("Error: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + switch(af) { + case TimerAF::None: return GPIODomain::OperationMode::INPUT; + + case TimerAF::PWM: return GPIODomain::OperationMode::ALT_PP; + case TimerAF::InputCapture: return GPIODomain::OperationMode::OUTPUT_OPENDRAIN; + + case TimerAF::BreakInput: return GPIODomain::OperationMode::OUTPUT_OPENDRAIN; + case TimerAF::BreakInputCompare: return GPIODomain::OperationMode::OUTPUT_OPENDRAIN; } } - return cfg; - } + // TODO: check what this really needs to be for each + static consteval GPIODomain::Pull get_pull(ST_LIB::TimerAF af) + { + switch(af) { + case TimerAF::None: return GPIODomain::Pull::None; - static constexpr std::array EMPTY_TIMER_NAME = {0,0,0,0, 0,0,0,0}; + case TimerAF::PWM: return GPIODomain::Pull::None; + case TimerAF::InputCapture: return GPIODomain::Pull::Up; + + case TimerAF::BreakInput: return GPIODomain::Pull::None; + case TimerAF::BreakInputCompare: return GPIODomain::Pull::None; + } + } - struct Timer { - using domain = TimerDomain; - Entry e; + // TODO: check what this really needs to be for each + static consteval GPIODomain::Speed get_speed(ST_LIB::TimerAF af) + { + switch(af) { + case TimerAF::None: return GPIODomain::Speed::Low; + + case TimerAF::PWM: return GPIODomain::Speed::Medium; + case TimerAF::InputCapture: return GPIODomain::Speed::High; + + case TimerAF::BreakInput: return GPIODomain::Speed::Medium; + case TimerAF::BreakInputCompare: return GPIODomain::Speed::Medium; + } + } + + static constexpr ST_LIB::TimerPin empty_pin = { + .af = TimerAF::None, + .pin = ST_LIB::PA0, + .channel = TimerChannel::CHANNEL_1, + }; +#define GetPinFromIdx(pinargs, idx) \ + sizeof...(pinargs) > idx ? (ST_LIB::TimerPin[]){pinargs...}[idx] : empty_pin +#define GetGPIOFromIdx(pinargs, request, idx) \ + sizeof...(pinargs) > idx ? (ST_LIB::TimerPin[]){pinargs...}[idx].pin : ST_LIB::PA0, get_operation_mode(sizeof...(pinargs) > idx ? (ST_LIB::TimerPin[]){pinargs...}[idx].af : TimerAF::None), get_pull(sizeof...(pinargs) > idx ? (ST_LIB::TimerPin[]){pinargs...}[idx].af : TimerAF::None), get_speed(sizeof...(pinargs) > idx ? (ST_LIB::TimerPin[]){pinargs...}[idx].af : TimerAF::None), (sizeof...(pinargs) > idx ? get_gpio_af(request, (ST_LIB::TimerPin[]){pinargs...}[idx]) : GPIODomain::AlternateFunction::NO_AF) + + template consteval Timer(TimerRequest request = TimerRequest::AnyGeneralPurpose, - TimerDomain::CountingMode counting_mode = CountingMode::UP, - std::array name = EMPTY_TIMER_NAME, uint32_t deadtime = 0, - uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH, - std::initializer_list pinargs = {}) + std::array name = EMPTY_TIMER_NAME, T... pinargs) : + e(name, request, sizeof...(pinargs), std::array({GetPinFromIdx(pinargs, 0), GetPinFromIdx(pinargs, 1), GetPinFromIdx(pinargs, 2), GetPinFromIdx(pinargs, 3)})), + gpio0(GetGPIOFromIdx(pinargs, request, 0)), + gpio1(GetGPIOFromIdx(pinargs, request, 1)), + gpio2(GetGPIOFromIdx(pinargs, request, 2)), + gpio3(GetGPIOFromIdx(pinargs, request, 3)) { - e.name = name; - e.request = request; - e.counting_mode = counting_mode; - e.deadtime = deadtime; - e.polarity = polarity; - e.negated_polarity = negated_polarity; - - e.pin_count = pinargs.size(); - if(pinargs.size() > 4) { + static_assert((std::is_same_v && ...), + "All template arguments must be of type TimerPin"); + if(sizeof...(pinargs) > 4) { ST_LIB::compile_error("Max 4 pins per timer"); } - int i = 0; - for(TimerPin p : pinargs) { - e.pins[i] = p; - i++; - } } - // anything not initialized will be 0 - consteval Timer(Entry e, std::initializer_list pinargs = {}) { - this->e.name = e.name; - this->e.request = e.request; - this->e.counting_mode = e.counting_mode; - this->e.deadtime = e.deadtime; - this->e.polarity = e.polarity; - this->e.negated_polarity = e.negated_polarity; - if(pinargs.size() == 0) { - this->e.pin_count = e.pin_count; - this->e.pins = e.pins; - } else { - e.pin_count = pinargs.size(); - if(pinargs.size() > 4) { - ST_LIB::compile_error("Max 4 pins per timer"); - } - int i = 0; - for(TimerPin p : pinargs) { - e.pins[i] = p; - i++; - } + // anything uninitialized will be 0 + template + consteval Timer(Entry ent, T... pinargs) : + e(ent.name, ent.request, sizeof...(pinargs), std::array({GetPinFromIdx(pinargs, 0), GetPinFromIdx(pinargs, 1), GetPinFromIdx(pinargs, 2), GetPinFromIdx(pinargs, 3)})), + gpio0(GetGPIOFromIdx(pinargs, ent.request, 0)), + gpio1(GetGPIOFromIdx(pinargs, ent.request, 1)), + gpio2(GetGPIOFromIdx(pinargs, ent.request, 2)), + gpio3(GetGPIOFromIdx(pinargs, ent.request, 3)) + { + static_assert((std::is_same_v && ...), + "All template arguments must be of type TimerPin"); + if(sizeof...(pinargs) > 4) { + ST_LIB::compile_error("Max 4 pins per timer"); } } template consteval void inscribe(Ctx &ctx) const { - ctx.template add(e, this); + if(e.pin_count > 0) { gpio0.inscribe(ctx); } + if(e.pin_count > 1) { gpio1.inscribe(ctx); } + if(e.pin_count > 2) { gpio2.inscribe(ctx); } + if(e.pin_count > 3) { gpio3.inscribe(ctx); } + + TimerDomain::Entry local_entry = { + .name = e.name, + .request = e.request, + .pin_count = e.pin_count, + .pins = e.pins, + }; + ctx.template add(local_entry, this); } }; @@ -364,8 +394,6 @@ struct TimerDomain { ST_LIB::compile_error("too many Timer requests, there are only 16 timers"); } - check_pins(requests); - int remaining_requests[max_instances] = {}; int count_remaining_requests = (int)requests.size(); for(int i = 0; i < (int)requests.size(); i++) remaining_requests[i] = i; @@ -390,7 +418,9 @@ struct TimerDomain { } used_timers[reqint] = true; - Config cfg = DoTimer(requests[i], reqint, i); + Config cfg = { + .timer_idx = timer_idxmap[reqint], + }; cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -418,7 +448,9 @@ struct TimerDomain { } uint8_t reqint = remaining_32bit_timers[count_32bit_requests]; - Config cfg = DoTimer(requests[i], reqint, i); + Config cfg = { + .timer_idx = timer_idxmap[reqint], + }; cfgs[cfg_idx++] = cfg; // unordered remove @@ -465,7 +497,9 @@ struct TimerDomain { ST_LIB::compile_error("This only processes TimerRequest::AnyGeneralPurpose"); } uint8_t reqint = remaining_timers[i]; - Config cfg = DoTimer(requests[i], reqint, i); + Config cfg = { + .timer_idx = timer_idxmap[reqint], + }; cfgs[cfg_idx++] = cfg; } @@ -476,7 +510,7 @@ struct TimerDomain { struct Instance { TIM_TypeDef *tim; TIM_HandleTypeDef *hal_tim; - uint16_t timer_idx; + uint8_t timer_idx; }; static void (*callbacks[TimerDomain::max_instances])(void*); @@ -489,7 +523,7 @@ struct TimerDomain { for(std::size_t i = 0; i < N; i++) { const Config &e = cfgs[i]; - TIM_HandleTypeDef *handle = (TIM_HandleTypeDef*)&hal_handles[e.timer_idx]; + TIM_HandleTypeDef *handle = hal_handles[e.timer_idx]; TIM_TypeDef *tim = cmsis_timers[e.timer_idx]; handle->Instance = tim; handle->Init.Period = 0; @@ -499,375 +533,360 @@ struct TimerDomain { handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; handle->Init.RepetitionCounter = 0; - /* if(e.counting_mode == CountingMode::UP) { - CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else */ - if(e.counting_mode == CountingMode::DOWN) { - SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); - } + handle->ChannelState[0] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelState[1] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelState[2] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelState[3] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelState[4] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelState[5] = HAL_TIM_CHANNEL_STATE_READY; + + handle->ChannelNState[0] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelNState[1] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelNState[2] = HAL_TIM_CHANNEL_STATE_READY; + handle->ChannelNState[3] = HAL_TIM_CHANNEL_STATE_READY; + handle->DMABurstState = HAL_DMA_BURST_STATE_READY; + handle->Lock = HAL_UNLOCKED; + handle->State = HAL_TIM_STATE_READY; rcc_enable_timer(tim); - // InputCapture stuff should be dome somewhere else.. - // PWM stuff should be done somewhere else.. + tim->PSC = 5; // was default in TimerPeripheral.cpp Instance *inst = &instances[i]; inst->tim = tim; inst->hal_tim = handle; inst->timer_idx = e.timer_idx; - __NOP(); } } }; +}; + +consteval GPIODomain::AlternateFunction +TimerDomain::Timer::get_gpio_af(ST_LIB::TimerRequest req, ST_LIB::TimerPin pin) +{ + enum TimerAF_Use { + Channel_1 = 1, + Channel_2 = 2, + Channel_3 = 3, + Channel_4 = 4, + ExternalTriggerFilter, /* ETR */ + BreakInput_1, + BreakInput_2, + BreakInputCompare_1, + BreakInputCompare_2, + }; + + struct TimerPossiblePin { + ST_LIB::GPIODomain::Pin pin; + ST_LIB::GPIODomain::AlternateFunction af; + TimerAF_Use use; + }; + + // 4 capture-compare channels + // complementary output +#define Tim1PinsMacro \ + {ST_LIB::PE6, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_2}, \ + {ST_LIB::PE6, ST_LIB::GPIODomain::AlternateFunction::AF12, BreakInputCompare_2}, \ + \ + {ST_LIB::PA6, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_1}, \ + {ST_LIB::PA6, ST_LIB::GPIODomain::AlternateFunction::AF11, BreakInputCompare_1}, \ + \ + {ST_LIB::PA7, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, /* negated */ \ + {ST_LIB::PB0, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, /* negated */ \ + {ST_LIB::PB1, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, /* negated */ \ + {ST_LIB::PE7, ST_LIB::GPIODomain::AlternateFunction::AF1, ExternalTriggerFilter}, \ + {ST_LIB::PE8, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, /* negated */ \ + {ST_LIB::PE9, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PE10, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, /* negated */\ + {ST_LIB::PE11, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, \ + {ST_LIB::PE12, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, /* negated */\ + {ST_LIB::PE13, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, \ + {ST_LIB::PE14, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_4}, \ + \ + {ST_LIB::PE15, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_1}, \ + {ST_LIB::PE15, ST_LIB::GPIODomain::AlternateFunction::AF13, BreakInputCompare_1}, \ + \ + {ST_LIB::PB12, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_1}, \ + {ST_LIB::PB12, ST_LIB::GPIODomain::AlternateFunction::AF13, BreakInputCompare_1}, \ + \ + {ST_LIB::PB13, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, /* negated */\ + {ST_LIB::PB14, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, /* negated */\ + {ST_LIB::PB15, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, /* negated */\ + \ + {ST_LIB::PG4, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_2}, \ + {ST_LIB::PG4, ST_LIB::GPIODomain::AlternateFunction::AF11, BreakInputCompare_2}, \ + \ + {ST_LIB::PG5, ST_LIB::GPIODomain::AlternateFunction::AF1, ExternalTriggerFilter}, \ + \ + {ST_LIB::PA8, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PA9, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, \ + {ST_LIB::PA10, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, \ + {ST_LIB::PA11, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_4}, \ + \ + {ST_LIB::PA12, ST_LIB::GPIODomain::AlternateFunction::AF1, ExternalTriggerFilter}, \ + {ST_LIB::PA12, ST_LIB::GPIODomain::AlternateFunction::AF12, BreakInput_2}, + + // 4 capture-compare channels +#define Tim2PinsMacro \ + {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::AF1, ExternalTriggerFilter}, \ + {ST_LIB::PA1, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, \ + {ST_LIB::PA2, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, \ + {ST_LIB::PA3, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_4}, \ + \ + {ST_LIB::PA5, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PA5, ST_LIB::GPIODomain::AlternateFunction::AF1, ExternalTriggerFilter}, \ + \ + {ST_LIB::PA15, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PA15, ST_LIB::GPIODomain::AlternateFunction::AF1, ExternalTriggerFilter}, \ + {ST_LIB::PB3, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_2}, \ + {ST_LIB::PB10, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_3}, \ + {ST_LIB::PB11, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_4}, + + // 4 capture-compare channels +#define Tim3PinsMacro \ + {ST_LIB::PA6, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PA7, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, \ + {ST_LIB::PB0, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_3}, \ + {ST_LIB::PB1, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_4}, \ + \ + {ST_LIB::PB4, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PB5, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, \ + \ + {ST_LIB::PC6, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PC7, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, \ + {ST_LIB::PC8, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_3}, \ + {ST_LIB::PC9, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_4}, \ + \ + {ST_LIB::PD2, ST_LIB::GPIODomain::AlternateFunction::AF2, ExternalTriggerFilter}, + + // 4 capture-compare channels +#define Tim4PinsMacro \ + {ST_LIB::PB6, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PB7, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, \ + {ST_LIB::PB8, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_3}, \ + {ST_LIB::PB9, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_4}, \ + \ + {ST_LIB::PD12, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PD13, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, \ + {ST_LIB::PD14, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_3}, \ + {ST_LIB::PD15, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_4}, \ + \ + {ST_LIB::PE0, ST_LIB::GPIODomain::AlternateFunction::AF2, ExternalTriggerFilter}, + + // 4 capture-compare channels +#define Tim5PinsMacro \ + {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PA1, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, \ + {ST_LIB::PA2, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_3}, \ + {ST_LIB::PA3, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_4}, \ + {ST_LIB::PA4, ST_LIB::GPIODomain::AlternateFunction::AF2, ExternalTriggerFilter}, + + // anything invalid, this doesn't get checked for basic timers because they have no pins +#define Tim6PinsMacro {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::NO_AF, Channel_1} + // anything invalid, this doesn't get checked for basic timers because they have no pins +#define Tim7PinsMacro {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::NO_AF, Channel_1} + + // 4 capture-compare channels + // complementary output +#define Tim8PinsMacro \ + {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::AF3, ExternalTriggerFilter}, \ + {ST_LIB::PA5, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_1}, /* negated */ \ + \ + {ST_LIB::PA6, ST_LIB::GPIODomain::AlternateFunction::AF3, BreakInput_1}, \ + {ST_LIB::PA6, ST_LIB::GPIODomain::AlternateFunction::AF10, BreakInputCompare_1}, \ + \ + {ST_LIB::PA7, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_1}, /* negated */ \ + \ + {ST_LIB::PA8, ST_LIB::GPIODomain::AlternateFunction::AF3, BreakInput_2}, \ + {ST_LIB::PA8, ST_LIB::GPIODomain::AlternateFunction::AF12, BreakInputCompare_2}, \ + \ + {ST_LIB::PB0, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_2}, /* negated */ \ + {ST_LIB::PB1, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_3}, /* negated */ \ + {ST_LIB::PB14, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_2}, /* negated */\ + {ST_LIB::PB15, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_3}, /* negated */\ + \ + {ST_LIB::PC6, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_1}, \ + {ST_LIB::PC7, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_2}, \ + {ST_LIB::PC8, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_3}, \ + {ST_LIB::PC9, ST_LIB::GPIODomain::AlternateFunction::AF3, Channel_4}, \ + \ + {ST_LIB::PG2, ST_LIB::GPIODomain::AlternateFunction::AF3, BreakInput_1}, \ + {ST_LIB::PG2, ST_LIB::GPIODomain::AlternateFunction::AF11, BreakInputCompare_1}, \ + \ + {ST_LIB::PG3, ST_LIB::GPIODomain::AlternateFunction::AF3, BreakInput_2}, \ + {ST_LIB::PG3, ST_LIB::GPIODomain::AlternateFunction::AF11, BreakInputCompare_2}, \ + \ + {ST_LIB::PG8, ST_LIB::GPIODomain::AlternateFunction::AF3, ExternalTriggerFilter}, + + // 2 capture-compare channels +#define Tim12PinsMacro \ + {ST_LIB::PB14, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PB15, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_2}, + + // 1 capture-compare channel +#define Tim13PinsMacro \ + {ST_LIB::PA6, ST_LIB::GPIODomain::AlternateFunction::AF9, Channel_1}, \ + {ST_LIB::PF8, ST_LIB::GPIODomain::AlternateFunction::AF9, Channel_1}, + + // 1 capture-compare channel +#define Tim14PinsMacro \ + {ST_LIB::PA7, ST_LIB::GPIODomain::AlternateFunction::AF9, Channel_1}, \ + {ST_LIB::PF9, ST_LIB::GPIODomain::AlternateFunction::AF9, Channel_1}, + + // 2 capture-compare channels +#define Tim15PinsMacro \ + {ST_LIB::PA0, ST_LIB::GPIODomain::AlternateFunction::AF4, BreakInput_1}, \ + \ + {ST_LIB::PA1, ST_LIB::GPIODomain::AlternateFunction::AF4, Channel_1}, /* negated */ \ + {ST_LIB::PA2, ST_LIB::GPIODomain::AlternateFunction::AF4, Channel_1}, \ + {ST_LIB::PA3, ST_LIB::GPIODomain::AlternateFunction::AF4, Channel_2}, \ + \ + {ST_LIB::PC12, ST_LIB::GPIODomain::AlternateFunction::AF2, Channel_1}, \ + {ST_LIB::PD2, ST_LIB::GPIODomain::AlternateFunction::AF4, Channel_2}, \ + \ + {ST_LIB::PE3, ST_LIB::GPIODomain::AlternateFunction::AF4, BreakInput_1}, \ + {ST_LIB::PE4, ST_LIB::GPIODomain::AlternateFunction::AF4, BreakInput_1}, \ + \ + {ST_LIB::PE4, ST_LIB::GPIODomain::AlternateFunction::AF4, Channel_1}, \ + {ST_LIB::PE4, ST_LIB::GPIODomain::AlternateFunction::AF4, Channel_2}, + + // 1 capture-compare channel +#define Tim16PinsMacro \ + {ST_LIB::PF6, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PF8, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, /* negated */ \ + {ST_LIB::PF10, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_1}, + + // 1 capture-compare channel +#define Tim17PinsMacro \ + {ST_LIB::PB5, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_1}, \ + {ST_LIB::PB7, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, /* negated */ \ + {ST_LIB::PB9, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PF7, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, \ + {ST_LIB::PF9, ST_LIB::GPIODomain::AlternateFunction::AF1, Channel_1}, /* negated */ \ + {ST_LIB::PG6, ST_LIB::GPIODomain::AlternateFunction::AF1, BreakInput_1}, + + // 4 capture-compare channels +#define Tim23PinsMacro \ + {ST_LIB::PB2, ST_LIB::GPIODomain::AlternateFunction::AF13, ExternalTriggerFilter}, \ + {ST_LIB::PF0, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_1}, \ + {ST_LIB::PF1, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_2}, \ + {ST_LIB::PF2, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_3}, \ + {ST_LIB::PF3, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_4}, \ + \ + {ST_LIB::PF6, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_1}, \ + {ST_LIB::PF7, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_2}, \ + {ST_LIB::PF8, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_3}, \ + {ST_LIB::PF9, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_4}, \ + \ + {ST_LIB::PG3, ST_LIB::GPIODomain::AlternateFunction::AF13, ExternalTriggerFilter}, \ + {ST_LIB::PG12, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_1}, \ + {ST_LIB::PG13, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_2}, \ + {ST_LIB::PG14, ST_LIB::GPIODomain::AlternateFunction::AF13, Channel_3}, + + // 4 capture-compare channels +#define Tim24PinsMacro \ + {ST_LIB::PB3, ST_LIB::GPIODomain::AlternateFunction::AF14, ExternalTriggerFilter}, \ + {ST_LIB::PF11, ST_LIB::GPIODomain::AlternateFunction::AF14, Channel_1}, \ + {ST_LIB::PF12, ST_LIB::GPIODomain::AlternateFunction::AF14, Channel_2}, \ + {ST_LIB::PF13, ST_LIB::GPIODomain::AlternateFunction::AF14, Channel_3}, \ + {ST_LIB::PF14, ST_LIB::GPIODomain::AlternateFunction::AF14, Channel_4}, \ + {ST_LIB::PG2, ST_LIB::GPIODomain::AlternateFunction::AF14, ExternalTriggerFilter}, + +#define X(timx, ignore) \ + constexpr TimerPossiblePin glue(tim, glue(timx, pins))[31] = { \ + glue(Tim, glue(timx, PinsMacro)) \ + }; \ + constexpr std::size_t glue(tim, glue(timx, pin_count)) = ARRAY_LENGTH(glue(tim, glue(timx, pins))); + + TimerXList + +#undef X - static consteval void check_pins(std::span requests) + struct TimerPossPins { + TimerPossiblePin pins[31]; + std::size_t pin_count; + }; + constexpr TimerPossPins empty_pins = { + .pins = {}, + .pin_count = 0 + }; + constexpr TimerPossPins tim_pins[25] = { + empty_pins, /* 0 */ + {{Tim1PinsMacro}, tim1pin_count}, /* TIM1 */ + {{Tim2PinsMacro}, tim2pin_count}, /* TIM2 */ + {{Tim3PinsMacro}, tim3pin_count}, /* TIM3 */ + {{Tim4PinsMacro}, tim4pin_count}, /* TIM4 */ + {{Tim5PinsMacro}, tim5pin_count}, /* TIM5 */ + {{Tim6PinsMacro}, tim6pin_count}, /* TIM6 - won't get checked since they have no associated pins */ + {{Tim7PinsMacro}, tim7pin_count}, /* TIM7 - won't get checked since they have no associated pins */ + {{Tim8PinsMacro}, tim8pin_count}, /* TIM8 */ + empty_pins, /* 9 */ + empty_pins, /* 10 */ + empty_pins, /* 11 */ + {{Tim12PinsMacro}, tim12pin_count}, /* TIM12 */ + {{Tim13PinsMacro}, tim13pin_count}, /* TIM13 */ + {{Tim14PinsMacro}, tim14pin_count}, /* TIM14 */ + {{Tim15PinsMacro}, tim15pin_count}, /* TIM15 */ + {{Tim16PinsMacro}, tim16pin_count}, /* TIM16 */ + {{Tim17PinsMacro}, tim17pin_count}, /* TIM17 */ + empty_pins, /* 18 */ + empty_pins, /* 19 */ + empty_pins, /* 20 */ + empty_pins, /* 21 */ + empty_pins, /* 22 */ + {{Tim23PinsMacro}, tim23pin_count}, /* TIM23 */ + {{Tim24PinsMacro}, tim24pin_count}, /* TIM24 */ + }; + + if(req == TimerRequest::AnyGeneralPurpose || + req == TimerRequest::Any32bit) { - enum TimerAF_Use { - Channel_1 = 1, - Channel_2 = 2, - Channel_3 = 3, - Channel_4 = 4, - ExternalTriggerFilter, /* ETR */ - BreakInput_1, - BreakInput_2, - BreakInputCompare_1, - BreakInputCompare_2, - }; + ST_LIB::compile_error("Any* timers can't use pins"); + } + if(req == TimerRequest::Basic_6 || + req == TimerRequest::Basic_7) + { + ST_LIB::compile_error("Basic timers can't use pins"); + } - struct TimerPossiblePin { - ST_LIB::GPIODomain::Pin pin; - ST_LIB::GPIODomain::AlternateFunction af; - TimerAF_Use use; - }; - TimerPossiblePin tim1pins[] = { - // 4 capture-compare channels - // complementary output - {ST_LIB::PE6, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_2}, - {ST_LIB::PE6, (ST_LIB::GPIODomain::AlternateFunction)12, BreakInputCompare_2}, - - {ST_LIB::PA6, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_1}, - {ST_LIB::PA6, (ST_LIB::GPIODomain::AlternateFunction)11, BreakInputCompare_1}, - - {ST_LIB::PA7, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, /* negated */ - {ST_LIB::PB0, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, /* negated */ - {ST_LIB::PB1, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, /* negated */ - {ST_LIB::PE7, (ST_LIB::GPIODomain::AlternateFunction)1, ExternalTriggerFilter}, - {ST_LIB::PE8, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, /* negated */ - {ST_LIB::PE9, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PE10, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, /* negated */ - {ST_LIB::PE11, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, - {ST_LIB::PE12, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, /* negated */ - {ST_LIB::PE13, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, - {ST_LIB::PE14, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_4}, - - {ST_LIB::PE15, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_1}, - {ST_LIB::PE15, (ST_LIB::GPIODomain::AlternateFunction)13, BreakInputCompare_1}, - - {ST_LIB::PB12, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_1}, - {ST_LIB::PB12, (ST_LIB::GPIODomain::AlternateFunction)13, BreakInputCompare_1}, - - {ST_LIB::PB13, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, /* negated */ - {ST_LIB::PB14, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, /* negated */ - {ST_LIB::PB15, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, /* negated */ - - {ST_LIB::PG4, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_2}, - {ST_LIB::PG4, (ST_LIB::GPIODomain::AlternateFunction)11, BreakInputCompare_2}, - - {ST_LIB::PG5, (ST_LIB::GPIODomain::AlternateFunction)1, ExternalTriggerFilter}, - - {ST_LIB::PA8, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PA9, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, - {ST_LIB::PA10, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, - {ST_LIB::PA11, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_4}, - - {ST_LIB::PA12, (ST_LIB::GPIODomain::AlternateFunction)1, ExternalTriggerFilter}, - {ST_LIB::PA12, (ST_LIB::GPIODomain::AlternateFunction)12, BreakInput_2}, // comprobar - }; - TimerPossiblePin tim2pins[] = { - // 4 capture-compare channels - {ST_LIB::PA0, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PA0, (ST_LIB::GPIODomain::AlternateFunction)1, ExternalTriggerFilter}, - {ST_LIB::PA1, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, - {ST_LIB::PA2, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, - {ST_LIB::PA3, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_4}, - - {ST_LIB::PA5, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PA5, (ST_LIB::GPIODomain::AlternateFunction)1, ExternalTriggerFilter}, - - {ST_LIB::PA15, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PA15, (ST_LIB::GPIODomain::AlternateFunction)1, ExternalTriggerFilter}, - {ST_LIB::PB3, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_2}, - {ST_LIB::PB10, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_3}, - {ST_LIB::PB11, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_4}, - }; - TimerPossiblePin tim3pins[] = { - // 4 capture-compare channels - {ST_LIB::PA6, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PA7, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - {ST_LIB::PB0, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_3}, - {ST_LIB::PB1, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_4}, - - {ST_LIB::PB4, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PB5, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - - {ST_LIB::PC6, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PC7, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - {ST_LIB::PC8, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_3}, - {ST_LIB::PC9, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_4}, - - {ST_LIB::PD2, (ST_LIB::GPIODomain::AlternateFunction)2, ExternalTriggerFilter}, - }; - TimerPossiblePin tim4pins[] = { - // 4 capture-compare channels - {ST_LIB::PB6, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PB7, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - {ST_LIB::PB8, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_3}, - {ST_LIB::PB9, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_4}, - - {ST_LIB::PD12, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PD13, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - {ST_LIB::PD14, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_3}, - {ST_LIB::PD15, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_4}, - - {ST_LIB::PE0, (ST_LIB::GPIODomain::AlternateFunction)2, ExternalTriggerFilter}, - }; - TimerPossiblePin tim5pins[] = { - // 4 capture-compare channels - {ST_LIB::PA0, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PA1, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - {ST_LIB::PA2, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_3}, - {ST_LIB::PA3, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_4}, - {ST_LIB::PA4, (ST_LIB::GPIODomain::AlternateFunction)2, ExternalTriggerFilter}, - }; - TimerPossiblePin tim8pins[] = { - // 4 capture-compare channels - // complementary output - {ST_LIB::PA0, (ST_LIB::GPIODomain::AlternateFunction)3, ExternalTriggerFilter}, - {ST_LIB::PA5, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_1}, /* negated */ - - {ST_LIB::PA6, (ST_LIB::GPIODomain::AlternateFunction)3, BreakInput_1}, - {ST_LIB::PA6, (ST_LIB::GPIODomain::AlternateFunction)10, BreakInputCompare_1}, - - {ST_LIB::PA7, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_1}, /* negated */ - - {ST_LIB::PA8, (ST_LIB::GPIODomain::AlternateFunction)3, BreakInput_2}, - {ST_LIB::PA8, (ST_LIB::GPIODomain::AlternateFunction)12, BreakInputCompare_2}, - - {ST_LIB::PB0, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_2}, /* negated */ - {ST_LIB::PB1, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_3}, /* negated */ - {ST_LIB::PB14, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_2}, /* negated */ - {ST_LIB::PB15, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_3}, /* negated */ - - {ST_LIB::PC6, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_1}, - {ST_LIB::PC7, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_2}, - {ST_LIB::PC8, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_3}, - {ST_LIB::PC9, (ST_LIB::GPIODomain::AlternateFunction)3, Channel_4}, - - {ST_LIB::PG2, (ST_LIB::GPIODomain::AlternateFunction)3, BreakInput_1}, - {ST_LIB::PG2, (ST_LIB::GPIODomain::AlternateFunction)11, BreakInputCompare_1}, - - {ST_LIB::PG3, (ST_LIB::GPIODomain::AlternateFunction)3, BreakInput_2}, - {ST_LIB::PG3, (ST_LIB::GPIODomain::AlternateFunction)11, BreakInputCompare_2}, - - {ST_LIB::PG8, (ST_LIB::GPIODomain::AlternateFunction)3, ExternalTriggerFilter}, - }; - TimerPossiblePin tim12pins[] = { - // 2 capture-compare channels - {ST_LIB::PB14, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PB15, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_2}, - }; - TimerPossiblePin tim13pins[] = { - // 1 capture-compare channel - {ST_LIB::PA6, (ST_LIB::GPIODomain::AlternateFunction)9, Channel_1}, - {ST_LIB::PF8, (ST_LIB::GPIODomain::AlternateFunction)9, Channel_1}, - }; - TimerPossiblePin tim14pins[] = { - // 1 capture-compare channel - {ST_LIB::PA7, (ST_LIB::GPIODomain::AlternateFunction)9, Channel_1}, - {ST_LIB::PF9, (ST_LIB::GPIODomain::AlternateFunction)9, Channel_1}, - }; - TimerPossiblePin tim15pins[] = { - // 2 capture-compare channels - {ST_LIB::PA0, (ST_LIB::GPIODomain::AlternateFunction)4, BreakInput_1}, - - {ST_LIB::PA1, (ST_LIB::GPIODomain::AlternateFunction)4, Channel_1}, /* negated */ - {ST_LIB::PA2, (ST_LIB::GPIODomain::AlternateFunction)4, Channel_1}, - {ST_LIB::PA3, (ST_LIB::GPIODomain::AlternateFunction)4, Channel_2}, - - {ST_LIB::PC12, (ST_LIB::GPIODomain::AlternateFunction)2, Channel_1}, - {ST_LIB::PD2, (ST_LIB::GPIODomain::AlternateFunction)4, Channel_2}, - - {ST_LIB::PE3, (ST_LIB::GPIODomain::AlternateFunction)4, BreakInput_1}, - {ST_LIB::PE4, (ST_LIB::GPIODomain::AlternateFunction)4, BreakInput_1}, - - {ST_LIB::PE4, (ST_LIB::GPIODomain::AlternateFunction)4, Channel_1}, - {ST_LIB::PE4, (ST_LIB::GPIODomain::AlternateFunction)4, Channel_2}, - }; - TimerPossiblePin tim16pins[] = { - // 1 capture-compare channel - {ST_LIB::PF6, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PF8, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, /* negated */ - {ST_LIB::PF10, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_1}, - }; - TimerPossiblePin tim17pins[] = { - // 1 capture-compare channel - {ST_LIB::PB5, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_1}, - {ST_LIB::PB7, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, /* negated */ - {ST_LIB::PB9, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PF7, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, - {ST_LIB::PF9, (ST_LIB::GPIODomain::AlternateFunction)1, Channel_1}, /* negated */ - {ST_LIB::PG6, (ST_LIB::GPIODomain::AlternateFunction)1, BreakInput_1}, - }; - TimerPossiblePin tim23pins[] = { - // 4 capture-compare channels - {ST_LIB::PB2, (ST_LIB::GPIODomain::AlternateFunction)13, ExternalTriggerFilter}, - {ST_LIB::PF0, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_1}, - {ST_LIB::PF1, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_2}, - {ST_LIB::PF2, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_3}, - {ST_LIB::PF3, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_4}, - - {ST_LIB::PF6, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_1}, - {ST_LIB::PF7, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_2}, - {ST_LIB::PF8, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_3}, - {ST_LIB::PF9, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_4}, - - {ST_LIB::PG3, (ST_LIB::GPIODomain::AlternateFunction)13, ExternalTriggerFilter}, - {ST_LIB::PG12, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_1}, - {ST_LIB::PG13, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_2}, - {ST_LIB::PG14, (ST_LIB::GPIODomain::AlternateFunction)13, Channel_3}, - }; - TimerPossiblePin tim24pins[] = { - // 4 capture-compare channels - {ST_LIB::PB3, (ST_LIB::GPIODomain::AlternateFunction)14, ExternalTriggerFilter}, - {ST_LIB::PF11, (ST_LIB::GPIODomain::AlternateFunction)14, Channel_1}, - {ST_LIB::PF12, (ST_LIB::GPIODomain::AlternateFunction)14, Channel_2}, - {ST_LIB::PF13, (ST_LIB::GPIODomain::AlternateFunction)14, Channel_3}, - {ST_LIB::PF14, (ST_LIB::GPIODomain::AlternateFunction)14, Channel_4}, - {ST_LIB::PG2, (ST_LIB::GPIODomain::AlternateFunction)14, ExternalTriggerFilter}, - }; + bool found = false; + for(std::size_t j = 0; j < tim_pins[(int)req].pin_count; j++) { + if(pin.af == ST_LIB::TimerAF::None) { + ST_LIB::compile_error("Error: Timers with pins must have associated TimerAF (alternate functions)"); + } else if(((pin.af == ST_LIB::TimerAF::InputCapture || pin.af == ST_LIB::TimerAF::PWM) && + (static_cast(pin.channel) == static_cast(tim_pins[(int)req].pins[j].use))) || - std::span tim_pins[25]; - tim_pins[TimerRequest::Advanced_1] = std::span(tim1pins); - tim_pins[TimerRequest::GeneralPurpose32bit_2] = std::span(tim2pins); - tim_pins[TimerRequest::GeneralPurpose_3] = std::span(tim3pins); - tim_pins[TimerRequest::GeneralPurpose_4] = std::span(tim4pins); - tim_pins[TimerRequest::GeneralPurpose32bit_5] = std::span(tim5pins); - /* TIM6, TIM7 have no associated pins */ - tim_pins[TimerRequest::Advanced_8] = std::span(tim8pins); - tim_pins[TimerRequest::SlaveTimer_12] = std::span(tim12pins); - tim_pins[TimerRequest::SlaveTimer_13] = std::span(tim13pins); - tim_pins[TimerRequest::SlaveTimer_14] = std::span(tim14pins); - tim_pins[TimerRequest::GeneralPurpose_15] = std::span(tim15pins); - tim_pins[TimerRequest::GeneralPurpose_16] = std::span(tim16pins); - tim_pins[TimerRequest::GeneralPurpose_17] = std::span(tim17pins); - tim_pins[TimerRequest::GeneralPurpose32bit_23] = std::span(tim23pins); - tim_pins[TimerRequest::GeneralPurpose32bit_24] = std::span(tim24pins); - - /* good luck n_n */ - for(std::size_t i = 0; i < requests.size(); i++) { - const Entry &e = requests[i]; - if(e.pin_count == 0) continue; - if(e.request == TimerRequest::AnyGeneralPurpose || - e.request == TimerRequest::Any32bit) - { - ST_LIB::compile_error("Any* timers can't use pins"); - } - if(e.request == TimerRequest::Basic_6 || - e.request == TimerRequest::Basic_7) - { - ST_LIB::compile_error("Basic timers can't use pins"); - } + ((pin.af == ST_LIB::TimerAF::BreakInput) && + (tim_pins[(int)req].pins[j].use == BreakInput_1 || tim_pins[(int)req].pins[j].use == BreakInput_2)) || - std::span curr_pins = tim_pins[(int)e.request]; - for(int j = 0; j < e.pin_count; j++) { - ST_LIB::TimerPin pin = e.pins[j]; - bool found = false; - for(TimerPossiblePin p : curr_pins) { - if(pin.af == ST_LIB::TimerAF::None) { - ST_LIB::compile_error("Error: Timers with pins must have associated TimerAF (alternate functions)"); - } else if(pin.af == ST_LIB::TimerAF::InputCapture || pin.af == ST_LIB::TimerAF::PWM) { - if((static_cast(pin.channel) == static_cast(p.use))) { - found = true; - break; - } - } else if(pin.af == ST_LIB::TimerAF::BreakInput) { - if(p.use == BreakInput_1 || p.use == BreakInput_2) { - found = true; - break; - } - } else if(pin.af == ST_LIB::TimerAF::BreakInputCompare) { - if(p.use == BreakInputCompare_1 || p.use == BreakInputCompare_2) { - found = true; - break; - } - } - } - if(!found) { - ST_LIB::compile_error("Error: Couldn't find any pins with the requested alternate function"); - } - } + ((pin.af == ST_LIB::TimerAF::BreakInputCompare) && + (tim_pins[(int)req].pins[j].use == BreakInputCompare_1 || tim_pins[(int)req].pins[j].use == BreakInputCompare_2))) + { + found = true; + // TODO: GPIO operation mode + // TODO: GPIO Pull + // TODO: GPIO Speed + return tim_pins[(int)req].pins[j].af; } } -}; + if(!found) { + ST_LIB::compile_error("Error: Couldn't find any pins with the requested alternate function"); + } + + return GPIODomain::AlternateFunction::NO_AF; +} + } // namespace ST_LIB #endif // HAL_TIM_MODULE_ENABLED /* Old init code from TimerPeripheral.cpp, some might be recycled - TIM_MasterConfigTypeDef sMasterConfig = {0}; - TIM_IC_InitTypeDef sConfigIC = {0}; - TIM_OC_InitTypeDef sConfigOC = {0}; - TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; - - TIM_HandleTypeDef *handle = &hal_handles[e.timer_idx]; - handle->Instance = cmsis_timers[e.timer_idx]; - handle->Init.Prescaler = e.prescaler; - handle->Init.CounterMode = TIM_COUNTERMODE_UP; - handle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - // PWM stuff should be done somewhere else.. - handle->Init.Period = e.period; - handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - handle->Init.RepetitionCounter = 0; - - if(e.type == TIM_TYPE::BASE) { - if(HAL_TIM_Base_Init(handle) != HAL_OK) { - // NOTE: In TimerPeripheral.cpp this is %d for a string ??? - ErrorHandler("Unable to init base timer on %s", e.name); - } - } - - // InputCapture stuff should be dome somewhere else.. - // PWM stuff should be done somewhere else.. - - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - if(HAL_TIMEx_MasterConfigSynchronization(handle, &sMasterConfig) != HAL_OK) { - ErrorHandler("Unable to configure master synch on %s", e.name); - } - - // InputCapture stuff should be dome somewhere else.. - // PWM stuff should be done somewhere else.. - - sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; - sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; - sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; - sBreakDeadTimeConfig.DeadTime = e.deadtime; - sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; - sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH; - sBreakDeadTimeConfig.BreakFilter = 0; - sBreakDeadTimeConfig.Break2State = TIM_BREAK2_DISABLE; - sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; - sBreakDeadTimeConfig.Break2Filter = 0; - sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; - if(HAL_TIMEx_ConfigBreakDeadTime(handle, &sBreakDeadTimeConfig) != HAL_OK) { - ErrorHandler("Unable to configure break dead time on %s", e.name); - } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if(HAL_TIMEx_MasterConfigSynchronization(handle, &sMasterConfig) != HAL_OK) { + ErrorHandler("Unable to configure master synch on %s", e.name); + } */ \ No newline at end of file diff --git a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp index 23618d94..99134bbc 100644 --- a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp +++ b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp @@ -26,7 +26,7 @@ struct PWMData { PWM_MODE mode; }; -template +template class PWM { static consteval uint8_t get_channel_state_idx(const ST_LIB::TimerChannel ch) { switch(ch) { @@ -60,81 +60,107 @@ class PWM { static constexpr float CLOCK_FREQ_MHZ_WITHOUT_PRESCALER = 275.0f; static constexpr float clock_period_ns = (1.0f/CLOCK_FREQ_MHZ_WITHOUT_PRESCALER)*1000.0f; - TimerWrapper &timer; - TimerPin pin; + TimerWrapper *timer; uint32_t frequency; float duty_cycle; bool is_on = false; bool is_center_aligned; public: - PWM(TimerWrapper &tim, TimerPin pin) : timer(tim) { - static_assert(dev.e.request != TimerRequest::Basic_6 && dev.e.request != TimerRequest::Basic_7, "These timers don't support pwm"); - this->is_center_aligned = ((tim.tim->CR1 & TIM_CR1_CMS) != 0); - this->pin = pin; + PWM(TimerWrapper *tim, uint32_t polarity, uint32_t negated_polarity) : timer(tim) { + this->is_center_aligned = ((timer->instance.tim->CR1 & TIM_CR1_CMS) != 0); + + TIM_OC_InitTypeDef sConfigOC = { + .OCMode = TIM_OCMODE_PWM1, + .Pulse = 0, + + .OCPolarity = polarity, + .OCNPolarity = negated_polarity, + + .OCFastMode = TIM_OCFAST_DISABLE, + .OCIdleState = TIM_OCIDLESTATE_RESET, + .OCNIdleState = TIM_OCNIDLESTATE_RESET, + }; + timer->template config_output_compare_channel(&sConfigOC); + timer->template set_output_compare_preload_enable(); } void turn_on() { - if(is_on) return; + if(this->is_on) return; - // if(HAL_TIM_PWM_Start(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } - HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[get_channel_state_idx(pin.channel)]; + //if(HAL_TIM_PWM_Start(timer->instance.hal_tim, channel) != HAL_OK) { ErrorHandler("", 0); } + volatile HAL_TIM_ChannelStateTypeDef *state = &timer->instance.hal_tim->ChannelState[get_channel_state_idx(pin.channel)]; if(*state != HAL_TIM_CHANNEL_STATE_READY) { ErrorHandler("Channel not ready"); } *state = HAL_TIM_CHANNEL_STATE_BUSY; // enable CCx - uint32_t tmp = TIM_CCER_CC1E << (get_channel_mul4(pin.channel) & 0x1FU); /* 0x1FU = 31 bits max shift */ - - SET_BIT(timer.tim->CCER, (uint32_t)(TIM_CCx_ENABLE << (get_channel_mul4(pin.channel) & 0x1FU))); + uint32_t enableCCx = TIM_CCER_CC1E << (get_channel_mul4(pin.channel) & 0x1FU); /* 0x1FU = 31 bits max shift */ + SET_BIT(timer->instance.tim->CCER, enableCCx); - // if timer supports break - if constexpr ((dev.e.request == (TimerRequest)1) || (dev.e.request == (TimerRequest)8) || (dev.e.request == (TimerRequest)15) || (dev.e.request == (TimerRequest)16) || (dev.e.request == (TimerRequest)17)) - { + if constexpr(timer->is_break_instance) { // Main Output Enable - SET_BIT(timer.tim->BDTR, TIM_BDTR_MOE); + SET_BIT(timer->instance.tim->BDTR, TIM_BDTR_MOE); } - // if timer can be a slave timer - if constexpr ((dev.e.request == (TimerRequest)1) || (dev.e.request == (TimerRequest)2) || (dev.e.request == (TimerRequest)3) || (dev.e.request == (TimerRequest)4) || (dev.e.request == (TimerRequest)5) || (dev.e.request == (TimerRequest)8) || (dev.e.request == (TimerRequest)12) || (dev.e.request == (TimerRequest)15) || (dev.e.request == (TimerRequest)23) || (dev.e.request == (TimerRequest)24)) - { - uint32_t tmpsmcr = timer.tim->SMCR & TIM_SMCR_SMS; + if constexpr(timer->is_slave_instance) { + uint32_t tmpsmcr = timer->instance.tim->SMCR & TIM_SMCR_SMS; if(!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr)) { - timer.counter_enable(); + timer->counter_enable(); } } else { - timer.counter_enable(); + timer->counter_enable(); + } + + if constexpr(pin.channel == ST_LIB::TimerChannel::CHANNEL_1) { + SET_BIT(timer->instance.tim->CCER, TIM_CCER_CC1E); + } else if constexpr(pin.channel == ST_LIB::TimerChannel::CHANNEL_2) { + SET_BIT(timer->instance.tim->CCER, TIM_CCER_CC2E); + } else if constexpr(pin.channel == ST_LIB::TimerChannel::CHANNEL_3) { + SET_BIT(timer->instance.tim->CCER, TIM_CCER_CC3E); + } else if constexpr(pin.channel == ST_LIB::TimerChannel::CHANNEL_4) { + SET_BIT(timer->instance.tim->CCER, TIM_CCER_CC4E); + } else if constexpr(pin.channel == ST_LIB::TimerChannel::CHANNEL_5) { + SET_BIT(timer->instance.tim->CCER, TIM_CCER_CC5E); + } else if constexpr(pin.channel == ST_LIB::TimerChannel::CHANNEL_6) { + SET_BIT(timer->instance.tim->CCER, TIM_CCER_CC6E); } - is_on = true; + this->is_on = true; } void turn_off() { - if(!is_on) return; - // if(HAL_TIM_PWM_Stop(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } + if(!this->is_on) return; + // if(HAL_TIM_PWM_Stop(timer->instance.hal_tim, channel) != HAL_OK) { ErrorHandler("", 0); } - SET_BIT(timer.tim->CCER, (uint32_t)(TIM_CCx_DISABLE << (get_channel_mul4(pin.channel) & 0x1FU))); + SET_BIT(timer->tim->CCER, (uint32_t)(TIM_CCx_DISABLE << (get_channel_mul4(pin.channel) & 0x1FU))); - // if timer supports break - if constexpr ((dev.e.request == (TimerRequest)1) || (dev.e.request == (TimerRequest)8) || (dev.e.request == (TimerRequest)15) || (dev.e.request == (TimerRequest)16) || (dev.e.request == (TimerRequest)17)) - { + if constexpr(timer->is_break_instance) { // Disable Main Output Enable (MOE) - CLEAR_BIT(timer.tim->BDTR, TIM_BDTR_MOE); + CLEAR_BIT(timer->tim->BDTR, TIM_BDTR_MOE); } - __HAL_TIM_DISABLE(timer.htim); - - HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[get_channel_state_idx(pin.channel)]; + HAL_TIM_ChannelStateTypeDef *state = &timer->instance.hal_tim.ChannelState[get_channel_state_idx(pin.channel)]; *state = HAL_TIM_CHANNEL_STATE_READY; - is_on = false; + if(timer->instance.hal_tim->ChannelState[0] == HAL_TIM_CHANNEL_STATE_READY && + timer->instance.hal_tim->ChannelState[1] == HAL_TIM_CHANNEL_STATE_READY && + timer->instance.hal_tim->ChannelState[2] == HAL_TIM_CHANNEL_STATE_READY && + timer->instance.hal_tim->ChannelState[3] == HAL_TIM_CHANNEL_STATE_READY && + timer->instance.hal_tim->ChannelState[4] == HAL_TIM_CHANNEL_STATE_READY && + timer->instance.hal_tim->ChannelState[5] == HAL_TIM_CHANNEL_STATE_READY) + { + timer->counter_disable(); + } + + this->is_on = false; } void set_duty_cycle(float duty_cycle) { - uint16_t raw_duty = (uint16_t)((float)timer->tim->ARR / 200.0f * duty_cycle); - //__HAL_TIM_SET_COMPARE(timer->htim, pin.channel, raw_duty); - *(uint16_t*)((uint8_t*)(timer->tim) + timer.get_CCR_offset(pin.channel)) = raw_duty; + uint16_t raw_duty = (uint16_t)((float)timer->instance.tim->ARR / 200.0f * duty_cycle); + //__HAL_TIM_SET_COMPARE(timer->instance.hal_tim, pin.channel, raw_duty); + timer->template set_capture_compare(raw_duty); this->duty_cycle = duty_cycle; } @@ -143,10 +169,25 @@ class PWM { frequency = 2*frequency; } this->frequency = frequency; - timer.tim->ARR = (HAL_RCC_GetPCLK1Freq() * 2 / (timer.tim->PSC + 1)) / frequency; + timer->instance.tim->ARR = (HAL_RCC_GetPCLK1Freq() * 2 / (timer->instance.tim->PSC + 1)) / frequency; set_duty_cycle(duty_cycle); } + void configure(uint32_t frequency, float duty_cycle) + { + if(is_center_aligned) { + frequency = 2*frequency; + } + this->frequency = frequency; + timer->instance.tim->ARR = (HAL_RCC_GetPCLK1Freq() * 2 / (timer->instance.tim->PSC + 1)) / frequency; + + //set_duty_cycle(duty_cycle); + uint16_t raw_duty = (uint16_t)((float)timer->instance.tim->ARR / 200.0f * duty_cycle); + //__HAL_TIM_SET_COMPARE(timer->instance.hal_tim, pin.channel, raw_duty); + timer->template set_capture_compare(raw_duty); + this->duty_cycle = duty_cycle; + } + void set_dead_time(int64_t dead_time_ns) { TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; @@ -174,8 +215,12 @@ class PWM { sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; sBreakDeadTimeConfig.Break2Filter = 0; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; - HAL_TIMEx_ConfigBreakDeadTime(timer->htim, &sBreakDeadTimeConfig); - SET_BIT(timer->tim->BDTR, TIM_BDTR_MOE); + HAL_TIMEx_ConfigBreakDeadTime(timer->instance.hal_tim, &sBreakDeadTimeConfig); + + if constexpr(timer->is_break_instance) { + // Main Output Enable + SET_BIT(timer->tim->BDTR, TIM_BDTR_MOE); + } } }; } // namespace ST_LIB diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 71abc4f0..fc5c4472 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -31,38 +31,88 @@ struct TimerWrapper { TimerDomain::Instance& instance; TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} - static constexpr bool bits32timer = ( + static constexpr bool is_32bit_instance = ( dev.e.request == TimerRequest::GeneralPurpose32bit_2 || dev.e.request == TimerRequest::GeneralPurpose32bit_5 || dev.e.request == TimerRequest::GeneralPurpose32bit_23 || dev.e.request == TimerRequest::GeneralPurpose32bit_24 || dev.e.request == TimerRequest::Any32bit ); + /* supports break input */ + static constexpr bool is_break_instance = ( + dev.e.request == TimerRequest::Advanced_1 || + dev.e.request == TimerRequest::Advanced_8 || + dev.e.request == TimerRequest::GeneralPurpose_15 || + dev.e.request == TimerRequest::GeneralPurpose_16 || + dev.e.request == TimerRequest::GeneralPurpose_17 + ); + static constexpr bool is_slave_instance = ( + dev.e.request == TimerRequest::Advanced_1 || + dev.e.request == TimerRequest::GeneralPurpose32bit_2 || + dev.e.request == TimerRequest::GeneralPurpose_3 || + dev.e.request == TimerRequest::GeneralPurpose_4 || + dev.e.request == TimerRequest::GeneralPurpose32bit_5 || + dev.e.request == TimerRequest::Advanced_8 || + dev.e.request == TimerRequest::SlaveTimer_12 || + dev.e.request == TimerRequest::GeneralPurpose_15 || + dev.e.request == TimerRequest::GeneralPurpose32bit_23 || + dev.e.request == TimerRequest::GeneralPurpose32bit_24 + ); + static constexpr bool only_supports_upcounting = ( + dev.e.request == TimerRequest::Basic_6 || + dev.e.request == TimerRequest::Basic_7 || + dev.e.request == TimerRequest::SlaveTimer_12 || + dev.e.request == TimerRequest::SlaveTimer_13 || + dev.e.request == TimerRequest::SlaveTimer_14 || + dev.e.request == TimerRequest::GeneralPurpose_15 || + dev.e.request == TimerRequest::GeneralPurpose_16 || + dev.e.request == TimerRequest::GeneralPurpose_17 + ); - template - inline PWM get_pwm(uint8_t channel) { - static_assert(dev.e.pin_count > 0, "Need at least one pin to get a pwm"); - if constexpr(dev.e.pins[0].pin == pin.pin) { - static_assert(dev.e.pins[0].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); - return PWM(this, pin); - } - - static_assert(dev.e.pin_count > 1, "No pins passed to TimerWrapper are the same as the pins passed to get_pwm() [this method]"); - if constexpr(dev.e.pins[1].pin == pin.pin) { - static_assert(dev.e.pins[1].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); - return PWM(this, pin); - } + /* returns if the channel can be negated or not {See TimerDomain get_gpio_af()} */ + static consteval bool is_ccxn_instance(ST_LIB::TimerChannel ch) { + switch(dev.e.request) { + case TimerRequest::Advanced_1: + case TimerRequest::Advanced_8: + return (ch == TimerChannel::CHANNEL_1) || + (ch == TimerChannel::CHANNEL_2) || + (ch == TimerChannel::CHANNEL_3); - static_assert(dev.e.pin_count > 2, "No pins passed to TimerWrapper are the same as the pins passed to get_pwm() [this method]"); - if constexpr(dev.e.pins[2].pin == pin.pin) { - static_assert(dev.e.pins[2].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); - return PWM(this, pin); + case TimerRequest::GeneralPurpose_15: + case TimerRequest::GeneralPurpose_16: + case TimerRequest::GeneralPurpose_17: + return ch == TimerChannel::CHANNEL_1; + + default: + return false; } + return false; + } - static_assert(dev.e.pin_count == 4, "No pins passed to TimerWrapper are the same as the pins passed to get_pwm() [this method]"); - if constexpr(dev.e.pins[3].pin == pin.pin) { - static_assert(dev.e.pins[3].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); - return PWM(this, pin); + template + inline PWM get_pwm(uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCNPOLARITY_HIGH) { + static_assert(dev.e.pin_count > 0, "Need at least one pin to get a pwm"); + if constexpr(dev.e.pins[0].pin == pin.pin && dev.e.pins[0].channel == pin.channel) { + static_assert(dev.e.pins[0].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); + return PWM(this, polarity, negated_polarity); + } else { + static_assert(dev.e.pin_count > 1, "No pins passed to TimerWrapper are the same as the pins passed to get_pwm() [this method]"); + if constexpr(dev.e.pins[1].pin == pin.pin && dev.e.pins[1].channel == pin.channel) { + static_assert(dev.e.pins[1].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); + return PWM(this, polarity, negated_polarity); + } else { + static_assert(dev.e.pin_count > 2, "No pins passed to TimerWrapper are the same as the pins passed to get_pwm() [this method]"); + if constexpr(dev.e.pins[2].pin == pin.pin && dev.e.pins[2].channel == pin.channel) { + static_assert(dev.e.pins[2].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); + return PWM(this, polarity, negated_polarity); + } else { + static_assert(dev.e.pin_count == 4, "No pins passed to TimerWrapper are the same as the pins passed to get_pwm() [this method]"); + if constexpr(dev.e.pins[3].pin == pin.pin && dev.e.pins[3].channel == pin.channel) { + static_assert(dev.e.pins[3].af == TimerAF::PWM, "Pin must be configured in TimerWrapper as a PWM"); + return PWM(this, polarity, negated_polarity); + } + } + } } } @@ -137,61 +187,33 @@ struct TimerWrapper { return instance.tim; } - template + inline void set_prescaler(uint16_t psc) { + instance.tim->PSC = psc; + } + inline void configure32bit(void (*callback)(void*), void *callback_data, uint32_t period) { - static_assert(bits32timer, "Only timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); + static_assert(this->is_32bit_instance, "Only timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); - if constexpr (psc != 0) { - instance.tim->PSC = psc; - } instance.tim->ARR = period; TimerDomain::callbacks[instance.timer_idx] = callback; TimerDomain::callback_data[instance.timer_idx] = callback_data; this->counter_enable(); } - template inline void configure16bit(void (*callback)(void*), void *callback_data, uint16_t period) { - if constexpr (psc != 0) { - instance.tim->PSC = psc; - } instance.tim->ARR = period; TimerDomain::callbacks[instance.timer_idx] = callback; TimerDomain::callback_data[instance.timer_idx] = callback_data; this->counter_enable(); } - static consteval size_t get_CCR_offset(const ST_LIB::TimerChannel ch) { - switch(ch) { - case TimerChannel::CHANNEL_1: return offsetof(TIM_TypeDef, CCR1); - case TimerChannel::CHANNEL_2: return offsetof(TIM_TypeDef, CCR2); - case TimerChannel::CHANNEL_3: return offsetof(TIM_TypeDef, CCR3); - case TimerChannel::CHANNEL_4: return offsetof(TIM_TypeDef, CCR4); - case TimerChannel::CHANNEL_5: return offsetof(TIM_TypeDef, CCR5); - case TimerChannel::CHANNEL_6: return offsetof(TIM_TypeDef, CCR6); - - default: ST_LIB::compile_error("unreachable"); - return 0; - } - } - - // leftover from old TimerPeripheral, maybe this was useful? - inline uint16_t get_prescaler() { - return instance.tim->PSC; - } - inline uint32_t get_period() { - return instance.tim->ARR; - } - /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ template - inline void set_mode(void) { + inline void set_counting_mode(void) { constexpr uint8_t reqint = static_cast(dev.e.request); - static_assert(!(reqint == 1 || reqint == 8 || - reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || - reqint == 3 || reqint == 4), + static_assert(!this->only_supports_upcounting, "Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); if constexpr (mode == TimerDomain::CountingMode::UP) { @@ -208,6 +230,193 @@ struct TimerWrapper { MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); } } + + /////////////////////////////////////// + + // TODO: should this be inline? + template + inline void config_output_compare_channel(const TIM_OC_InitTypeDef *OC_Config) + { + uint32_t tmpccmrx; + uint32_t tmpccer; + uint32_t tmpcr2; + + tmpccer = instance.tim->CCER; + + tmpcr2 = instance.tim->CR2; + + if constexpr(ch == TimerChannel::CHANNEL_1 || ch == TimerChannel::CHANNEL_2) { + tmpccmrx = instance.tim->CCMR1; + } else if constexpr(ch == TimerChannel::CHANNEL_3 || ch == TimerChannel::CHANNEL_4) { + tmpccmrx = instance.tim->CCMR2; + } else if constexpr(ch == TimerChannel::CHANNEL_5 || ch == TimerChannel::CHANNEL_6) { + tmpccmrx = instance.tim->CCMR3; + } + + if constexpr(ch == TimerChannel::CHANNEL_1) { + CLEAR_BIT(instance.tim->CCER, TIM_CCER_CC1E); + + CLEAR_BIT(tmpccmrx, TIM_CCMR1_OC1M); + CLEAR_BIT(tmpccmrx, TIM_CCMR1_CC1S); + + SET_BIT(tmpccmrx, OC_Config->OCMode); + CLEAR_BIT(tmpccer, TIM_CCER_CC1P); + SET_BIT(tmpccer, OC_Config->OCPolarity); + } else if constexpr(ch == TimerChannel::CHANNEL_2) { + CLEAR_BIT(instance.tim->CCER, TIM_CCER_CC2E); + + CLEAR_BIT(tmpccmrx, TIM_CCMR1_OC2M); + CLEAR_BIT(tmpccmrx, TIM_CCMR1_CC2S); + + SET_BIT(tmpccmrx, OC_Config->OCMode << 8U); + CLEAR_BIT(tmpccer, TIM_CCER_CC2P); + SET_BIT(tmpccer, OC_Config->OCPolarity << 4U); + } else if constexpr(ch == TimerChannel::CHANNEL_3) { + CLEAR_BIT(instance.tim->CCER, TIM_CCER_CC3E); + + CLEAR_BIT(tmpccmrx, TIM_CCMR2_OC3M); + CLEAR_BIT(tmpccmrx, TIM_CCMR2_CC3S); + + SET_BIT(tmpccmrx, OC_Config->OCMode); + CLEAR_BIT(tmpccer, TIM_CCER_CC3P); + SET_BIT(tmpccer, OC_Config->OCPolarity << 8U); + } else if constexpr(ch == TimerChannel::CHANNEL_4) { + CLEAR_BIT(instance.tim->CCER, TIM_CCER_CC4E); + + CLEAR_BIT(tmpccmrx, TIM_CCMR2_OC4M); + CLEAR_BIT(tmpccmrx, TIM_CCMR2_CC4S); + + SET_BIT(tmpccmrx, OC_Config->OCMode); + CLEAR_BIT(tmpccer, TIM_CCER_CC4P); + SET_BIT(tmpccer, OC_Config->OCPolarity << 12U); + } else if constexpr(ch == TimerChannel::CHANNEL_5) { + CLEAR_BIT(instance.tim->CCER, TIM_CCER_CC5E); + + CLEAR_BIT(tmpccmrx, TIM_CCMR3_OC5M); + + SET_BIT(tmpccmrx, OC_Config->OCMode); + CLEAR_BIT(tmpccer, TIM_CCER_CC5P); + SET_BIT(tmpccer, OC_Config->OCPolarity << 16U); + } else if constexpr(ch == TimerChannel::CHANNEL_6) { + CLEAR_BIT(instance.tim->CCER, TIM_CCER_CC6E); + + CLEAR_BIT(tmpccmrx, TIM_CCMR3_OC6M); + + SET_BIT(tmpccmrx, OC_Config->OCMode); + CLEAR_BIT(tmpccer, TIM_CCER_CC6P); + SET_BIT(tmpccer, OC_Config->OCPolarity << 20U); + } + + if(this->is_ccxn_instance(ch)) { + assert_param(IS_TIM_OCN_POLARITY(OC_Config->OCNPolarity)); + + if constexpr(ch == TimerChannel::CHANNEL_1) { + CLEAR_BIT(tmpccer, TIM_CCER_CC1NP); + SET_BIT(tmpccer, OC_Config->OCNPolarity); + CLEAR_BIT(tmpccer, TIM_CCER_CC1NE); + } else if constexpr(ch == TimerChannel::CHANNEL_2) { + CLEAR_BIT(tmpccer, TIM_CCER_CC2NP); + SET_BIT(tmpccer, OC_Config->OCNPolarity << 4U); + CLEAR_BIT(tmpccer, TIM_CCER_CC2NE); + } else if constexpr(ch == TimerChannel::CHANNEL_3) { + CLEAR_BIT(tmpccer, TIM_CCER_CC3NP); + SET_BIT(tmpccer, OC_Config->OCNPolarity << 8U); + CLEAR_BIT(tmpccer, TIM_CCER_CC3NE); + } + } + + if(this->is_break_instance) { + assert_param(IS_TIM_OCNIDLE_STATE(OC_Config->OCNIdleState)); + assert_param(IS_TIM_OCIDLE_STATE(OC_Config->OCIdleState)); + + if constexpr(ch == TimerChannel::CHANNEL_1) { + CLEAR_BIT(tmpcr2, TIM_CR2_OIS1); + CLEAR_BIT(tmpcr2, TIM_CR2_OIS1N); + SET_BIT(tmpcr2, OC_Config->OCNIdleState); + SET_BIT(tmpcr2, OC_Config->OCIdleState); + } else if constexpr(ch == TimerChannel::CHANNEL_2) { + CLEAR_BIT(tmpcr2, TIM_CR2_OIS2); + CLEAR_BIT(tmpcr2, TIM_CR2_OIS2N); + SET_BIT(tmpcr2, OC_Config->OCNIdleState << 2U); + SET_BIT(tmpcr2, OC_Config->OCIdleState << 2U); + } else if constexpr(ch == TimerChannel::CHANNEL_3) { + CLEAR_BIT(tmpcr2, TIM_CR2_OIS3); + CLEAR_BIT(tmpcr2, TIM_CR2_OIS3N); + SET_BIT(tmpcr2, OC_Config->OCNIdleState << 4U); + SET_BIT(tmpcr2, OC_Config->OCIdleState << 4U); + } else if constexpr(ch == TimerChannel::CHANNEL_4) { + CLEAR_BIT(tmpcr2, TIM_CR2_OIS4); + SET_BIT(tmpcr2, OC_Config->OCIdleState << 6U); + } else if constexpr(ch == TimerChannel::CHANNEL_5) { + CLEAR_BIT(tmpcr2, TIM_CR2_OIS5); + SET_BIT(tmpcr2, OC_Config->OCIdleState << 8U); + } else if constexpr(ch == TimerChannel::CHANNEL_6) { + CLEAR_BIT(tmpcr2, TIM_CR2_OIS6); + SET_BIT(tmpcr2, OC_Config->OCIdleState << 10U); + } + } + + instance.tim->CR2 = tmpcr2; + if constexpr(ch == TimerChannel::CHANNEL_1 || ch == TimerChannel::CHANNEL_2) { + instance.tim->CCMR1 = tmpccmrx; + } else if constexpr(ch == TimerChannel::CHANNEL_3 || ch == TimerChannel::CHANNEL_4) { + instance.tim->CCMR2 = tmpccmrx; + } else if constexpr(ch == TimerChannel::CHANNEL_5 || ch == TimerChannel::CHANNEL_6) { + instance.tim->CCMR3 = tmpccmrx; + } + + if constexpr(ch == TimerChannel::CHANNEL_1) instance.tim->CCR1 = OC_Config->Pulse; + else if constexpr(ch == TimerChannel::CHANNEL_2) instance.tim->CCR2 = OC_Config->Pulse; + else if constexpr(ch == TimerChannel::CHANNEL_3) instance.tim->CCR3 = OC_Config->Pulse; + else if constexpr(ch == TimerChannel::CHANNEL_4) instance.tim->CCR4 = OC_Config->Pulse; + else if constexpr(ch == TimerChannel::CHANNEL_5) instance.tim->CCR5 = OC_Config->Pulse; + else if constexpr(ch == TimerChannel::CHANNEL_6) instance.tim->CCR6 = OC_Config->Pulse; + + instance.tim->CCER = tmpccer; + } + + template + inline void set_output_compare_preload_enable() + { + if constexpr (ch == TimerChannel::CHANNEL_1) { + SET_BIT(instance.tim->CCMR1, TIM_CCMR1_OC1PE); + } else if constexpr(ch == TimerChannel::CHANNEL_2) { + SET_BIT(instance.tim->CCMR1, TIM_CCMR1_OC2PE); + } else if constexpr(ch == TimerChannel::CHANNEL_3) { + SET_BIT(instance.tim->CCMR2, TIM_CCMR2_OC3PE); + } else if constexpr(ch == TimerChannel::CHANNEL_4) { + SET_BIT(instance.tim->CCMR2, TIM_CCMR2_OC4PE); + } else if constexpr(ch == TimerChannel::CHANNEL_5) { + SET_BIT(instance.tim->CCMR3, TIM_CCMR3_OC5PE); + } else if constexpr(ch == TimerChannel::CHANNEL_6) { + SET_BIT(instance.tim->CCMR3, TIM_CCMR3_OC6PE); + } else ST_LIB::compile_error("Unknown timer channel, there are only 6 channels [1..6]"); + } + + template + inline void set_capture_compare(uint16_t val) { + if constexpr (ch == TimerChannel::CHANNEL_1) { + instance.tim->CCR1 = val; + } else if constexpr(ch == TimerChannel::CHANNEL_2) { + instance.tim->CCR2 = val; + } else if constexpr(ch == TimerChannel::CHANNEL_3) { + instance.tim->CCR3 = val; + } else if constexpr(ch == TimerChannel::CHANNEL_4) { + instance.tim->CCR4 = val; + } else if constexpr(ch == TimerChannel::CHANNEL_5) { + instance.tim->CCR5 = val; + } else if constexpr(ch == TimerChannel::CHANNEL_6) { + instance.tim->CCR6 = val; + } else ST_LIB::compile_error("Unknown timer channel, there are only 6 channels [1..6]"); + } + + // leftover from old TimerPeripheral, maybe this was useful? + inline uint16_t get_prescaler() { + return instance.tim->PSC; + } + inline uint32_t get_period() { + return instance.tim->ARR; + } }; } // namespace ST_LIB diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index e6901553..1aa23495 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -25,7 +25,7 @@ class TimerRegister : public RegisterBase { static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); -struct TIM_TypeDef{ +struct TIM_TypeDef { TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): // PSC(*this), callback{irq_handler}, irq_n{irq_n} callback{irq_handler}, irq_n{irq_n} diff --git a/Tests/Time/timer_wrapper_test.cpp b/Tests/Time/timer_wrapper_test.cpp index 681f7a90..88c8b116 100644 --- a/Tests/Time/timer_wrapper_test.cpp +++ b/Tests/Time/timer_wrapper_test.cpp @@ -107,7 +107,8 @@ TEST_F(TimerWrapperTests, ConfigureTimer) { #define PRESCALER_VAL 200 #define PERIOD 1000 - tim1.configure16bit(callback, 0, PERIOD); + tim1.set_prescaler(PRESCALER_VAL); + tim1.configure16bit(callback, 0, PERIOD); EXPECT_EQ(TIM1_BASE->PSC, PRESCALER_VAL); /* set prescaler */ EXPECT_EQ(TIM1_BASE->ARR, PERIOD); /* set period */ EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_CEN, TIM_CR1_CEN); /* set counter enable */