From 2a537abebfc28fadb62065c9b6738679d7bf9244 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 09:43:31 +0100 Subject: [PATCH 001/281] Add initial implementation of scheduler --- Inc/HALAL/Services/Time/Scheduler.hpp | 96 ++++++++ Src/HALAL/Services/Time/Scheduler.cpp | 309 ++++++++++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 Inc/HALAL/Services/Time/Scheduler.hpp create mode 100644 Src/HALAL/Services/Time/Scheduler.cpp diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp new file mode 100644 index 000000000..e300094cf --- /dev/null +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -0,0 +1,96 @@ +/* + * Scheduler.hpp + * + * Created on: 17 nov. 2025 + * Author: Victor (coauthor Stephan) + */ +#pragma once + +#include "stm32h7xx_ll_tim.h" + +#include +#include +#include + +/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto + * Cambiar el SCHEDULER_TIMER_IDX si es mejor usar otro timer que no sea TIM2 + */ +#ifndef SCHEDULER_TIMER_IDX +# define SCHEDULER_TIMER_IDX 2 +#endif + +#define glue_(a,b) a ## b +#define glue(a,b) glue_(a,b) +#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) + +// Used to reserve a TimerPeripheral +#include "stm32h7xx_hal_tim.h" +#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) +extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; + +struct Scheduler { + using callback_t = void (*)(); + static constexpr uint32_t INVALID_ID = 0xFFu; + + static void start(); + static void update(); + static inline uint64_t get_global_tick(); + + static inline uint8_t register_task(uint32_t period_us, callback_t func) { + if(period_us == 0) [[unlikely]] period_us = 1; + return register_task(period_us, func, true); + } + static bool unregister_task(uint8_t id); + + static inline uint8_t set_timeout(uint32_t microseconds, callback_t func) { + if(microseconds == 0) [[unlikely]] microseconds = 1; + return register_task(microseconds, func, false); + } + static inline void cancel_timeout(uint8_t id) { unregister_task(id); } + + // static void global_timer_callback(); + + // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise + static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + static void on_timer_update(); + +private: + struct Task { + uint64_t next_fire_us{0}; + callback_t callback{}; + uint32_t period_us{0}; + bool repeating{false}; + }; + + static constexpr std::size_t kMaxTasks = 16; + static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); + static constexpr uint32_t kBaseClockHz = 1'000'000u; + + static std::array tasks_; + static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); + static uint64_t sorted_task_ids_; + + static std::size_t active_task_count_; + static uint32_t ready_bitmap_; + static uint32_t used_bitmap_; + static uint64_t global_tick_us_; + static uint64_t long_wait_remaining_us_; + static uint64_t current_interval_us_; + + static inline uint8_t allocate_slot(); + static inline void release_slot(uint8_t id); + static void insert_sorted(uint8_t id); + static void remove_sorted(uint8_t id); + static void schedule_next_interval(); + static inline void configure_timer_for_interval(uint64_t microseconds); + static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); + + // helpers + static inline uint8_t get_at(std::size_t logical); + static inline void set_at(std::size_t logical, uint8_t id); + static inline void pop_front(); + static inline uint8_t front_id(); + + static inline void global_timer_disable(); + static inline void global_timer_enable(); +}; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp new file mode 100644 index 000000000..0e1faf054 --- /dev/null +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -0,0 +1,309 @@ +/* + * Scheduler.hpp + * + * Created on: 17 nov. 2025 + * Author: Victor (coauthor Stephan) + */ +#include "HALAL/Services/Time/Scheduler.hpp" + +// This is needed to register a TimerPeripheral +#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" + +#include +#include + +/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ +#define SCHEDULER_RCC_TIMER_ENABLE glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) +#define SCHEDULER_GLOBAL_TIMER_IRQn glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) +#define SCHEDULER_GLOBAL_TIMER_CALLBACK() extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) +#define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) + +/* bit field insert + * (internally) mask = ((1UL << width) - 1) << pos + * dest = (dest & ~mask) | (source & mask) + * With the condition that pos and width are immediate values + * ref: https://developer.arm.com/documentation/dui0646/c/The-Cortex-M7-Instruction-Set/Bit-field-instructions/BFC-and-BFI + */ +#define BFI(dest, source, pos, width) \ + __asm__( \ + "bfi %0, %1, %2, %3" \ + : "+r" (dest) \ + : "r" (source), "i" (pos), "i" (width) \ + ) + +namespace { +constexpr uint64_t kMaxIntervalUs = + static_cast(std::numeric_limits::max()) + 1ULL; +} + +std::array Scheduler::tasks_{}; +uint64_t Scheduler::sorted_task_ids_ = 0; +std::size_t Scheduler::active_task_count_{0}; + +uint32_t Scheduler::ready_bitmap_{0}; +uint32_t Scheduler::used_bitmap_{0}; +uint64_t Scheduler::global_tick_us_{0}; +uint64_t Scheduler::long_wait_remaining_us_{0}; +uint64_t Scheduler::current_interval_us_{0}; + +inline uint8_t Scheduler::get_at(std::size_t idx) { + uint32_t shift = idx*4; + return (sorted_task_ids_ & (0x0F << shift)) >> shift; +} +inline void Scheduler::set_at(std::size_t idx, uint8_t id) { + uint32_t shift = idx*4; + uint64_t clearmask = ~(0xFF << shift); + Scheduler::sorted_task_ids_ = (sorted_task_ids_ & clearmask) | (id << shift); + // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though +} +inline uint8_t Scheduler::front_id() { + return Scheduler::get_at(0); +} +inline void Scheduler::pop_front() { + // O(1) remove of logical index 0 + Scheduler::active_task_count_--; + Scheduler::sorted_task_ids_ <<= 4; +} + +// ---------------------------- + +inline void Scheduler::global_timer_disable() { + LL_TIM_DisableCounter(Scheduler_global_timer); + //Scheduler_global_timer->CR1 &= ~TIM_CR1_CEN; +} +inline void Scheduler::global_timer_enable() { + LL_TIM_EnableCounter(Scheduler_global_timer); + //Scheduler_global_timer->CR1 |= TIM_CR1_CEN; +} + +// ---------------------------- + +void Scheduler::start() { + static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); + + const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; + static_assert(prescaler < 0xFFFF'FFFF, "Prescaler is 16 bit, so it must be in that range"); + + // Register a TimerPeripheral so it's not used anywhere else + // hopefully we can move to something better than TimerPeripheral + TimerPeripheral::InitData init_data(TimerPeripheral::BASE); + TimerPeripheral perif_reserve(&SCHEDULER_HAL_TIM, std::move(init_data), (std::string)"timer2"); + + RCC->APB1LENR |= SCHEDULER_RCC_TIMER_ENABLE; + Scheduler_global_timer->PSC = (uint16_t)prescaler; + Scheduler_global_timer->ARR = 0; + Scheduler_global_timer->DIER |= LL_TIM_DIER_UIE; + Scheduler_global_timer->CR1 = LL_TIM_CLOCKDIVISION_DIV1 | (Scheduler_global_timer->CR1 & ~TIM_CR1_CKD); + // I think this should be cleared at startup. TODO: Look it up in ref manual + // LL_TIM_DisableExternalClock(Scheduler_global_timer); + // |-> does this: Scheduler_global_timer->SMCR &= ~TIM_SMCR_ECE; /* Disable external clock */ + + active_task_count_ = 0; + Scheduler_global_timer->CNT = 0; /* Clear counter value */ + + NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); + Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ + // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() + // Scheduler::global_timer_enable(); + + Scheduler::schedule_next_interval(); +} + +SCHEDULER_GLOBAL_TIMER_CALLBACK() { + Scheduler_global_timer->SR &= ~TIM_SR_UIF; + Scheduler::on_timer_update(); +} + +void Scheduler::update() { + while(ready_bitmap_ != 0u) { + uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); + ready_bitmap_ &= ~(1u << bit_index); // Clear the bit + Task& task = tasks_[bit_index]; + task.callback(); + if (!task.repeating) [[unlikely]] { + release_slot(static_cast(bit_index)); + } + } +} + +inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } + +// void Scheduler::global_timer_callback() { on_timer_update(); } + +inline uint8_t Scheduler::allocate_slot() { + int idx = __builtin_clz(Scheduler::ready_bitmap_); + if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] + return static_cast(Scheduler::INVALID_ID); + return static_cast(idx); +} + +inline void Scheduler::release_slot(uint8_t id) { + // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert + if(id >= kMaxTasks) return; + tasks_[id] = Task{}; + uint32_t clearmask = ~(1u << id); + ready_bitmap_ &= clearmask; + used_bitmap_ &= clearmask; +} + +void Scheduler::insert_sorted(uint8_t id) { + Task& task = tasks_[id]; + + // binary search on logical range [0, active_task_count_) + std::size_t left = 0; + std::size_t right = active_task_count_; + while (left < right) { + std::size_t mid = left + ((right - left) / 2); + const Task& mid_task = tasks_[Scheduler::get_at(mid)]; + if (mid_task.next_fire_us <= task.next_fire_us) { + left = mid + 1; + } else { + right = mid; + } + } + const std::size_t pos = left; + + uint32_t lo = (uint32_t)sorted_task_ids_; + uint32_t hi = (uint32_t)(sorted_task_ids_ >> 32); + + uint32_t shift = (pos & 7) << 2; + uint32_t id_shifted = id << shift; + + uint32_t mask = (1UL << shift) - 1; + uint32_t inv_mask = ~mask; //Hole mask + + //Calculate both posibilities + uint32_t lo_modified = ((lo & inv_mask) << 4) | (lo & mask) | id_shifted; + uint32_t hi_modified = ((hi & inv_mask) << 4) | (hi & mask) | id_shifted; + + uint32_t hi_spilled = (hi << 4) | (lo >> 28); + + if (pos >= 8) { //this can be done without branching + hi = hi_modified; + // lo remains unchanged + } else { + hi = hi_spilled; + lo = lo_modified; + } + + sorted_task_ids_ = ((uint64_t)hi << 32) | lo; + ++active_task_count_; +} + +void Scheduler::remove_sorted(uint8_t id) { + uint64_t nibble_lsb = 0x1111'1111'1111'1111ULL; + + // pattern = nibble_lsb * id (para obtener id en cada nibble) + uint32_t pattern_32 = id + (id << 4); + pattern_32 = pattern_32 + (pattern_32 << 8); + pattern_32 = pattern_32 + (pattern_32 << 16); + uint64_t pattern = pattern_32; + BFI(((uint32_t*)&pattern)[1], pattern, 0, 32); + + // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids + uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; + + //https://stackoverflow.com/questions/79058066/finding-position-of-zero-nibble-in-64-bits + //https://stackoverflow.com/questions/59480527/fast-lookup-of-a-null-nibble-in-a-64-bit-unsigned + uint64_t nibble_msb = 0x8888'8888'8888'8888ULL; + uint64_t matches = (diff - nibble_lsb) & (~diff & nibble_msb); + + if(matches == 0) [[unlikely]] return; // not found + + uint32_t pos_msb = __builtin_ctzll(matches); + uint32_t pos_lsb = pos_msb - 3; + + // convert pos_lsb to 0x0..0_FFF_0..0 + uint64_t mask = (1ULL << pos_lsb) - 1; + + // Remove element (lower part | higher pushing nibble out of mask) + Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); + Scheduler::active_task_count_--; +} + +void Scheduler::schedule_next_interval() { + if (active_task_count_ == 0) [[unlikely]] { + Scheduler::global_timer_disable(); + current_interval_us_ = 0; + long_wait_remaining_us_ = 0; + return; + } + + Scheduler::global_timer_enable(); + uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] + Task& next_task = tasks_[next_id]; + uint64_t delta = (next_task.next_fire_us > global_tick_us_) + ? (next_task.next_fire_us - global_tick_us_ + 1ULL) : 1ULL; // +1 to ensure we don't miss, means loss in accuracy + + //TODO: Adding 1 accumulates drift over time analyze if acceptable, it can be solved by adding an extra if + + if (delta > kMaxIntervalUs) [[unlikely]] { + current_interval_us_ = kMaxIntervalUs; + long_wait_remaining_us_ = delta - kMaxIntervalUs; + } else { + current_interval_us_ = delta; + long_wait_remaining_us_ = 0; + } + + configure_timer_for_interval(current_interval_us_); +} + +inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { + // NOTE(vic): disabling the timer _might_ be necessary to prevent the timer from firing in the middle of configuring it, highly unlikely since it has a period of at least 1 microsecond + const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; + Scheduler_global_timer->PSC = prescaler; + Scheduler_global_timer->ARR = static_cast(microseconds - 1u); + Scheduler_global_timer->CNT = 0; + Scheduler::global_timer_enable(); +} + +void Scheduler::on_timer_update() { + global_tick_us_ += current_interval_us_; + + if (long_wait_remaining_us_ > 0) [[unlikely]] { + uint64_t next_chunk = std::min(long_wait_remaining_us_, kMaxIntervalUs); + long_wait_remaining_us_ -= next_chunk; + current_interval_us_ = next_chunk; + configure_timer_for_interval(current_interval_us_); + return; + } + + uint8_t candidate_id = Scheduler::front_id(); + Task& task = tasks_[candidate_id]; + pop_front(); + ready_bitmap_ |= (1u << candidate_id); // mark task as ready + + if (task.repeating) [[likely]] { + task.next_fire_us = global_tick_us_ + task.period_us; + insert_sorted(candidate_id); + } + + schedule_next_interval(); +} + +uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repeating) { + if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + + uint8_t slot = allocate_slot(); + if(slot == Scheduler::INVALID_ID) return slot; + + Task& task = tasks_[slot]; + task.callback = func; + task.period_us = period_us; + task.repeating = repeating; + task.next_fire_us = global_tick_us_ + period_us; + + insert_sorted(slot); + schedule_next_interval(); + return slot; +} + +bool Scheduler::unregister_task(uint8_t id) { + if (id >= kMaxTasks) return false; + if (!(used_bitmap_ & (1UL << id))) return false; + + remove_sorted(id); + release_slot(id); + schedule_next_interval(); + return true; +} From 3f72fbe7a47e53725cd2530f6d8bb41456026e8a Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:02:02 +0100 Subject: [PATCH 002/281] Try to fix -Wuninitialized warning --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 0e1faf054..6224b4cba 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -198,7 +198,7 @@ void Scheduler::remove_sorted(uint8_t id) { pattern_32 = pattern_32 + (pattern_32 << 8); pattern_32 = pattern_32 + (pattern_32 << 16); uint64_t pattern = pattern_32; - BFI(((uint32_t*)&pattern)[1], pattern, 0, 32); + BFI(((uint32_t*)&pattern)[1], pattern_32, 0, 32); // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; From 8620d889a940c94b6faa36964d9fc0128389e32e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:04:53 +0100 Subject: [PATCH 003/281] Try to remove Wuninitialized warning temporarily --- Src/HALAL/Services/Time/Scheduler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 6224b4cba..a8684f536 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -193,6 +193,9 @@ void Scheduler::insert_sorted(uint8_t id) { void Scheduler::remove_sorted(uint8_t id) { uint64_t nibble_lsb = 0x1111'1111'1111'1111ULL; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + // pattern = nibble_lsb * id (para obtener id en cada nibble) uint32_t pattern_32 = id + (id << 4); pattern_32 = pattern_32 + (pattern_32 << 8); @@ -200,6 +203,8 @@ void Scheduler::remove_sorted(uint8_t id) { uint64_t pattern = pattern_32; BFI(((uint32_t*)&pattern)[1], pattern_32, 0, 32); +#pragma GCC diagnostic pop + // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; From 87404bd7281de0cf84e507b62bd6d1a75500102b Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:27:25 +0100 Subject: [PATCH 004/281] Remove unnecessary clear of task element --- Src/HALAL/Services/Time/Scheduler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index a8684f536..aad615cb1 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -140,7 +140,6 @@ inline uint8_t Scheduler::allocate_slot() { inline void Scheduler::release_slot(uint8_t id) { // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert if(id >= kMaxTasks) return; - tasks_[id] = Task{}; uint32_t clearmask = ~(1u << id); ready_bitmap_ &= clearmask; used_bitmap_ &= clearmask; From 7ea80c72d93b68c1ac987367722d999e75ae9c50 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:41:29 +0100 Subject: [PATCH 005/281] fix: Readability and todo for validation --- Src/HALAL/Services/Time/Scheduler.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index aad615cb1..1167fcfab 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -13,9 +13,13 @@ #include /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ -#define SCHEDULER_RCC_TIMER_ENABLE glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) -#define SCHEDULER_GLOBAL_TIMER_IRQn glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) -#define SCHEDULER_GLOBAL_TIMER_CALLBACK() extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) +#define SCHEDULER_RCC_TIMER_ENABLE \ + glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) +#define SCHEDULER_GLOBAL_TIMER_IRQn \ + glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) +#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ + extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) + #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) /* bit field insert @@ -254,8 +258,7 @@ void Scheduler::schedule_next_interval() { inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { // NOTE(vic): disabling the timer _might_ be necessary to prevent the timer from firing in the middle of configuring it, highly unlikely since it has a period of at least 1 microsecond - const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; - Scheduler_global_timer->PSC = prescaler; + // TODO(vic): Validation: check arr is set correctly here: https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#pullrequestreview-3529132356 Scheduler_global_timer->ARR = static_cast(microseconds - 1u); Scheduler_global_timer->CNT = 0; Scheduler::global_timer_enable(); From ed50013b3f7de10c0d17ec3d4a4ae50e7c2c893c Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 12:15:29 +0100 Subject: [PATCH 006/281] fix: allocate_slot --- Src/HALAL/Services/Time/Scheduler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 1167fcfab..98400893d 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -135,7 +135,11 @@ inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } // void Scheduler::global_timer_callback() { on_timer_update(); } inline uint8_t Scheduler::allocate_slot() { - int idx = __builtin_clz(Scheduler::ready_bitmap_); + /* https://developer.arm.com/documentation/dui0204/j/arm-and-thumb-instructions/general-data-processing-instructions/clz + * clz(0) = 32 -> 32 - clz(0) = 0 + * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks + */ + uint32_t idx = 32 - __builtin_clz(Scheduler::used_bitmap_); if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); return static_cast(idx); From 4f6bbac18231409c2957ca72c900865e80c07c06 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 12:36:56 +0100 Subject: [PATCH 007/281] Add explenation of sorted_task_ids_, static_assert for the bitmaps --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 ++ Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index e300094cf..9b3643a17 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -68,9 +68,11 @@ struct Scheduler { static std::array tasks_; static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); + /* sorted_task_ids_ is a sorted queue with 4bits for each id in the scheduler's current ids */ static uint64_t sorted_task_ids_; static std::size_t active_task_count_; + static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); static uint32_t ready_bitmap_; static uint32_t used_bitmap_; static uint64_t global_tick_us_; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 98400893d..9cda60689 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -139,7 +139,7 @@ inline uint8_t Scheduler::allocate_slot() { * clz(0) = 32 -> 32 - clz(0) = 0 * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks */ - uint32_t idx = 32 - __builtin_clz(Scheduler::used_bitmap_); + uint32_t idx = 32 - __builtin_clz(~Scheduler::used_bitmap_); if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); return static_cast(idx); From 4323671779d00685558646864e3db3872f2cf721 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 12:44:10 +0100 Subject: [PATCH 008/281] Remove long_wait_remaining_us_ --- Inc/HALAL/Services/Time/Scheduler.hpp | 1 - Src/HALAL/Services/Time/Scheduler.cpp | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 9b3643a17..0951ca96b 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -76,7 +76,6 @@ struct Scheduler { static uint32_t ready_bitmap_; static uint32_t used_bitmap_; static uint64_t global_tick_us_; - static uint64_t long_wait_remaining_us_; static uint64_t current_interval_us_; static inline uint8_t allocate_slot(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9cda60689..20b77d734 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -47,7 +47,6 @@ std::size_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::used_bitmap_{0}; uint64_t Scheduler::global_tick_us_{0}; -uint64_t Scheduler::long_wait_remaining_us_{0}; uint64_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(std::size_t idx) { @@ -237,7 +236,6 @@ void Scheduler::schedule_next_interval() { if (active_task_count_ == 0) [[unlikely]] { Scheduler::global_timer_disable(); current_interval_us_ = 0; - long_wait_remaining_us_ = 0; return; } @@ -251,10 +249,8 @@ void Scheduler::schedule_next_interval() { if (delta > kMaxIntervalUs) [[unlikely]] { current_interval_us_ = kMaxIntervalUs; - long_wait_remaining_us_ = delta - kMaxIntervalUs; } else { current_interval_us_ = delta; - long_wait_remaining_us_ = 0; } configure_timer_for_interval(current_interval_us_); @@ -271,14 +267,6 @@ inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { void Scheduler::on_timer_update() { global_tick_us_ += current_interval_us_; - if (long_wait_remaining_us_ > 0) [[unlikely]] { - uint64_t next_chunk = std::min(long_wait_remaining_us_, kMaxIntervalUs); - long_wait_remaining_us_ -= next_chunk; - current_interval_us_ = next_chunk; - configure_timer_for_interval(current_interval_us_); - return; - } - uint8_t candidate_id = Scheduler::front_id(); Task& task = tasks_[candidate_id]; pop_front(); From a10df84db8ef444ffcd208ee8962b2acba565c9e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:45:38 +0100 Subject: [PATCH 009/281] fix: better get_at --- Inc/HALAL/Services/Time/Scheduler.hpp | 4 ++-- Src/HALAL/Services/Time/Scheduler.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 0951ca96b..d080bb181 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -87,8 +87,8 @@ struct Scheduler { static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); // helpers - static inline uint8_t get_at(std::size_t logical); - static inline void set_at(std::size_t logical, uint8_t id); + static inline uint8_t get_at(uint8_t idx); + static inline void set_at(uint8_t idx, uint8_t id); static inline void pop_front(); static inline uint8_t front_id(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 20b77d734..54beea194 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -49,11 +49,12 @@ uint32_t Scheduler::used_bitmap_{0}; uint64_t Scheduler::global_tick_us_{0}; uint64_t Scheduler::current_interval_us_{0}; -inline uint8_t Scheduler::get_at(std::size_t idx) { - uint32_t shift = idx*4; - return (sorted_task_ids_ & (0x0F << shift)) >> shift; +inline uint8_t Scheduler::get_at(uint8_t idx) { + int word_idx = idx > 7; + uint32_t shift = (idx & 7) << 2; + return (((uint32_t*)sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; } -inline void Scheduler::set_at(std::size_t idx, uint8_t id) { +inline void Scheduler::set_at(uint8_t idx, uint8_t id) { uint32_t shift = idx*4; uint64_t clearmask = ~(0xFF << shift); Scheduler::sorted_task_ids_ = (sorted_task_ids_ & clearmask) | (id << shift); From 023446394bc8038b5ac853f132ecc0ccf2d8e5e0 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:46:51 +0100 Subject: [PATCH 010/281] fix: better front_id Compiler would've probably optimized it but it's better to make it explicit --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 54beea194..9fda2ae1f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -61,7 +61,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return Scheduler::get_at(0); + return ((uint32_t*)sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From a7cad0611d3b2fb3c7c2161141ebe32f6d4c542c Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:51:12 +0100 Subject: [PATCH 011/281] fix: endianness in pop_front --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9fda2ae1f..72a91ecca 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -66,7 +66,7 @@ inline uint8_t Scheduler::front_id() { inline void Scheduler::pop_front() { // O(1) remove of logical index 0 Scheduler::active_task_count_--; - Scheduler::sorted_task_ids_ <<= 4; + Scheduler::sorted_task_ids_ >>= 4; } // ---------------------------- From db13d89c40c8f6509992f3bf69821cc364baa5e6 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:56:27 +0100 Subject: [PATCH 012/281] Added unlikely to release_slot conditional --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 72a91ecca..57856ebfd 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -147,7 +147,7 @@ inline uint8_t Scheduler::allocate_slot() { inline void Scheduler::release_slot(uint8_t id) { // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert - if(id >= kMaxTasks) return; + if(id >= kMaxTasks) [[unlikely]] return; uint32_t clearmask = ~(1u << id); ready_bitmap_ &= clearmask; used_bitmap_ &= clearmask; From 022578a703cb6fc02e9121d9618d7e21d8903d47 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:03:16 +0100 Subject: [PATCH 013/281] fix: Correct comment explenation --- Src/HALAL/Services/Time/Scheduler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 57856ebfd..5a25321e4 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -222,10 +222,12 @@ void Scheduler::remove_sorted(uint8_t id) { if(matches == 0) [[unlikely]] return; // not found + /* split the bm in two 0x0000...FFFFFF where removal index is placed + * then invert to keep both sides that surround the discarded index + */ uint32_t pos_msb = __builtin_ctzll(matches); uint32_t pos_lsb = pos_msb - 3; - // convert pos_lsb to 0x0..0_FFF_0..0 uint64_t mask = (1ULL << pos_lsb) - 1; // Remove element (lower part | higher pushing nibble out of mask) From 6addcb2d6b52f51b291c7da1d2756e5eb7fc2f5e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:09:18 +0100 Subject: [PATCH 014/281] No bit field insert, it annoyed me --- Src/HALAL/Services/Time/Scheduler.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 5a25321e4..63431ba85 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -22,19 +22,6 @@ #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) -/* bit field insert - * (internally) mask = ((1UL << width) - 1) << pos - * dest = (dest & ~mask) | (source & mask) - * With the condition that pos and width are immediate values - * ref: https://developer.arm.com/documentation/dui0646/c/The-Cortex-M7-Instruction-Set/Bit-field-instructions/BFC-and-BFI - */ -#define BFI(dest, source, pos, width) \ - __asm__( \ - "bfi %0, %1, %2, %3" \ - : "+r" (dest) \ - : "r" (source), "i" (pos), "i" (width) \ - ) - namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; @@ -208,7 +195,7 @@ void Scheduler::remove_sorted(uint8_t id) { pattern_32 = pattern_32 + (pattern_32 << 8); pattern_32 = pattern_32 + (pattern_32 << 16); uint64_t pattern = pattern_32; - BFI(((uint32_t*)&pattern)[1], pattern_32, 0, 32); + ((uint32_t*)&pattern)[1] = pattern_32; #pragma GCC diagnostic pop From 4a6e6e5e27c6cf71c6c0aaf28a90ad1bcfef62ab Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:09:59 +0100 Subject: [PATCH 015/281] No more diagnostic ignore --- Src/HALAL/Services/Time/Scheduler.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 63431ba85..a9044789e 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -187,9 +187,6 @@ void Scheduler::insert_sorted(uint8_t id) { void Scheduler::remove_sorted(uint8_t id) { uint64_t nibble_lsb = 0x1111'1111'1111'1111ULL; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuninitialized" - // pattern = nibble_lsb * id (para obtener id en cada nibble) uint32_t pattern_32 = id + (id << 4); pattern_32 = pattern_32 + (pattern_32 << 8); @@ -197,8 +194,6 @@ void Scheduler::remove_sorted(uint8_t id) { uint64_t pattern = pattern_32; ((uint32_t*)&pattern)[1] = pattern_32; -#pragma GCC diagnostic pop - // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; From 8681ca374e2488f3de7ea3f0b2befb75b937e833 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:13:51 +0100 Subject: [PATCH 016/281] fix: loss in accuracy by not adding 1: https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#discussion_r2581260196 --- Src/HALAL/Services/Time/Scheduler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index a9044789e..ff58b1c09 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -227,10 +227,8 @@ void Scheduler::schedule_next_interval() { Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; - uint64_t delta = (next_task.next_fire_us > global_tick_us_) - ? (next_task.next_fire_us - global_tick_us_ + 1ULL) : 1ULL; // +1 to ensure we don't miss, means loss in accuracy - - //TODO: Adding 1 accumulates drift over time analyze if acceptable, it can be solved by adding an extra if + uint64_t delta = (next_task.next_fire_us > (global_tick_us_ - 1ULL)) + ? (next_task.next_fire_us - global_tick_us_) : 1ULL; if (delta > kMaxIntervalUs) [[unlikely]] { current_interval_us_ = kMaxIntervalUs; From 1ff50c7063cfa4d96e7cf81d99f8076ff0d37edc Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:19:19 +0100 Subject: [PATCH 017/281] fix: Moved active_task_count_ modification --- Src/HALAL/Services/Time/Scheduler.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ff58b1c09..ebd0b0578 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -89,7 +89,6 @@ void Scheduler::start() { // LL_TIM_DisableExternalClock(Scheduler_global_timer); // |-> does this: Scheduler_global_timer->SMCR &= ~TIM_SMCR_ECE; /* Disable external clock */ - active_task_count_ = 0; Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); @@ -129,6 +128,7 @@ inline uint8_t Scheduler::allocate_slot() { uint32_t idx = 32 - __builtin_clz(~Scheduler::used_bitmap_); if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + Scheduler::active_task_count_++; return static_cast(idx); } @@ -138,6 +138,7 @@ inline void Scheduler::release_slot(uint8_t id) { uint32_t clearmask = ~(1u << id); ready_bitmap_ &= clearmask; used_bitmap_ &= clearmask; + Scheduler::active_task_count_--; } void Scheduler::insert_sorted(uint8_t id) { @@ -181,7 +182,6 @@ void Scheduler::insert_sorted(uint8_t id) { } sorted_task_ids_ = ((uint64_t)hi << 32) | lo; - ++active_task_count_; } void Scheduler::remove_sorted(uint8_t id) { @@ -214,7 +214,6 @@ void Scheduler::remove_sorted(uint8_t id) { // Remove element (lower part | higher pushing nibble out of mask) Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); - Scheduler::active_task_count_--; } void Scheduler::schedule_next_interval() { From a2e60765ff4b53c87bd58789b6f15e9f3a64d6a3 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 20:05:13 +0100 Subject: [PATCH 018/281] Actually set used_bitmap_ in allocate_slot --- Src/HALAL/Services/Time/Scheduler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ebd0b0578..7b056a2eb 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -129,6 +129,7 @@ inline uint8_t Scheduler::allocate_slot() { if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); Scheduler::active_task_count_++; + Scheduler::used_bitmap_ |= (1UL << idx); return static_cast(idx); } From cdfe0817aa50f4c446f7f969431a6f0d4349815c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:26:55 +0100 Subject: [PATCH 019/281] only include sources when cross-compiling --- CMakeLists.txt | 51 +++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ba062c27..45d1e7b2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,22 +18,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 +200,28 @@ 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}> + + $<$:${STLIB_LOW_C_NO_ETH}> + $<$:${STLIB_LOW_CPP_NO_ETH}> + $<$,$>:${STLIB_LOW_C_ETH}> + $<$,$>:${STLIB_LOW_CPP_ETH}> - ${CPP_UTILITIES_C} - ${CPP_UTILITIES_CPP} + $<$:${STLIB_HIGH_C_NO_ETH}> + $<$:${STLIB_HIGH_CPP_NO_ETH}> + $<$,$>:${STLIB_HIGH_C_ETH}> + $<$,$>:${STLIB_HIGH_CPP_ETH}> - ${STLIB_LOW_C_NO_ETH} - ${STLIB_LOW_CPP_NO_ETH} - $<$:${STLIB_LOW_C_ETH}> - $<$:${STLIB_LOW_CPP_ETH}> + $<$:${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp> - ${STLIB_HIGH_C_NO_ETH} - ${STLIB_HIGH_CPP_NO_ETH} - $<$:${STLIB_HIGH_C_ETH}> - $<$:${STLIB_HIGH_CPP_ETH}> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/HALAL/Services/Time/Scheduler.cpp> - ${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp ) set_target_properties(${STLIB_LIBRARY} PROPERTIES @@ -248,7 +235,7 @@ target_compile_definitions(${STLIB_LIBRARY} PUBLIC $<$:USE_HAL_DRIVER> $<$:STM32H723xx> - $<$>:SIM_ON> + $<$>:TESTING_ENV> $<$:STLIB_ETH> $,NUCLEO,BOARD> From 2e0ce1b666ad1f065b2211e3bff45be8a85a9765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:27:34 +0100 Subject: [PATCH 020/281] modify CMakeLists inside Tests --- Tests/CMakeLists.txt | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e677d6bee..38eb7334c 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,36 +1,37 @@ +cmake_minimum_required(VERSION 3.14) if(DEFINED STLIB_NAME_SUFFIX) set(STLIB_TEST_EXECUTABLE st-lib-${STLIB_NAME_SUFFIX}-test) else() set(STLIB_TEST_EXECUTABLE st-lib-test) endif() - +project( ${STLIB_TEST_EXECUTABLE}) +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) target_link_libraries( ${STLIB_TEST_EXECUTABLE} - ${STLIB_LIBRARY} GTest::gtest_main + ${STLIB_LIBRARY} ) +if(MINGW OR CYGWIN) + # Force static linking of libgcc and libstdc++ to avoid DLL version mismatches + 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 From 8605cab5bcca7ff7b699c5c1f17e51e165649246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:28:29 +0100 Subject: [PATCH 021/281] feat: use ugly ifdef guards for host testing purposes --- Inc/HALAL/Services/Time/Scheduler.hpp | 38 +++++++++------ Src/HALAL/Services/Time/Scheduler.cpp | 67 +++++++++++++++++++-------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index d080bb181..860951ec0 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -6,8 +6,9 @@ */ #pragma once -#include "stm32h7xx_ll_tim.h" - +#ifndef TESTING_ENV + #include "stm32h7xx_ll_tim.h" +#endif #include #include #include @@ -19,15 +20,22 @@ # define SCHEDULER_TIMER_IDX 2 #endif -#define glue_(a,b) a ## b -#define glue(a,b) glue_(a,b) -#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) - -// Used to reserve a TimerPeripheral -#include "stm32h7xx_hal_tim.h" -#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) -extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; - +#ifndef TESTING_ENV + #define glue_(a,b) a ## b + #define glue(a,b) glue_(a,b) + #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) + + // Used to reserve a TimerPeripheral + #include "stm32h7xx_hal_tim.h" + #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) + extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; +#else +struct FakeTimer{ + int64_t CNT; + int64_t ARR; +}; +extern FakeTimer* Scheduler_global_timer; +#endif struct Scheduler { using callback_t = void (*)(); static constexpr uint32_t INVALID_ID = 0xFFu; @@ -51,10 +59,14 @@ struct Scheduler { // static void global_timer_callback(); // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise - static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + #ifndef TESTING_ENV + static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + #endif static void on_timer_update(); -private: +#ifndef TESTING_ENV + private: +#endif struct Task { uint64_t next_fire_us{0}; callback_t callback{}; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 7b056a2eb..562186fe3 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -6,22 +6,26 @@ */ #include "HALAL/Services/Time/Scheduler.hpp" -// This is needed to register a TimerPeripheral -#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" - +#ifndef TESTING_ENV + // This is needed to register a TimerPeripheral + #include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" +#else + #include +#endif #include #include -/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ -#define SCHEDULER_RCC_TIMER_ENABLE \ - glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) -#define SCHEDULER_GLOBAL_TIMER_IRQn \ - glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) -#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ - extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) - -#define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) - +#ifndef TESTING_ENV + /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ + #define SCHEDULER_RCC_TIMER_ENABLE \ + glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) + #define SCHEDULER_GLOBAL_TIMER_IRQn \ + glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) + #define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ + extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) + + #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) +#endif namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; @@ -59,21 +63,35 @@ inline void Scheduler::pop_front() { // ---------------------------- inline void Scheduler::global_timer_disable() { +#ifndef TESTING_ENV LL_TIM_DisableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 &= ~TIM_CR1_CEN; +#endif } inline void Scheduler::global_timer_enable() { +#ifndef TESTING_ENV LL_TIM_EnableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 |= TIM_CR1_CEN; +#endif } // ---------------------------- - +FakeTimer* Scheduler_global_timer; +void TimerCallback(); +void simulate_ticking(){ + Scheduler_global_timer->CNT++; + if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ + TimerCallback(); + std::cout<<"overflow\n"; + Scheduler_global_timer->CNT = -1; + } +} void Scheduler::start() { static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; static_assert(prescaler < 0xFFFF'FFFF, "Prescaler is 16 bit, so it must be in that range"); +#ifndef TESTING_ENV // Register a TimerPeripheral so it's not used anywhere else // hopefully we can move to something better than TimerPeripheral @@ -95,15 +113,24 @@ void Scheduler::start() { Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() // Scheduler::global_timer_enable(); - +#else + active_task_count_ = 0; + Scheduler_global_timer = new FakeTimer(); + Scheduler_global_timer->CNT = 0; + Scheduler_global_timer->ARR = 0; +#endif Scheduler::schedule_next_interval(); } -SCHEDULER_GLOBAL_TIMER_CALLBACK() { - Scheduler_global_timer->SR &= ~TIM_SR_UIF; - Scheduler::on_timer_update(); -} - +#ifndef TESTING_ENV + SCHEDULER_GLOBAL_TIMER_CALLBACK() { + Scheduler_global_timer->SR &= ~TIM_SR_UIF; +#else + void TimerCallback(){ +#endif + + Scheduler::on_timer_update(); + } void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); From affc2347f1aa7a2e5da819e0a89b5ddea7a4ec43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:28:53 +0100 Subject: [PATCH 022/281] add sample tests for Scheduler --- Tests/Time/scheduler_test.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Tests/Time/scheduler_test.cpp diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp new file mode 100644 index 000000000..45d2fe390 --- /dev/null +++ b/Tests/Time/scheduler_test.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include "HALAL/Services/Time/Scheduler.hpp" +int count = 0; +void fake_workload(){ + count++; +} + +TEST(SchedulerTests, UsedBitmap) { + Scheduler::register_task(10,&fake_workload); + EXPECT_EQ(Scheduler::used_bitmap_,1); +} + +TEST(SchedulerTests, TaskRegistration) { + Scheduler::register_task(10,&fake_workload); + EXPECT_EQ(Scheduler::tasks_[0].callback,fake_workload); +} \ No newline at end of file From 58af59f4179daa3aa0e7087f2343cccd6bd807de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:39:11 +0100 Subject: [PATCH 023/281] add emulated ticking --- Inc/HALAL/Services/Time/Scheduler.hpp | 13 ++++++++----- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 860951ec0..cb06984aa 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -30,11 +30,12 @@ #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; #else -struct FakeTimer{ - int64_t CNT; - int64_t ARR; -}; -extern FakeTimer* Scheduler_global_timer; + + struct FakeTimer{ + int64_t CNT; + int64_t ARR; + }; + extern FakeTimer* Scheduler_global_timer; #endif struct Scheduler { using callback_t = void (*)(); @@ -61,6 +62,8 @@ struct Scheduler { // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise #ifndef TESTING_ENV static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + #else + static void simulate_ticking(); #endif static void on_timer_update(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 562186fe3..88ccc010f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -78,7 +78,7 @@ inline void Scheduler::global_timer_enable() { // ---------------------------- FakeTimer* Scheduler_global_timer; void TimerCallback(); -void simulate_ticking(){ +void Scheduler::simulate_ticking(){ Scheduler_global_timer->CNT++; if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ TimerCallback(); From 3d8bb6ba494778da0ba968910399b39d72031ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:39:23 +0100 Subject: [PATCH 024/281] test for execution count --- Tests/Time/scheduler_test.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 45d2fe390..4c3d1ed7a 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -15,4 +15,15 @@ TEST(SchedulerTests, UsedBitmap) { TEST(SchedulerTests, TaskRegistration) { Scheduler::register_task(10,&fake_workload); EXPECT_EQ(Scheduler::tasks_[0].callback,fake_workload); +} + +TEST(SchedulerTests, TaskExecution) { + Scheduler::register_task(10,&fake_workload); + Scheduler::start(); + constexpr int NUM_TICKS = 1'000'000; + for(int i = 0; i < NUM_TICKS; i++){ + Scheduler::simulate_ticking(); + Scheduler::update(); + } + EXPECT_EQ(count,100'000); } \ No newline at end of file From e24c63795331d5d61ac89e2573786a0a6d49adb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:44:21 +0100 Subject: [PATCH 025/281] fix: CI --- Src/HALAL/Services/Time/Scheduler.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 88ccc010f..9003bad12 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -76,16 +76,18 @@ inline void Scheduler::global_timer_enable() { } // ---------------------------- -FakeTimer* Scheduler_global_timer; -void TimerCallback(); -void Scheduler::simulate_ticking(){ - Scheduler_global_timer->CNT++; - if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ - TimerCallback(); - std::cout<<"overflow\n"; - Scheduler_global_timer->CNT = -1; +#ifdef TESTING_ENV + FakeTimer* Scheduler_global_timer; + void TimerCallback(); + void Scheduler::simulate_ticking(){ + Scheduler_global_timer->CNT++; + if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ + TimerCallback(); + std::cout<<"overflow\n"; + Scheduler_global_timer->CNT = -1; + } } -} +#endif void Scheduler::start() { static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); From f670cabef432d3f9d28c853102890d77a665d644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 23:25:26 +0100 Subject: [PATCH 026/281] fix: expected result in test case + explanation --- Tests/Time/scheduler_test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 4c3d1ed7a..e090f3dfd 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -21,9 +21,11 @@ TEST(SchedulerTests, TaskExecution) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); constexpr int NUM_TICKS = 1'000'000; - for(int i = 0; i < NUM_TICKS; i++){ + for(int i = 0; i <= NUM_TICKS; i++){ Scheduler::simulate_ticking(); Scheduler::update(); } + // one tick is 1us, and we register a task that executes every 10us + // thus it should execute NUM_TICKS/10 EXPECT_EQ(count,100'000); } \ No newline at end of file From a75dd5493d9c49d03d1fd91c1efc404abc828c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:51:41 +0100 Subject: [PATCH 027/281] add compiler specific and CoreMacros --- Inc/MockedDrivers/common.hpp | 106 ++++++++++++++++++++++++ Inc/MockedDrivers/compiler_specific.hpp | 10 +++ 2 files changed, 116 insertions(+) create mode 100644 Inc/MockedDrivers/common.hpp create mode 100644 Inc/MockedDrivers/compiler_specific.hpp diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp new file mode 100644 index 000000000..b7f33c2bc --- /dev/null +++ b/Inc/MockedDrivers/common.hpp @@ -0,0 +1,106 @@ +#pragma once +#include "MockedDrivers/compiler_specific.hpp" +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +typedef enum +{ + RESET = 0, + SET = !RESET +} FlagStatus, ITStatus; + +typedef enum +{ + DISABLE = 0, + ENABLE = !DISABLE +} FunctionalState; +#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) + +typedef enum +{ + SUCCESS = 0, + ERROR = !SUCCESS +} ErrorStatus; + + +#define SET_BIT(REG, BIT) ((REG) |= (BIT)) + +#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) + +#define READ_BIT(REG, BIT) ((REG) & (BIT)) + +#define CLEAR_REG(REG) ((REG) = (0x0)) + +#define WRITE_REG(REG, VAL) ((REG) = (VAL)) + +#define READ_REG(REG) ((REG)) + +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) + +#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) + + +/* Use of CMSIS compiler intrinsics for register exclusive access */ +/* Atomic 32-bit register access macro to set one or several bits */ +#define ATOMIC_SET_BIT(REG, BIT) \ + do { \ + uint32_t val; \ + do { \ + val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \ + } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 32-bit register access macro to clear one or several bits */ +#define ATOMIC_CLEAR_BIT(REG, BIT) \ + do { \ + uint32_t val; \ + do { \ + val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \ + } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 32-bit register access macro to clear and set one or several bits */ +#define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \ + do { \ + uint32_t val; \ + do { \ + val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 16-bit register access macro to set one or several bits */ +#define ATOMIC_SETH_BIT(REG, BIT) \ + do { \ + uint16_t val; \ + do { \ + val = __LDREXH((__IO uint16_t *)&(REG)) | (BIT); \ + } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 16-bit register access macro to clear one or several bits */ +#define ATOMIC_CLEARH_BIT(REG, BIT) \ + do { \ + uint16_t val; \ + do { \ + val = __LDREXH((__IO uint16_t *)&(REG)) & ~(BIT); \ + } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 16-bit register access macro to clear and set one or several bits */ +#define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) \ + do { \ + uint16_t val; \ + do { \ + val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ + } while(0) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp new file mode 100644 index 000000000..fdad61521 --- /dev/null +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -0,0 +1,10 @@ +#pragma once + +/* + +This file contains implementatios or altername names for +ARM GCC compiler that don't work in x86_64 + +*/ +#define __RBIT +#define __CLZ __builtin_clz From f8592f4b9e9b70f9cb144a347ff79f728a618f9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:52:29 +0100 Subject: [PATCH 028/281] copy files from LL and CMSIS for TIM Registers --- Inc/MockedDrivers/ll_tim_interface.h | 5215 +++++++++++++++++ .../tim_register_definitions.hpp | 914 +++ 2 files changed, 6129 insertions(+) create mode 100644 Inc/MockedDrivers/ll_tim_interface.h create mode 100644 Inc/MockedDrivers/tim_register_definitions.hpp diff --git a/Inc/MockedDrivers/ll_tim_interface.h b/Inc/MockedDrivers/ll_tim_interface.h new file mode 100644 index 000000000..dfb2587b9 --- /dev/null +++ b/Inc/MockedDrivers/ll_tim_interface.h @@ -0,0 +1,5215 @@ +/** + ****************************************************************************** + * @file stm32h7xx_ll_tim.h + * @author MCD Application Team + * @brief Header file of TIM LL 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_LL_TIM_H +#define __STM32H7xx_LL_TIM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "mocked_ll_tim.hpp" + +#define TIM1 + +/** @addtogroup STM32H7xx_LL_Driver + * @{ + */ + +#if defined (TIM1) || defined (TIM2) || defined (TIM3) || defined (TIM4) || defined (TIM5) || defined (TIM6) || defined (TIM7) || defined (TIM8) || defined (TIM12) || defined (TIM13) || defined (TIM14) || defined (TIM15) || defined (TIM16) || defined (TIM17) || defined (TIM23) || defined (TIM24) + +/** @defgroup TIM_LL TIM + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/** @defgroup TIM_LL_Private_Variables TIM Private Variables + * @{ + */ +static const uint8_t OFFSET_TAB_CCMRx[] = +{ + 0x00U, /* 0: TIMx_CH1 */ + 0x00U, /* 1: TIMx_CH1N */ + 0x00U, /* 2: TIMx_CH2 */ + 0x00U, /* 3: TIMx_CH2N */ + 0x04U, /* 4: TIMx_CH3 */ + 0x04U, /* 5: TIMx_CH3N */ + 0x04U, /* 6: TIMx_CH4 */ + 0x3CU, /* 7: TIMx_CH5 */ + 0x3CU /* 8: TIMx_CH6 */ +}; + +static const uint8_t SHIFT_TAB_OCxx[] = +{ + 0U, /* 0: OC1M, OC1FE, OC1PE */ + 0U, /* 1: - NA */ + 8U, /* 2: OC2M, OC2FE, OC2PE */ + 0U, /* 3: - NA */ + 0U, /* 4: OC3M, OC3FE, OC3PE */ + 0U, /* 5: - NA */ + 8U, /* 6: OC4M, OC4FE, OC4PE */ + 0U, /* 7: OC5M, OC5FE, OC5PE */ + 8U /* 8: OC6M, OC6FE, OC6PE */ +}; + +static const uint8_t SHIFT_TAB_ICxx[] = +{ + 0U, /* 0: CC1S, IC1PSC, IC1F */ + 0U, /* 1: - NA */ + 8U, /* 2: CC2S, IC2PSC, IC2F */ + 0U, /* 3: - NA */ + 0U, /* 4: CC3S, IC3PSC, IC3F */ + 0U, /* 5: - NA */ + 8U, /* 6: CC4S, IC4PSC, IC4F */ + 0U, /* 7: - NA */ + 0U /* 8: - NA */ +}; + +static const uint8_t SHIFT_TAB_CCxP[] = +{ + 0U, /* 0: CC1P */ + 2U, /* 1: CC1NP */ + 4U, /* 2: CC2P */ + 6U, /* 3: CC2NP */ + 8U, /* 4: CC3P */ + 10U, /* 5: CC3NP */ + 12U, /* 6: CC4P */ + 16U, /* 7: CC5P */ + 20U /* 8: CC6P */ +}; + +static const uint8_t SHIFT_TAB_OISx[] = +{ + 0U, /* 0: OIS1 */ + 1U, /* 1: OIS1N */ + 2U, /* 2: OIS2 */ + 3U, /* 3: OIS2N */ + 4U, /* 4: OIS3 */ + 5U, /* 5: OIS3N */ + 6U, /* 6: OIS4 */ + 8U, /* 7: OIS5 */ + 10U /* 8: OIS6 */ +}; +/** + * @} + */ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup TIM_LL_Private_Constants TIM Private Constants + * @{ + */ + +#if defined(TIM_BREAK_INPUT_SUPPORT) +/* Defines used for the bit position in the register and perform offsets */ +#define TIM_POSITION_BRK_SOURCE (POSITION_VAL(Source) & 0x1FUL) + +/* Generic bit definitions for TIMx_AF1 register */ +#define TIMx_AF1_BKINP TIM1_AF1_BKINP /*!< BRK BKIN input polarity */ +#define TIMx_AF1_ETRSEL TIM1_AF1_ETRSEL /*!< TIMx ETR source selection */ +#endif /* TIM_BREAK_INPUT_SUPPORT */ + + +/* Mask used to set the TDG[x:0] of the DTG bits of the TIMx_BDTR register */ +#define DT_DELAY_1 ((uint8_t)0x7F) +#define DT_DELAY_2 ((uint8_t)0x3F) +#define DT_DELAY_3 ((uint8_t)0x1F) +#define DT_DELAY_4 ((uint8_t)0x1F) + +/* Mask used to set the DTG[7:5] bits of the DTG bits of the TIMx_BDTR register */ +#define DT_RANGE_1 ((uint8_t)0x00) +#define DT_RANGE_2 ((uint8_t)0x80) +#define DT_RANGE_3 ((uint8_t)0xC0) +#define DT_RANGE_4 ((uint8_t)0xE0) + + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup TIM_LL_Private_Macros TIM Private Macros + * @{ + */ +/** @brief Convert channel id into channel index. + * @param __CHANNEL__ This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval none + */ +#define TIM_GET_CHANNEL_INDEX( __CHANNEL__) \ + (((__CHANNEL__) == LL_TIM_CHANNEL_CH1) ? 0U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH1N) ? 1U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH2) ? 2U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH2N) ? 3U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH3) ? 4U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH3N) ? 5U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH4) ? 6U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH5) ? 7U : 8U) + +/** @brief Calculate the deadtime sampling period(in ps). + * @param __TIMCLK__ timer input clock frequency (in Hz). + * @param __CKD__ This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + * @retval none + */ +#define TIM_CALC_DTS(__TIMCLK__, __CKD__) \ + (((__CKD__) == LL_TIM_CLOCKDIVISION_DIV1) ? ((uint64_t)1000000000000U/(__TIMCLK__)) : \ + ((__CKD__) == LL_TIM_CLOCKDIVISION_DIV2) ? ((uint64_t)1000000000000U/((__TIMCLK__) >> 1U)) : \ + ((uint64_t)1000000000000U/((__TIMCLK__) >> 2U))) +/** + * @} + */ + + +/* Exported types ------------------------------------------------------------*/ +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_ES_INIT TIM Exported Init structure + * @{ + */ + +/** + * @brief TIM Time Base configuration structure definition. + */ +typedef struct +{ + uint16_t Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock. + This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetPrescaler().*/ + + uint32_t CounterMode; /*!< Specifies the counter mode. + This parameter can be a value of @ref TIM_LL_EC_COUNTERMODE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetCounterMode().*/ + + uint32_t Autoreload; /*!< Specifies the auto reload value to be loaded into the active + Auto-Reload Register at the next update event. + This parameter must be a number between Min_Data=0x0000 and Max_Data=0xFFFF. + Some timer instances may support 32 bits counters. In that case this parameter must + be a number between 0x0000 and 0xFFFFFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetAutoReload().*/ + + uint32_t ClockDivision; /*!< Specifies the clock division. + This parameter can be a value of @ref TIM_LL_EC_CLOCKDIVISION. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetClockDivision().*/ + + uint32_t RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter + reaches zero, an update event is generated and counting restarts + from the RCR value (N). + This means in PWM mode that (N+1) corresponds to: + - the number of PWM periods in edge-aligned mode + - the number of half PWM period in center-aligned mode + GP timers: this parameter must be a number between Min_Data = 0x00 and + Max_Data = 0xFF. + Advanced timers: this parameter must be a number between Min_Data = 0x0000 and + Max_Data = 0xFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetRepetitionCounter().*/ +} LL_TIM_InitTypeDef; + +/** + * @brief TIM Output Compare configuration structure definition. + */ +typedef struct +{ + uint32_t OCMode; /*!< Specifies the output mode. + This parameter can be a value of @ref TIM_LL_EC_OCMODE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetMode().*/ + + uint32_t OCState; /*!< Specifies the TIM Output Compare state. + This parameter can be a value of @ref TIM_LL_EC_OCSTATE. + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ + + uint32_t OCNState; /*!< Specifies the TIM complementary Output Compare state. + This parameter can be a value of @ref TIM_LL_EC_OCSTATE. + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ + + uint32_t CompareValue; /*!< Specifies the Compare value to be loaded into the Capture Compare Register. + This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. + + This feature can be modified afterwards using unitary function + LL_TIM_OC_SetCompareCHx (x=1..6).*/ + + uint32_t OCPolarity; /*!< Specifies the output polarity. + This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetPolarity().*/ + + uint32_t OCNPolarity; /*!< Specifies the complementary output polarity. + This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetPolarity().*/ + + + uint32_t OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. + This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetIdleState().*/ + + uint32_t OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. + This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetIdleState().*/ +} LL_TIM_OC_InitTypeDef; + +/** + * @brief TIM Input Capture configuration structure definition. + */ + +typedef struct +{ + + uint32_t ICPolarity; /*!< Specifies the active edge of the input signal. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t ICActiveInput; /*!< Specifies the input. + This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetActiveInput().*/ + + uint32_t ICPrescaler; /*!< Specifies the Input Capture Prescaler. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t ICFilter; /*!< Specifies the input capture filter. + This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ +} LL_TIM_IC_InitTypeDef; + + +/** + * @brief TIM Encoder interface configuration structure definition. + */ +typedef struct +{ + uint32_t EncoderMode; /*!< Specifies the encoder resolution (x2 or x4). + This parameter can be a value of @ref TIM_LL_EC_ENCODERMODE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetEncoderMode().*/ + + uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t IC1ActiveInput; /*!< Specifies the TI1 input source + This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetActiveInput().*/ + + uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t IC1Filter; /*!< Specifies the TI1 input filter. + This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ + + uint32_t IC2Polarity; /*!< Specifies the active edge of TI2 input. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t IC2ActiveInput; /*!< Specifies the TI2 input source + This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetActiveInput().*/ + + uint32_t IC2Prescaler; /*!< Specifies the TI2 input prescaler value. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t IC2Filter; /*!< Specifies the TI2 input filter. + This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ + +} LL_TIM_ENCODER_InitTypeDef; + +/** + * @brief TIM Hall sensor interface configuration structure definition. + */ +typedef struct +{ + + uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. + Prescaler must be set to get a maximum counter period longer than the + time interval between 2 consecutive changes on the Hall inputs. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t IC1Filter; /*!< Specifies the TI1 input filter. + This parameter can be a value of + @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ + + uint32_t CommutationDelay; /*!< Specifies the compare value to be loaded into the Capture Compare Register. + A positive pulse (TRGO event) is generated with a programmable delay every time + a change occurs on the Hall inputs. + This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetCompareCH2().*/ +} LL_TIM_HALLSENSOR_InitTypeDef; + +/** + * @brief BDTR (Break and Dead Time) structure definition + */ +typedef struct +{ + uint32_t OSSRState; /*!< Specifies the Off-State selection used in Run mode. + This parameter can be a value of @ref TIM_LL_EC_OSSR + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetOffStates() + + @note This bit-field cannot be modified as long as LOCK level 2 has been + programmed. */ + + uint32_t OSSIState; /*!< Specifies the Off-State used in Idle state. + This parameter can be a value of @ref TIM_LL_EC_OSSI + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetOffStates() + + @note This bit-field cannot be modified as long as LOCK level 2 has been + programmed. */ + + uint32_t LockLevel; /*!< Specifies the LOCK level parameters. + This parameter can be a value of @ref TIM_LL_EC_LOCKLEVEL + + @note The LOCK bits can be written only once after the reset. Once the TIMx_BDTR + register has been written, their content is frozen until the next reset.*/ + + uint8_t DeadTime; /*!< Specifies the delay time between the switching-off and the + switching-on of the outputs. + This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetDeadTime() + + @note This bit-field can not be modified as long as LOCK level 1, 2 or 3 has been + programmed. */ + + uint16_t BreakState; /*!< Specifies whether the TIM Break input is enabled or not. + This parameter can be a value of @ref TIM_LL_EC_BREAK_ENABLE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_EnableBRK() or @ref LL_TIM_DisableBRK() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t BreakPolarity; /*!< Specifies the TIM Break Input pin polarity. + This parameter can be a value of @ref TIM_LL_EC_BREAK_POLARITY + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t BreakFilter; /*!< Specifies the TIM Break Filter. + This parameter can be a value of @ref TIM_LL_EC_BREAK_FILTER + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#if defined(TIM_BDTR_BKBID) + uint32_t BreakAFMode; /*!< Specifies the alternate function mode of the break input. + This parameter can be a value of @ref TIM_LL_EC_BREAK_AFMODE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_ConfigBRK() + + @note Bidirectional break input is only supported by advanced timers instances. + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#endif /*TIM_BDTR_BKBID */ + uint32_t Break2State; /*!< Specifies whether the TIM Break2 input is enabled or not. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_ENABLE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_EnableBRK2() or @ref LL_TIM_DisableBRK2() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t Break2Polarity; /*!< Specifies the TIM Break2 Input pin polarity. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_POLARITY + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK2() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t Break2Filter; /*!< Specifies the TIM Break2 Filter. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_FILTER + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK2() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#if defined(TIM_BDTR_BKBID) + uint32_t Break2AFMode; /*!< Specifies the alternate function mode of the break2 input. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_AFMODE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_ConfigBRK2() + + @note Bidirectional break input is only supported by advanced timers instances. + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#endif /*TIM_BDTR_BKBID */ + uint32_t AutomaticOutput; /*!< Specifies whether the TIM Automatic Output feature is enabled or not. + This parameter can be a value of @ref TIM_LL_EC_AUTOMATICOUTPUT_ENABLE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_EnableAutomaticOutput() or @ref LL_TIM_DisableAutomaticOutput() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ +} LL_TIM_BDTR_InitTypeDef; + +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup TIM_LL_Exported_Constants TIM Exported Constants + * @{ + */ + +/** @defgroup TIM_LL_EC_GET_FLAG Get Flags Defines + * @brief Flags defines which can be used with LL_TIM_ReadReg function. + * @{ + */ +#define LL_TIM_SR_UIF TIM_SR_UIF /*!< Update interrupt flag */ +#define LL_TIM_SR_CC1IF TIM_SR_CC1IF /*!< Capture/compare 1 interrupt flag */ +#define LL_TIM_SR_CC2IF TIM_SR_CC2IF /*!< Capture/compare 2 interrupt flag */ +#define LL_TIM_SR_CC3IF TIM_SR_CC3IF /*!< Capture/compare 3 interrupt flag */ +#define LL_TIM_SR_CC4IF TIM_SR_CC4IF /*!< Capture/compare 4 interrupt flag */ +#define LL_TIM_SR_CC5IF TIM_SR_CC5IF /*!< Capture/compare 5 interrupt flag */ +#define LL_TIM_SR_CC6IF TIM_SR_CC6IF /*!< Capture/compare 6 interrupt flag */ +#define LL_TIM_SR_COMIF TIM_SR_COMIF /*!< COM interrupt flag */ +#define LL_TIM_SR_TIF TIM_SR_TIF /*!< Trigger interrupt flag */ +#define LL_TIM_SR_BIF TIM_SR_BIF /*!< Break interrupt flag */ +#define LL_TIM_SR_B2IF TIM_SR_B2IF /*!< Second break interrupt flag */ +#define LL_TIM_SR_CC1OF TIM_SR_CC1OF /*!< Capture/Compare 1 overcapture flag */ +#define LL_TIM_SR_CC2OF TIM_SR_CC2OF /*!< Capture/Compare 2 overcapture flag */ +#define LL_TIM_SR_CC3OF TIM_SR_CC3OF /*!< Capture/Compare 3 overcapture flag */ +#define LL_TIM_SR_CC4OF TIM_SR_CC4OF /*!< Capture/Compare 4 overcapture flag */ +#define LL_TIM_SR_SBIF TIM_SR_SBIF /*!< System Break interrupt flag */ +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_EC_BREAK_ENABLE Break Enable + * @{ + */ +#define LL_TIM_BREAK_DISABLE 0x00000000U /*!< Break function disabled */ +#define LL_TIM_BREAK_ENABLE TIM_BDTR_BKE /*!< Break function enabled */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_BREAK2_ENABLE Break2 Enable + * @{ + */ +#define LL_TIM_BREAK2_DISABLE 0x00000000U /*!< Break2 function disabled */ +#define LL_TIM_BREAK2_ENABLE TIM_BDTR_BK2E /*!< Break2 function enabled */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_AUTOMATICOUTPUT_ENABLE Automatic output enable + * @{ + */ +#define LL_TIM_AUTOMATICOUTPUT_DISABLE 0x00000000U /*!< MOE can be set only by software */ +#define LL_TIM_AUTOMATICOUTPUT_ENABLE TIM_BDTR_AOE /*!< MOE can be set by software or automatically at the next update event */ +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** @defgroup TIM_LL_EC_IT IT Defines + * @brief IT defines which can be used with LL_TIM_ReadReg and LL_TIM_WriteReg functions. + * @{ + */ +#define LL_TIM_DIER_UIE TIM_DIER_UIE /*!< Update interrupt enable */ +#define LL_TIM_DIER_CC1IE TIM_DIER_CC1IE /*!< Capture/compare 1 interrupt enable */ +#define LL_TIM_DIER_CC2IE TIM_DIER_CC2IE /*!< Capture/compare 2 interrupt enable */ +#define LL_TIM_DIER_CC3IE TIM_DIER_CC3IE /*!< Capture/compare 3 interrupt enable */ +#define LL_TIM_DIER_CC4IE TIM_DIER_CC4IE /*!< Capture/compare 4 interrupt enable */ +#define LL_TIM_DIER_COMIE TIM_DIER_COMIE /*!< COM interrupt enable */ +#define LL_TIM_DIER_TIE TIM_DIER_TIE /*!< Trigger interrupt enable */ +#define LL_TIM_DIER_BIE TIM_DIER_BIE /*!< Break interrupt enable */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_UPDATESOURCE Update Source + * @{ + */ +#define LL_TIM_UPDATESOURCE_REGULAR 0x00000000U /*!< Counter overflow/underflow, Setting the UG bit or Update generation through the slave mode controller generates an update request */ +#define LL_TIM_UPDATESOURCE_COUNTER TIM_CR1_URS /*!< Only counter overflow/underflow generates an update request */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_ONEPULSEMODE One Pulse Mode + * @{ + */ +#define LL_TIM_ONEPULSEMODE_SINGLE TIM_CR1_OPM /*!< Counter stops counting at the next update event */ +#define LL_TIM_ONEPULSEMODE_REPETITIVE 0x00000000U /*!< Counter is not stopped at update event */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_COUNTERMODE Counter Mode + * @{ + */ +#define LL_TIM_COUNTERMODE_UP 0x00000000U /*!< Counter used as upcounter */ +#define LL_TIM_COUNTERMODE_DOWN TIM_CR1_DIR /*!< Counter used as downcounter */ +#define LL_TIM_COUNTERMODE_CENTER_DOWN TIM_CR1_CMS_0 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting down. */ +#define LL_TIM_COUNTERMODE_CENTER_UP TIM_CR1_CMS_1 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up */ +#define LL_TIM_COUNTERMODE_CENTER_UP_DOWN TIM_CR1_CMS /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up or down. */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CLOCKDIVISION Clock Division + * @{ + */ +#define LL_TIM_CLOCKDIVISION_DIV1 0x00000000U /*!< tDTS=tCK_INT */ +#define LL_TIM_CLOCKDIVISION_DIV2 TIM_CR1_CKD_0 /*!< tDTS=2*tCK_INT */ +#define LL_TIM_CLOCKDIVISION_DIV4 TIM_CR1_CKD_1 /*!< tDTS=4*tCK_INT */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_COUNTERDIRECTION Counter Direction + * @{ + */ +#define LL_TIM_COUNTERDIRECTION_UP 0x00000000U /*!< Timer counter counts up */ +#define LL_TIM_COUNTERDIRECTION_DOWN TIM_CR1_DIR /*!< Timer counter counts down */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CCUPDATESOURCE Capture Compare Update Source + * @{ + */ +#define LL_TIM_CCUPDATESOURCE_COMG_ONLY 0x00000000U /*!< Capture/compare control bits are updated by setting the COMG bit only */ +#define LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI TIM_CR2_CCUS /*!< Capture/compare control bits are updated by setting the COMG bit or when a rising edge occurs on trigger input (TRGI) */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CCDMAREQUEST Capture Compare DMA Request + * @{ + */ +#define LL_TIM_CCDMAREQUEST_CC 0x00000000U /*!< CCx DMA request sent when CCx event occurs */ +#define LL_TIM_CCDMAREQUEST_UPDATE TIM_CR2_CCDS /*!< CCx DMA requests sent when update event occurs */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_LOCKLEVEL Lock Level + * @{ + */ +#define LL_TIM_LOCKLEVEL_OFF 0x00000000U /*!< LOCK OFF - No bit is write protected */ +#define LL_TIM_LOCKLEVEL_1 TIM_BDTR_LOCK_0 /*!< LOCK Level 1 */ +#define LL_TIM_LOCKLEVEL_2 TIM_BDTR_LOCK_1 /*!< LOCK Level 2 */ +#define LL_TIM_LOCKLEVEL_3 TIM_BDTR_LOCK /*!< LOCK Level 3 */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CHANNEL Channel + * @{ + */ +#define LL_TIM_CHANNEL_CH1 TIM_CCER_CC1E /*!< Timer input/output channel 1 */ +#define LL_TIM_CHANNEL_CH1N TIM_CCER_CC1NE /*!< Timer complementary output channel 1 */ +#define LL_TIM_CHANNEL_CH2 TIM_CCER_CC2E /*!< Timer input/output channel 2 */ +#define LL_TIM_CHANNEL_CH2N TIM_CCER_CC2NE /*!< Timer complementary output channel 2 */ +#define LL_TIM_CHANNEL_CH3 TIM_CCER_CC3E /*!< Timer input/output channel 3 */ +#define LL_TIM_CHANNEL_CH3N TIM_CCER_CC3NE /*!< Timer complementary output channel 3 */ +#define LL_TIM_CHANNEL_CH4 TIM_CCER_CC4E /*!< Timer input/output channel 4 */ +#define LL_TIM_CHANNEL_CH5 TIM_CCER_CC5E /*!< Timer output channel 5 */ +#define LL_TIM_CHANNEL_CH6 TIM_CCER_CC6E /*!< Timer output channel 6 */ +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_EC_OCSTATE Output Configuration State + * @{ + */ +#define LL_TIM_OCSTATE_DISABLE 0x00000000U /*!< OCx is not active */ +#define LL_TIM_OCSTATE_ENABLE TIM_CCER_CC1E /*!< OCx signal is output on the corresponding output pin */ +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** Legacy definitions for compatibility purpose +@cond 0 + */ +#define LL_TIM_OCMODE_ASSYMETRIC_PWM1 LL_TIM_OCMODE_ASYMMETRIC_PWM1 +#define LL_TIM_OCMODE_ASSYMETRIC_PWM2 LL_TIM_OCMODE_ASYMMETRIC_PWM2 +/** +@endcond + */ + +/** @defgroup TIM_LL_EC_OCMODE Output Configuration Mode + * @{ + */ +#define LL_TIM_OCMODE_FROZEN 0x00000000U /*!TIMx_CCRy else active.*/ +#define LL_TIM_OCMODE_PWM2 (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0) /*!TIMx_CCRy else inactive*/ +#define LL_TIM_OCMODE_RETRIG_OPM1 TIM_CCMR1_OC1M_3 /*!__REG__, (__VALUE__)) + +/** + * @brief Read a value in TIM register. + * @param __INSTANCE__ TIM Instance + * @param __REG__ Register to be read + * @retval Register value + */ +#define LL_TIM_ReadReg(__INSTANCE__, __REG__) READ_REG((__INSTANCE__)->__REG__) +/** + * @} + */ + +/** + * @brief HELPER macro retrieving the UIFCPY flag from the counter value. + * @note ex: @ref __LL_TIM_GETFLAG_UIFCPY (@ref LL_TIM_GetCounter ()); + * @note Relevant only if UIF flag remapping has been enabled (UIF status bit is copied + * to TIMx_CNT register bit 31) + * @param __CNT__ Counter value + * @retval UIF status bit + */ +#define __LL_TIM_GETFLAG_UIFCPY(__CNT__) \ + (READ_BIT((__CNT__), TIM_CNT_UIFCPY) >> TIM_CNT_UIFCPY_Pos) + +/** + * @brief HELPER macro calculating DTG[0:7] in the TIMx_BDTR register to achieve the requested dead time duration. + * @note ex: @ref __LL_TIM_CALC_DEADTIME (80000000, @ref LL_TIM_GetClockDivision (), 120); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __CKD__ This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + * @param __DT__ deadtime duration (in ns) + * @retval DTG[0:7] + */ +#define __LL_TIM_CALC_DEADTIME(__TIMCLK__, __CKD__, __DT__) \ + ( (((uint64_t)((__DT__)*1000U)) < ((DT_DELAY_1+1U) * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(((uint64_t)((__DT__)*1000U) / TIM_CALC_DTS((__TIMCLK__), (__CKD__))) & DT_DELAY_1) : \ + (((uint64_t)((__DT__)*1000U)) < ((64U + (DT_DELAY_2+1U)) * 2U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(DT_RANGE_2 | ((uint8_t)((uint8_t)((((uint64_t)((__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ + (__CKD__))) >> 1U) - (uint8_t) 64) & DT_DELAY_2)) :\ + (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_3+1U)) * 8U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(DT_RANGE_3 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ + (__CKD__))) >> 3U) - (uint8_t) 32) & DT_DELAY_3)) :\ + (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_4+1U)) * 16U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(DT_RANGE_4 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ + (__CKD__))) >> 4U) - (uint8_t) 32) & DT_DELAY_4)) :\ + 0U) + +/** + * @brief HELPER macro calculating the prescaler value to achieve the required counter clock frequency. + * @note ex: @ref __LL_TIM_CALC_PSC (80000000, 1000000); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __CNTCLK__ counter clock frequency (in Hz) + * @retval Prescaler value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_PSC(__TIMCLK__, __CNTCLK__) \ + (((__TIMCLK__) >= (__CNTCLK__)) ? (uint32_t)((((__TIMCLK__) + (__CNTCLK__)/2U)/(__CNTCLK__)) - 1U) : 0U) + +/** + * @brief HELPER macro calculating the auto-reload value to achieve the required output signal frequency. + * @note ex: @ref __LL_TIM_CALC_ARR (1000000, @ref LL_TIM_GetPrescaler (), 10000); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __PSC__ prescaler + * @param __FREQ__ output signal frequency (in Hz) + * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_ARR(__TIMCLK__, __PSC__, __FREQ__) \ + ((((__TIMCLK__)/((__PSC__) + 1U)) >= (__FREQ__)) ? (((__TIMCLK__)/((__FREQ__) * ((__PSC__) + 1U))) - 1U) : 0U) + +/** + * @brief HELPER macro calculating the compare value required to achieve the required timer output compare + * active/inactive delay. + * @note ex: @ref __LL_TIM_CALC_DELAY (1000000, @ref LL_TIM_GetPrescaler (), 10); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __PSC__ prescaler + * @param __DELAY__ timer output compare active/inactive delay (in us) + * @retval Compare value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_DELAY(__TIMCLK__, __PSC__, __DELAY__) \ + ((uint32_t)(((uint64_t)(__TIMCLK__) * (uint64_t)(__DELAY__)) \ + / ((uint64_t)1000000U * (uint64_t)((__PSC__) + 1U)))) + +/** + * @brief HELPER macro calculating the auto-reload value to achieve the required pulse duration + * (when the timer operates in one pulse mode). + * @note ex: @ref __LL_TIM_CALC_PULSE (1000000, @ref LL_TIM_GetPrescaler (), 10, 20); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __PSC__ prescaler + * @param __DELAY__ timer output compare active/inactive delay (in us) + * @param __PULSE__ pulse duration (in us) + * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_PULSE(__TIMCLK__, __PSC__, __DELAY__, __PULSE__) \ + ((uint32_t)(__LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__PULSE__)) \ + + __LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__DELAY__)))) + +/** + * @brief HELPER macro retrieving the ratio of the input capture prescaler + * @note ex: @ref __LL_TIM_GET_ICPSC_RATIO (@ref LL_TIM_IC_GetPrescaler ()); + * @param __ICPSC__ This parameter can be one of the following values: + * @arg @ref LL_TIM_ICPSC_DIV1 + * @arg @ref LL_TIM_ICPSC_DIV2 + * @arg @ref LL_TIM_ICPSC_DIV4 + * @arg @ref LL_TIM_ICPSC_DIV8 + * @retval Input capture prescaler ratio (1, 2, 4 or 8) + */ +#define __LL_TIM_GET_ICPSC_RATIO(__ICPSC__) \ + ((uint32_t)(0x01U << (((__ICPSC__) >> 16U) >> TIM_CCMR1_IC1PSC_Pos))) + + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup TIM_LL_Exported_Functions TIM Exported Functions + * @{ + */ + +/** @defgroup TIM_LL_EF_Time_Base Time Base configuration + * @{ + */ +/** + * @brief Enable timer counter. + * @rmtoll CR1 CEN LL_TIM_EnableCounter + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableCounter(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_CEN); +} + +/** + * @brief Disable timer counter. + * @rmtoll CR1 CEN LL_TIM_DisableCounter + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableCounter(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_CEN); +} + +/** + * @brief Indicates whether the timer counter is enabled. + * @rmtoll CR1 CEN LL_TIM_IsEnabledCounter + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledCounter(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR1, TIM_CR1_CEN) == (TIM_CR1_CEN)) ? 1UL : 0UL); +} + +/** + * @brief Enable update event generation. + * @rmtoll CR1 UDIS LL_TIM_EnableUpdateEvent + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableUpdateEvent(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_UDIS); +} + +/** + * @brief Disable update event generation. + * @rmtoll CR1 UDIS LL_TIM_DisableUpdateEvent + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableUpdateEvent(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_UDIS); +} + +/** + * @brief Indicates whether update event generation is enabled. + * @rmtoll CR1 UDIS LL_TIM_IsEnabledUpdateEvent + * @param TIMx Timer instance + * @retval Inverted state of bit (0 or 1). + */ +static inline uint32_t LL_TIM_IsEnabledUpdateEvent(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR1, TIM_CR1_UDIS) == (uint32_t)RESET) ? 1UL : 0UL); +} + +/** + * @brief Set update event source + * @note Update event source set to LL_TIM_UPDATESOURCE_REGULAR: any of the following events + * generate an update interrupt or DMA request if enabled: + * - Counter overflow/underflow + * - Setting the UG bit + * - Update generation through the slave mode controller + * @note Update event source set to LL_TIM_UPDATESOURCE_COUNTER: only counter + * overflow/underflow generates an update interrupt or DMA request if enabled. + * @rmtoll CR1 URS LL_TIM_SetUpdateSource + * @param TIMx Timer instance + * @param UpdateSource This parameter can be one of the following values: + * @arg @ref LL_TIM_UPDATESOURCE_REGULAR + * @arg @ref LL_TIM_UPDATESOURCE_COUNTER + * @retval None + */ +static inline void LL_TIM_SetUpdateSource(TIM_TypeDef *TIMx, uint32_t UpdateSource) +{ + MODIFY_REG(TIMx->CR1, TIM_CR1_URS, UpdateSource); +} + +/** + * @brief Get actual event update source + * @rmtoll CR1 URS LL_TIM_GetUpdateSource + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_UPDATESOURCE_REGULAR + * @arg @ref LL_TIM_UPDATESOURCE_COUNTER + */ +static inline uint32_t LL_TIM_GetUpdateSource(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_URS)); +} + +/** + * @brief Set one pulse mode (one shot v.s. repetitive). + * @rmtoll CR1 OPM LL_TIM_SetOnePulseMode + * @param TIMx Timer instance + * @param OnePulseMode This parameter can be one of the following values: + * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE + * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE + * @retval None + */ +static inline void LL_TIM_SetOnePulseMode(TIM_TypeDef *TIMx, uint32_t OnePulseMode) +{ + MODIFY_REG(TIMx->CR1, TIM_CR1_OPM, OnePulseMode); +} + +/** + * @brief Get actual one pulse mode. + * @rmtoll CR1 OPM LL_TIM_GetOnePulseMode + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE + * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE + */ +static inline uint32_t LL_TIM_GetOnePulseMode(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_OPM)); +} + +/** + * @brief Set the timer counter counting mode. + * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to + * check whether or not the counter mode selection feature is supported + * by a timer instance. + * @note Switching from Center Aligned counter mode to Edge counter mode (or reverse) + * requires a timer reset to avoid unexpected direction + * due to DIR bit readonly in center aligned mode. + * @rmtoll CR1 DIR LL_TIM_SetCounterMode\n + * CR1 CMS LL_TIM_SetCounterMode + * @param TIMx Timer instance + * @param CounterMode This parameter can be one of the following values: + * @arg @ref LL_TIM_COUNTERMODE_UP + * @arg @ref LL_TIM_COUNTERMODE_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP + * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN + * @retval None + */ +static inline void LL_TIM_SetCounterMode(TIM_TypeDef *TIMx, uint32_t CounterMode) +{ + MODIFY_REG(TIMx->CR1, (TIM_CR1_DIR | TIM_CR1_CMS), CounterMode); +} + +/** + * @brief Get actual counter mode. + * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to + * check whether or not the counter mode selection feature is supported + * by a timer instance. + * @rmtoll CR1 DIR LL_TIM_GetCounterMode\n + * CR1 CMS LL_TIM_GetCounterMode + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_COUNTERMODE_UP + * @arg @ref LL_TIM_COUNTERMODE_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP + * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN + */ +static inline uint32_t LL_TIM_GetCounterMode(const TIM_TypeDef *TIMx) +{ + uint32_t counter_mode; + + counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CMS)); + + if (counter_mode == 0U) + { + counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); + } + + return counter_mode; +} + +/** + * @brief Enable auto-reload (ARR) preload. + * @rmtoll CR1 ARPE LL_TIM_EnableARRPreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableARRPreload(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_ARPE); +} + +/** + * @brief Disable auto-reload (ARR) preload. + * @rmtoll CR1 ARPE LL_TIM_DisableARRPreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableARRPreload(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_ARPE); +} + +/** + * @brief Indicates whether auto-reload (ARR) preload is enabled. + * @rmtoll CR1 ARPE LL_TIM_IsEnabledARRPreload + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledARRPreload(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR1, TIM_CR1_ARPE) == (TIM_CR1_ARPE)) ? 1UL : 0UL); +} + +/** + * @brief Set the division ratio between the timer clock and the sampling clock used by the dead-time generators + * (when supported) and the digital filters. + * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check + * whether or not the clock division feature is supported by the timer + * instance. + * @rmtoll CR1 CKD LL_TIM_SetClockDivision + * @param TIMx Timer instance + * @param ClockDivision This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + * @retval None + */ +static inline void LL_TIM_SetClockDivision(TIM_TypeDef *TIMx, uint32_t ClockDivision) +{ + MODIFY_REG(TIMx->CR1, TIM_CR1_CKD, ClockDivision); +} + +/** + * @brief Get the actual division ratio between the timer clock and the sampling clock used by the dead-time + * generators (when supported) and the digital filters. + * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check + * whether or not the clock division feature is supported by the timer + * instance. + * @rmtoll CR1 CKD LL_TIM_GetClockDivision + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + */ +static inline uint32_t LL_TIM_GetClockDivision(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CKD)); +} + +/** + * @brief Set the counter value. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @rmtoll CNT CNT LL_TIM_SetCounter + * @param TIMx Timer instance + * @param Counter Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) + * @retval None + */ +static inline void LL_TIM_SetCounter(TIM_TypeDef *TIMx, uint32_t Counter) +{ + WRITE_REG(TIMx->CNT, Counter); +} + +/** + * @brief Get the counter value. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @rmtoll CNT CNT LL_TIM_GetCounter + * @param TIMx Timer instance + * @retval Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) + */ +static inline uint32_t LL_TIM_GetCounter(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CNT)); +} + +/** + * @brief Get the current direction of the counter + * @rmtoll CR1 DIR LL_TIM_GetDirection + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_COUNTERDIRECTION_UP + * @arg @ref LL_TIM_COUNTERDIRECTION_DOWN + */ +static inline uint32_t LL_TIM_GetDirection(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); +} + +/** + * @brief Set the prescaler value. + * @note The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1). + * @note The prescaler can be changed on the fly as this control register is buffered. The new + * prescaler ratio is taken into account at the next update event. + * @note Helper macro @ref __LL_TIM_CALC_PSC can be used to calculate the Prescaler parameter + * @rmtoll PSC PSC LL_TIM_SetPrescaler + * @param TIMx Timer instance + * @param Prescaler between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Prescaler) +{ + WRITE_REG(TIMx->PSC, Prescaler); +} + +/** + * @brief Get the prescaler value. + * @rmtoll PSC PSC LL_TIM_GetPrescaler + * @param TIMx Timer instance + * @retval Prescaler value between Min_Data=0 and Max_Data=65535 + */ +static inline uint32_t LL_TIM_GetPrescaler(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->PSC)); +} + +/** + * @brief Set the auto-reload value. + * @note The counter is blocked while the auto-reload value is null. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Helper macro @ref __LL_TIM_CALC_ARR can be used to calculate the AutoReload parameter + * @rmtoll ARR ARR LL_TIM_SetAutoReload + * @param TIMx Timer instance + * @param AutoReload between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_SetAutoReload(TIM_TypeDef *TIMx, uint32_t AutoReload) +{ + WRITE_REG(TIMx->ARR, AutoReload); +} + +/** + * @brief Get the auto-reload value. + * @rmtoll ARR ARR LL_TIM_GetAutoReload + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @param TIMx Timer instance + * @retval Auto-reload value + */ +static inline uint32_t LL_TIM_GetAutoReload(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->ARR)); +} + +/** + * @brief Set the repetition counter value. + * @note For advanced timer instances RepetitionCounter can be up to 65535. + * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a repetition counter. + * @rmtoll RCR REP LL_TIM_SetRepetitionCounter + * @param TIMx Timer instance + * @param RepetitionCounter between Min_Data=0 and Max_Data=255 or 65535 for advanced timer. + * @retval None + */ +static inline void LL_TIM_SetRepetitionCounter(TIM_TypeDef *TIMx, uint32_t RepetitionCounter) +{ + WRITE_REG(TIMx->RCR, RepetitionCounter); +} + +/** + * @brief Get the repetition counter value. + * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a repetition counter. + * @rmtoll RCR REP LL_TIM_GetRepetitionCounter + * @param TIMx Timer instance + * @retval Repetition counter value + */ +static inline uint32_t LL_TIM_GetRepetitionCounter(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->RCR)); +} + +/** + * @brief Force a continuous copy of the update interrupt flag (UIF) into the timer counter register (bit 31). + * @note This allows both the counter value and a potential roll-over condition signalled by the UIFCPY flag to be read + * in an atomic way. + * @rmtoll CR1 UIFREMAP LL_TIM_EnableUIFRemap + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableUIFRemap(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); +} + +/** + * @brief Disable update interrupt flag (UIF) remapping. + * @rmtoll CR1 UIFREMAP LL_TIM_DisableUIFRemap + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableUIFRemap(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); +} + +/** + * @brief Indicate whether update interrupt flag (UIF) copy is set. + * @param Counter Counter value + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveUIFCPY(const uint32_t Counter) +{ + return (((Counter & TIM_CNT_UIFCPY) == (TIM_CNT_UIFCPY)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Capture_Compare Capture Compare configuration + * @{ + */ +/** + * @brief Enable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. + * @note CCxE, CCxNE and OCxM bits are preloaded, after having been written, + * they are updated only when a commutation event (COM) occurs. + * @note Only on channels that have a complementary output. + * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check + * whether or not a timer instance is able to generate a commutation event. + * @rmtoll CR2 CCPC LL_TIM_CC_EnablePreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_CC_EnablePreload(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR2, TIM_CR2_CCPC); +} + +/** + * @brief Disable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. + * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check + * whether or not a timer instance is able to generate a commutation event. + * @rmtoll CR2 CCPC LL_TIM_CC_DisablePreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_CC_DisablePreload(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR2, TIM_CR2_CCPC); +} + +/** + * @brief Indicates whether the capture/compare control bits (CCxE, CCxNE and OCxM) preload is enabled. + * @rmtoll CR2 CCPC LL_TIM_CC_IsEnabledPreload + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_CC_IsEnabledPreload(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR2, TIM_CR2_CCPC) == (TIM_CR2_CCPC)) ? 1UL : 0UL); +} + +/** + * @brief Set the updated source of the capture/compare control bits (CCxE, CCxNE and OCxM). + * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check + * whether or not a timer instance is able to generate a commutation event. + * @rmtoll CR2 CCUS LL_TIM_CC_SetUpdate + * @param TIMx Timer instance + * @param CCUpdateSource This parameter can be one of the following values: + * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_ONLY + * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI + * @retval None + */ +static inline void LL_TIM_CC_SetUpdate(TIM_TypeDef *TIMx, uint32_t CCUpdateSource) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_CCUS, CCUpdateSource); +} + +/** + * @brief Set the trigger of the capture/compare DMA request. + * @rmtoll CR2 CCDS LL_TIM_CC_SetDMAReqTrigger + * @param TIMx Timer instance + * @param DMAReqTrigger This parameter can be one of the following values: + * @arg @ref LL_TIM_CCDMAREQUEST_CC + * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE + * @retval None + */ +static inline void LL_TIM_CC_SetDMAReqTrigger(TIM_TypeDef *TIMx, uint32_t DMAReqTrigger) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_CCDS, DMAReqTrigger); +} + +/** + * @brief Get actual trigger of the capture/compare DMA request. + * @rmtoll CR2 CCDS LL_TIM_CC_GetDMAReqTrigger + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_CCDMAREQUEST_CC + * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE + */ +static inline uint32_t LL_TIM_CC_GetDMAReqTrigger(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR2, TIM_CR2_CCDS)); +} + +/** + * @brief Set the lock level to freeze the + * configuration of several capture/compare parameters. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * the lock mechanism is supported by a timer instance. + * @rmtoll BDTR LOCK LL_TIM_CC_SetLockLevel + * @param TIMx Timer instance + * @param LockLevel This parameter can be one of the following values: + * @arg @ref LL_TIM_LOCKLEVEL_OFF + * @arg @ref LL_TIM_LOCKLEVEL_1 + * @arg @ref LL_TIM_LOCKLEVEL_2 + * @arg @ref LL_TIM_LOCKLEVEL_3 + * @retval None + */ +static inline void LL_TIM_CC_SetLockLevel(TIM_TypeDef *TIMx, uint32_t LockLevel) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_LOCK, LockLevel); +} + +/** + * @brief Enable capture/compare channels. + * @rmtoll CCER CC1E LL_TIM_CC_EnableChannel\n + * CCER CC1NE LL_TIM_CC_EnableChannel\n + * CCER CC2E LL_TIM_CC_EnableChannel\n + * CCER CC2NE LL_TIM_CC_EnableChannel\n + * CCER CC3E LL_TIM_CC_EnableChannel\n + * CCER CC3NE LL_TIM_CC_EnableChannel\n + * CCER CC4E LL_TIM_CC_EnableChannel\n + * CCER CC5E LL_TIM_CC_EnableChannel\n + * CCER CC6E LL_TIM_CC_EnableChannel + * @param TIMx Timer instance + * @param Channels This parameter can be a combination of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_CC_EnableChannel(TIM_TypeDef *TIMx, uint32_t Channels) +{ + SET_BIT(TIMx->CCER, Channels); +} + +/** + * @brief Disable capture/compare channels. + * @rmtoll CCER CC1E LL_TIM_CC_DisableChannel\n + * CCER CC1NE LL_TIM_CC_DisableChannel\n + * CCER CC2E LL_TIM_CC_DisableChannel\n + * CCER CC2NE LL_TIM_CC_DisableChannel\n + * CCER CC3E LL_TIM_CC_DisableChannel\n + * CCER CC3NE LL_TIM_CC_DisableChannel\n + * CCER CC4E LL_TIM_CC_DisableChannel\n + * CCER CC5E LL_TIM_CC_DisableChannel\n + * CCER CC6E LL_TIM_CC_DisableChannel + * @param TIMx Timer instance + * @param Channels This parameter can be a combination of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_CC_DisableChannel(TIM_TypeDef *TIMx, uint32_t Channels) +{ + CLEAR_BIT(TIMx->CCER, Channels); +} + +/** + * @brief Indicate whether channel(s) is(are) enabled. + * @rmtoll CCER CC1E LL_TIM_CC_IsEnabledChannel\n + * CCER CC1NE LL_TIM_CC_IsEnabledChannel\n + * CCER CC2E LL_TIM_CC_IsEnabledChannel\n + * CCER CC2NE LL_TIM_CC_IsEnabledChannel\n + * CCER CC3E LL_TIM_CC_IsEnabledChannel\n + * CCER CC3NE LL_TIM_CC_IsEnabledChannel\n + * CCER CC4E LL_TIM_CC_IsEnabledChannel\n + * CCER CC5E LL_TIM_CC_IsEnabledChannel\n + * CCER CC6E LL_TIM_CC_IsEnabledChannel + * @param TIMx Timer instance + * @param Channels This parameter can be a combination of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_CC_IsEnabledChannel(const TIM_TypeDef *TIMx, uint32_t Channels) +{ + return ((READ_BIT(TIMx->CCER, Channels) == (Channels)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Output_Channel Output channel configuration + * @{ + */ +/** + * @brief Configure an output channel. + * @rmtoll CCMR1 CC1S LL_TIM_OC_ConfigOutput\n + * CCMR1 CC2S LL_TIM_OC_ConfigOutput\n + * CCMR2 CC3S LL_TIM_OC_ConfigOutput\n + * CCMR2 CC4S LL_TIM_OC_ConfigOutput\n + * CCMR3 CC5S LL_TIM_OC_ConfigOutput\n + * CCMR3 CC6S LL_TIM_OC_ConfigOutput\n + * CCER CC1P LL_TIM_OC_ConfigOutput\n + * CCER CC2P LL_TIM_OC_ConfigOutput\n + * CCER CC3P LL_TIM_OC_ConfigOutput\n + * CCER CC4P LL_TIM_OC_ConfigOutput\n + * CCER CC5P LL_TIM_OC_ConfigOutput\n + * CCER CC6P LL_TIM_OC_ConfigOutput\n + * CR2 OIS1 LL_TIM_OC_ConfigOutput\n + * CR2 OIS2 LL_TIM_OC_ConfigOutput\n + * CR2 OIS3 LL_TIM_OC_ConfigOutput\n + * CR2 OIS4 LL_TIM_OC_ConfigOutput\n + * CR2 OIS5 LL_TIM_OC_ConfigOutput\n + * CR2 OIS6 LL_TIM_OC_ConfigOutput + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param Configuration This parameter must be a combination of all the following values: + * @arg @ref LL_TIM_OCPOLARITY_HIGH or @ref LL_TIM_OCPOLARITY_LOW + * @arg @ref LL_TIM_OCIDLESTATE_LOW or @ref LL_TIM_OCIDLESTATE_HIGH + * @retval None + */ +static inline void LL_TIM_OC_ConfigOutput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_CC1S << SHIFT_TAB_OCxx[iChannel])); + MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), + (Configuration & TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]); + MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), + (Configuration & TIM_CR2_OIS1) << SHIFT_TAB_OISx[iChannel]); +} + +/** + * @brief Define the behavior of the output reference signal OCxREF from which + * OCx and OCxN (when relevant) are derived. + * @rmtoll CCMR1 OC1M LL_TIM_OC_SetMode\n + * CCMR1 OC2M LL_TIM_OC_SetMode\n + * CCMR2 OC3M LL_TIM_OC_SetMode\n + * CCMR2 OC4M LL_TIM_OC_SetMode\n + * CCMR3 OC5M LL_TIM_OC_SetMode\n + * CCMR3 OC6M LL_TIM_OC_SetMode + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param Mode This parameter can be one of the following values: + * @arg @ref LL_TIM_OCMODE_FROZEN + * @arg @ref LL_TIM_OCMODE_ACTIVE + * @arg @ref LL_TIM_OCMODE_INACTIVE + * @arg @ref LL_TIM_OCMODE_TOGGLE + * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE + * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE + * @arg @ref LL_TIM_OCMODE_PWM1 + * @arg @ref LL_TIM_OCMODE_PWM2 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 + * @retval None + */ +static inline void LL_TIM_OC_SetMode(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Mode) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel]), Mode << SHIFT_TAB_OCxx[iChannel]); +} + +/** + * @brief Get the output compare mode of an output channel. + * @rmtoll CCMR1 OC1M LL_TIM_OC_GetMode\n + * CCMR1 OC2M LL_TIM_OC_GetMode\n + * CCMR2 OC3M LL_TIM_OC_GetMode\n + * CCMR2 OC4M LL_TIM_OC_GetMode\n + * CCMR3 OC5M LL_TIM_OC_GetMode\n + * CCMR3 OC6M LL_TIM_OC_GetMode + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_OCMODE_FROZEN + * @arg @ref LL_TIM_OCMODE_ACTIVE + * @arg @ref LL_TIM_OCMODE_INACTIVE + * @arg @ref LL_TIM_OCMODE_TOGGLE + * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE + * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE + * @arg @ref LL_TIM_OCMODE_PWM1 + * @arg @ref LL_TIM_OCMODE_PWM2 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 + */ +static inline uint32_t LL_TIM_OC_GetMode(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return (READ_BIT(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel])) >> SHIFT_TAB_OCxx[iChannel]); +} + +/** + * @brief Set the polarity of an output channel. + * @rmtoll CCER CC1P LL_TIM_OC_SetPolarity\n + * CCER CC1NP LL_TIM_OC_SetPolarity\n + * CCER CC2P LL_TIM_OC_SetPolarity\n + * CCER CC2NP LL_TIM_OC_SetPolarity\n + * CCER CC3P LL_TIM_OC_SetPolarity\n + * CCER CC3NP LL_TIM_OC_SetPolarity\n + * CCER CC4P LL_TIM_OC_SetPolarity\n + * CCER CC5P LL_TIM_OC_SetPolarity\n + * CCER CC6P LL_TIM_OC_SetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_OCPOLARITY_HIGH + * @arg @ref LL_TIM_OCPOLARITY_LOW + * @retval None + */ +static inline void LL_TIM_OC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Polarity) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), Polarity << SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Get the polarity of an output channel. + * @rmtoll CCER CC1P LL_TIM_OC_GetPolarity\n + * CCER CC1NP LL_TIM_OC_GetPolarity\n + * CCER CC2P LL_TIM_OC_GetPolarity\n + * CCER CC2NP LL_TIM_OC_GetPolarity\n + * CCER CC3P LL_TIM_OC_GetPolarity\n + * CCER CC3NP LL_TIM_OC_GetPolarity\n + * CCER CC4P LL_TIM_OC_GetPolarity\n + * CCER CC5P LL_TIM_OC_GetPolarity\n + * CCER CC6P LL_TIM_OC_GetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_OCPOLARITY_HIGH + * @arg @ref LL_TIM_OCPOLARITY_LOW + */ +static inline uint32_t LL_TIM_OC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + return (READ_BIT(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel])) >> SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Set the IDLE state of an output channel + * @note This function is significant only for the timer instances + * supporting the break feature. Macro IS_TIM_BREAK_INSTANCE(TIMx) + * can be used to check whether or not a timer instance provides + * a break input. + * @rmtoll CR2 OIS1 LL_TIM_OC_SetIdleState\n + * CR2 OIS2N LL_TIM_OC_SetIdleState\n + * CR2 OIS2 LL_TIM_OC_SetIdleState\n + * CR2 OIS2N LL_TIM_OC_SetIdleState\n + * CR2 OIS3 LL_TIM_OC_SetIdleState\n + * CR2 OIS3N LL_TIM_OC_SetIdleState\n + * CR2 OIS4 LL_TIM_OC_SetIdleState\n + * CR2 OIS5 LL_TIM_OC_SetIdleState\n + * CR2 OIS6 LL_TIM_OC_SetIdleState + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param IdleState This parameter can be one of the following values: + * @arg @ref LL_TIM_OCIDLESTATE_LOW + * @arg @ref LL_TIM_OCIDLESTATE_HIGH + * @retval None + */ +static inline void LL_TIM_OC_SetIdleState(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t IdleState) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), IdleState << SHIFT_TAB_OISx[iChannel]); +} + +/** + * @brief Get the IDLE state of an output channel + * @rmtoll CR2 OIS1 LL_TIM_OC_GetIdleState\n + * CR2 OIS2N LL_TIM_OC_GetIdleState\n + * CR2 OIS2 LL_TIM_OC_GetIdleState\n + * CR2 OIS2N LL_TIM_OC_GetIdleState\n + * CR2 OIS3 LL_TIM_OC_GetIdleState\n + * CR2 OIS3N LL_TIM_OC_GetIdleState\n + * CR2 OIS4 LL_TIM_OC_GetIdleState\n + * CR2 OIS5 LL_TIM_OC_GetIdleState\n + * CR2 OIS6 LL_TIM_OC_GetIdleState + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_OCIDLESTATE_LOW + * @arg @ref LL_TIM_OCIDLESTATE_HIGH + */ +static inline uint32_t LL_TIM_OC_GetIdleState(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + return (READ_BIT(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel])) >> SHIFT_TAB_OISx[iChannel]); +} + +/** + * @brief Enable fast mode for the output channel. + * @note Acts only if the channel is configured in PWM1 or PWM2 mode. + * @rmtoll CCMR1 OC1FE LL_TIM_OC_EnableFast\n + * CCMR1 OC2FE LL_TIM_OC_EnableFast\n + * CCMR2 OC3FE LL_TIM_OC_EnableFast\n + * CCMR2 OC4FE LL_TIM_OC_EnableFast\n + * CCMR3 OC5FE LL_TIM_OC_EnableFast\n + * CCMR3 OC6FE LL_TIM_OC_EnableFast + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_EnableFast(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + SET_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); + +} + +/** + * @brief Disable fast mode for the output channel. + * @rmtoll CCMR1 OC1FE LL_TIM_OC_DisableFast\n + * CCMR1 OC2FE LL_TIM_OC_DisableFast\n + * CCMR2 OC3FE LL_TIM_OC_DisableFast\n + * CCMR2 OC4FE LL_TIM_OC_DisableFast\n + * CCMR3 OC5FE LL_TIM_OC_DisableFast\n + * CCMR3 OC6FE LL_TIM_OC_DisableFast + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_DisableFast(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); + +} + +/** + * @brief Indicates whether fast mode is enabled for the output channel. + * @rmtoll CCMR1 OC1FE LL_TIM_OC_IsEnabledFast\n + * CCMR1 OC2FE LL_TIM_OC_IsEnabledFast\n + * CCMR2 OC3FE LL_TIM_OC_IsEnabledFast\n + * CCMR2 OC4FE LL_TIM_OC_IsEnabledFast\n + * CCMR3 OC5FE LL_TIM_OC_IsEnabledFast\n + * CCMR3 OC6FE LL_TIM_OC_IsEnabledFast + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_OC_IsEnabledFast(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + uint32_t bitfield = TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel]; + return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); +} + +/** + * @brief Enable compare register (TIMx_CCRx) preload for the output channel. + * @rmtoll CCMR1 OC1PE LL_TIM_OC_EnablePreload\n + * CCMR1 OC2PE LL_TIM_OC_EnablePreload\n + * CCMR2 OC3PE LL_TIM_OC_EnablePreload\n + * CCMR2 OC4PE LL_TIM_OC_EnablePreload\n + * CCMR3 OC5PE LL_TIM_OC_EnablePreload\n + * CCMR3 OC6PE LL_TIM_OC_EnablePreload + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_EnablePreload(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + SET_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Disable compare register (TIMx_CCRx) preload for the output channel. + * @rmtoll CCMR1 OC1PE LL_TIM_OC_DisablePreload\n + * CCMR1 OC2PE LL_TIM_OC_DisablePreload\n + * CCMR2 OC3PE LL_TIM_OC_DisablePreload\n + * CCMR2 OC4PE LL_TIM_OC_DisablePreload\n + * CCMR3 OC5PE LL_TIM_OC_DisablePreload\n + * CCMR3 OC6PE LL_TIM_OC_DisablePreload + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_DisablePreload(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Indicates whether compare register (TIMx_CCRx) preload is enabled for the output channel. + * @rmtoll CCMR1 OC1PE LL_TIM_OC_IsEnabledPreload\n + * CCMR1 OC2PE LL_TIM_OC_IsEnabledPreload\n + * CCMR2 OC3PE LL_TIM_OC_IsEnabledPreload\n + * CCMR2 OC4PE LL_TIM_OC_IsEnabledPreload\n + * CCMR3 OC5PE LL_TIM_OC_IsEnabledPreload\n + * CCMR3 OC6PE LL_TIM_OC_IsEnabledPreload + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_OC_IsEnabledPreload(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + uint32_t bitfield = TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel]; + return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); +} + +/** + * @brief Enable clearing the output channel on an external event. + * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. + * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether + * or not a timer instance can clear the OCxREF signal on an external event. + * @rmtoll CCMR1 OC1CE LL_TIM_OC_EnableClear\n + * CCMR1 OC2CE LL_TIM_OC_EnableClear\n + * CCMR2 OC3CE LL_TIM_OC_EnableClear\n + * CCMR2 OC4CE LL_TIM_OC_EnableClear\n + * CCMR3 OC5CE LL_TIM_OC_EnableClear\n + * CCMR3 OC6CE LL_TIM_OC_EnableClear + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_EnableClear(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + SET_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Disable clearing the output channel on an external event. + * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether + * or not a timer instance can clear the OCxREF signal on an external event. + * @rmtoll CCMR1 OC1CE LL_TIM_OC_DisableClear\n + * CCMR1 OC2CE LL_TIM_OC_DisableClear\n + * CCMR2 OC3CE LL_TIM_OC_DisableClear\n + * CCMR2 OC4CE LL_TIM_OC_DisableClear\n + * CCMR3 OC5CE LL_TIM_OC_DisableClear\n + * CCMR3 OC6CE LL_TIM_OC_DisableClear + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_DisableClear(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Indicates clearing the output channel on an external event is enabled for the output channel. + * @note This function enables clearing the output channel on an external event. + * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. + * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether + * or not a timer instance can clear the OCxREF signal on an external event. + * @rmtoll CCMR1 OC1CE LL_TIM_OC_IsEnabledClear\n + * CCMR1 OC2CE LL_TIM_OC_IsEnabledClear\n + * CCMR2 OC3CE LL_TIM_OC_IsEnabledClear\n + * CCMR2 OC4CE LL_TIM_OC_IsEnabledClear\n + * CCMR3 OC5CE LL_TIM_OC_IsEnabledClear\n + * CCMR3 OC6CE LL_TIM_OC_IsEnabledClear + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_OC_IsEnabledClear(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + uint32_t bitfield = TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel]; + return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); +} + +/** + * @brief Set the dead-time delay (delay inserted between the rising edge of the OCxREF signal and the rising edge of + * the Ocx and OCxN signals). + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * dead-time insertion feature is supported by a timer instance. + * @note Helper macro @ref __LL_TIM_CALC_DEADTIME can be used to calculate the DeadTime parameter + * @rmtoll BDTR DTG LL_TIM_OC_SetDeadTime + * @param TIMx Timer instance + * @param DeadTime between Min_Data=0 and Max_Data=255 + * @retval None + */ +static inline void LL_TIM_OC_SetDeadTime(TIM_TypeDef *TIMx, uint32_t DeadTime) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_DTG, DeadTime); +} + +/** + * @brief Set compare value for output channel 1 (TIMx_CCR1). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not + * output channel 1 is supported by a timer instance. + * @rmtoll CCR1 CCR1 LL_TIM_OC_SetCompareCH1 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH1(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR1, CompareValue); +} + +/** + * @brief Set compare value for output channel 2 (TIMx_CCR2). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not + * output channel 2 is supported by a timer instance. + * @rmtoll CCR2 CCR2 LL_TIM_OC_SetCompareCH2 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH2(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR2, CompareValue); +} + +/** + * @brief Set compare value for output channel 3 (TIMx_CCR3). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not + * output channel is supported by a timer instance. + * @rmtoll CCR3 CCR3 LL_TIM_OC_SetCompareCH3 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH3(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR3, CompareValue); +} + +/** + * @brief Set compare value for output channel 4 (TIMx_CCR4). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not + * output channel 4 is supported by a timer instance. + * @rmtoll CCR4 CCR4 LL_TIM_OC_SetCompareCH4 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH4(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR4, CompareValue); +} + +/** + * @brief Set compare value for output channel 5 (TIMx_CCR5). + * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not + * output channel 5 is supported by a timer instance. + * @rmtoll CCR5 CCR5 LL_TIM_OC_SetCompareCH5 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH5(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + MODIFY_REG(TIMx->CCR5, TIM_CCR5_CCR5, CompareValue); +} + +/** + * @brief Set compare value for output channel 6 (TIMx_CCR6). + * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not + * output channel 6 is supported by a timer instance. + * @rmtoll CCR6 CCR6 LL_TIM_OC_SetCompareCH6 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH6(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR6, CompareValue); +} + +/** + * @brief Get compare value (TIMx_CCR1) set for output channel 1. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not + * output channel 1 is supported by a timer instance. + * @rmtoll CCR1 CCR1 LL_TIM_OC_GetCompareCH1 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH1(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR1)); +} + +/** + * @brief Get compare value (TIMx_CCR2) set for output channel 2. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not + * output channel 2 is supported by a timer instance. + * @rmtoll CCR2 CCR2 LL_TIM_OC_GetCompareCH2 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH2(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR2)); +} + +/** + * @brief Get compare value (TIMx_CCR3) set for output channel 3. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not + * output channel 3 is supported by a timer instance. + * @rmtoll CCR3 CCR3 LL_TIM_OC_GetCompareCH3 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH3(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR3)); +} + +/** + * @brief Get compare value (TIMx_CCR4) set for output channel 4. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not + * output channel 4 is supported by a timer instance. + * @rmtoll CCR4 CCR4 LL_TIM_OC_GetCompareCH4 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH4(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR4)); +} + +/** + * @brief Get compare value (TIMx_CCR5) set for output channel 5. + * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not + * output channel 5 is supported by a timer instance. + * @rmtoll CCR5 CCR5 LL_TIM_OC_GetCompareCH5 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH5(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CCR5, TIM_CCR5_CCR5)); +} + +/** + * @brief Get compare value (TIMx_CCR6) set for output channel 6. + * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not + * output channel 6 is supported by a timer instance. + * @rmtoll CCR6 CCR6 LL_TIM_OC_GetCompareCH6 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH6(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR6)); +} + +/** + * @brief Select on which reference signal the OC5REF is combined to. + * @note Macro IS_TIM_COMBINED3PHASEPWM_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports the combined 3-phase PWM mode. + * @rmtoll CCR5 GC5C3 LL_TIM_SetCH5CombinedChannels\n + * CCR5 GC5C2 LL_TIM_SetCH5CombinedChannels\n + * CCR5 GC5C1 LL_TIM_SetCH5CombinedChannels + * @param TIMx Timer instance + * @param GroupCH5 This parameter can be a combination of the following values: + * @arg @ref LL_TIM_GROUPCH5_NONE + * @arg @ref LL_TIM_GROUPCH5_OC1REFC + * @arg @ref LL_TIM_GROUPCH5_OC2REFC + * @arg @ref LL_TIM_GROUPCH5_OC3REFC + * @retval None + */ +static inline void LL_TIM_SetCH5CombinedChannels(TIM_TypeDef *TIMx, uint32_t GroupCH5) +{ + MODIFY_REG(TIMx->CCR5, (TIM_CCR5_GC5C3 | TIM_CCR5_GC5C2 | TIM_CCR5_GC5C1), GroupCH5); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Input_Channel Input channel configuration + * @{ + */ +/** + * @brief Configure input channel. + * @rmtoll CCMR1 CC1S LL_TIM_IC_Config\n + * CCMR1 IC1PSC LL_TIM_IC_Config\n + * CCMR1 IC1F LL_TIM_IC_Config\n + * CCMR1 CC2S LL_TIM_IC_Config\n + * CCMR1 IC2PSC LL_TIM_IC_Config\n + * CCMR1 IC2F LL_TIM_IC_Config\n + * CCMR2 CC3S LL_TIM_IC_Config\n + * CCMR2 IC3PSC LL_TIM_IC_Config\n + * CCMR2 IC3F LL_TIM_IC_Config\n + * CCMR2 CC4S LL_TIM_IC_Config\n + * CCMR2 IC4PSC LL_TIM_IC_Config\n + * CCMR2 IC4F LL_TIM_IC_Config\n + * CCER CC1P LL_TIM_IC_Config\n + * CCER CC1NP LL_TIM_IC_Config\n + * CCER CC2P LL_TIM_IC_Config\n + * CCER CC2NP LL_TIM_IC_Config\n + * CCER CC3P LL_TIM_IC_Config\n + * CCER CC3NP LL_TIM_IC_Config\n + * CCER CC4P LL_TIM_IC_Config\n + * CCER CC4NP LL_TIM_IC_Config + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param Configuration This parameter must be a combination of all the following values: + * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI or @ref LL_TIM_ACTIVEINPUT_INDIRECTTI or @ref LL_TIM_ACTIVEINPUT_TRC + * @arg @ref LL_TIM_ICPSC_DIV1 or ... or @ref LL_TIM_ICPSC_DIV8 + * @arg @ref LL_TIM_IC_FILTER_FDIV1 or ... or @ref LL_TIM_IC_FILTER_FDIV32_N8 + * @arg @ref LL_TIM_IC_POLARITY_RISING or @ref LL_TIM_IC_POLARITY_FALLING or @ref LL_TIM_IC_POLARITY_BOTHEDGE + * @retval None + */ +static inline void LL_TIM_IC_Config(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), + ((Configuration >> 16U) & (TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S)) \ + << SHIFT_TAB_ICxx[iChannel]); + MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), + (Configuration & (TIM_CCER_CC1NP | TIM_CCER_CC1P)) << SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Set the active input. + * @rmtoll CCMR1 CC1S LL_TIM_IC_SetActiveInput\n + * CCMR1 CC2S LL_TIM_IC_SetActiveInput\n + * CCMR2 CC3S LL_TIM_IC_SetActiveInput\n + * CCMR2 CC4S LL_TIM_IC_SetActiveInput + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICActiveInput This parameter can be one of the following values: + * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_TRC + * @retval None + */ +static inline void LL_TIM_IC_SetActiveInput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICActiveInput) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), (ICActiveInput >> 16U) << SHIFT_TAB_ICxx[iChannel]); +} + +/** + * @brief Get the current active input. + * @rmtoll CCMR1 CC1S LL_TIM_IC_GetActiveInput\n + * CCMR1 CC2S LL_TIM_IC_GetActiveInput\n + * CCMR2 CC3S LL_TIM_IC_GetActiveInput\n + * CCMR2 CC4S LL_TIM_IC_GetActiveInput + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_TRC + */ +static inline uint32_t LL_TIM_IC_GetActiveInput(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return ((READ_BIT(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); +} + +/** + * @brief Set the prescaler of input channel. + * @rmtoll CCMR1 IC1PSC LL_TIM_IC_SetPrescaler\n + * CCMR1 IC2PSC LL_TIM_IC_SetPrescaler\n + * CCMR2 IC3PSC LL_TIM_IC_SetPrescaler\n + * CCMR2 IC4PSC LL_TIM_IC_SetPrescaler + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICPrescaler This parameter can be one of the following values: + * @arg @ref LL_TIM_ICPSC_DIV1 + * @arg @ref LL_TIM_ICPSC_DIV2 + * @arg @ref LL_TIM_ICPSC_DIV4 + * @arg @ref LL_TIM_ICPSC_DIV8 + * @retval None + */ +static inline void LL_TIM_IC_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPrescaler) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel]), (ICPrescaler >> 16U) << SHIFT_TAB_ICxx[iChannel]); +} + +/** + * @brief Get the current prescaler value acting on an input channel. + * @rmtoll CCMR1 IC1PSC LL_TIM_IC_GetPrescaler\n + * CCMR1 IC2PSC LL_TIM_IC_GetPrescaler\n + * CCMR2 IC3PSC LL_TIM_IC_GetPrescaler\n + * CCMR2 IC4PSC LL_TIM_IC_GetPrescaler + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_ICPSC_DIV1 + * @arg @ref LL_TIM_ICPSC_DIV2 + * @arg @ref LL_TIM_ICPSC_DIV4 + * @arg @ref LL_TIM_ICPSC_DIV8 + */ +static inline uint32_t LL_TIM_IC_GetPrescaler(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); +} + +/** + * @brief Set the input filter duration. + * @rmtoll CCMR1 IC1F LL_TIM_IC_SetFilter\n + * CCMR1 IC2F LL_TIM_IC_SetFilter\n + * CCMR2 IC3F LL_TIM_IC_SetFilter\n + * CCMR2 IC4F LL_TIM_IC_SetFilter + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_IC_FILTER_FDIV1 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_IC_SetFilter(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICFilter) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel]), (ICFilter >> 16U) << SHIFT_TAB_ICxx[iChannel]); +} + +/** + * @brief Get the input filter duration. + * @rmtoll CCMR1 IC1F LL_TIM_IC_GetFilter\n + * CCMR1 IC2F LL_TIM_IC_GetFilter\n + * CCMR2 IC3F LL_TIM_IC_GetFilter\n + * CCMR2 IC4F LL_TIM_IC_GetFilter + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_IC_FILTER_FDIV1 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 + */ +static inline uint32_t LL_TIM_IC_GetFilter(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); +} + +/** + * @brief Set the input channel polarity. + * @rmtoll CCER CC1P LL_TIM_IC_SetPolarity\n + * CCER CC1NP LL_TIM_IC_SetPolarity\n + * CCER CC2P LL_TIM_IC_SetPolarity\n + * CCER CC2NP LL_TIM_IC_SetPolarity\n + * CCER CC3P LL_TIM_IC_SetPolarity\n + * CCER CC3NP LL_TIM_IC_SetPolarity\n + * CCER CC4P LL_TIM_IC_SetPolarity\n + * CCER CC4NP LL_TIM_IC_SetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_IC_POLARITY_RISING + * @arg @ref LL_TIM_IC_POLARITY_FALLING + * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE + * @retval None + */ +static inline void LL_TIM_IC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPolarity) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), + ICPolarity << SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Get the current input channel polarity. + * @rmtoll CCER CC1P LL_TIM_IC_GetPolarity\n + * CCER CC1NP LL_TIM_IC_GetPolarity\n + * CCER CC2P LL_TIM_IC_GetPolarity\n + * CCER CC2NP LL_TIM_IC_GetPolarity\n + * CCER CC3P LL_TIM_IC_GetPolarity\n + * CCER CC3NP LL_TIM_IC_GetPolarity\n + * CCER CC4P LL_TIM_IC_GetPolarity\n + * CCER CC4NP LL_TIM_IC_GetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_IC_POLARITY_RISING + * @arg @ref LL_TIM_IC_POLARITY_FALLING + * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE + */ +static inline uint32_t LL_TIM_IC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + return (READ_BIT(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel])) >> + SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Connect the TIMx_CH1, CH2 and CH3 pins to the TI1 input (XOR combination). + * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an XOR input. + * @rmtoll CR2 TI1S LL_TIM_IC_EnableXORCombination + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_IC_EnableXORCombination(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR2, TIM_CR2_TI1S); +} + +/** + * @brief Disconnect the TIMx_CH1, CH2 and CH3 pins from the TI1 input. + * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an XOR input. + * @rmtoll CR2 TI1S LL_TIM_IC_DisableXORCombination + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_IC_DisableXORCombination(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR2, TIM_CR2_TI1S); +} + +/** + * @brief Indicates whether the TIMx_CH1, CH2 and CH3 pins are connectected to the TI1 input. + * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an XOR input. + * @rmtoll CR2 TI1S LL_TIM_IC_IsEnabledXORCombination + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IC_IsEnabledXORCombination(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR2, TIM_CR2_TI1S) == (TIM_CR2_TI1S)) ? 1UL : 0UL); +} + +/** + * @brief Get captured value for input channel 1. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not + * input channel 1 is supported by a timer instance. + * @rmtoll CCR1 CCR1 LL_TIM_IC_GetCaptureCH1 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH1(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR1)); +} + +/** + * @brief Get captured value for input channel 2. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not + * input channel 2 is supported by a timer instance. + * @rmtoll CCR2 CCR2 LL_TIM_IC_GetCaptureCH2 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH2(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR2)); +} + +/** + * @brief Get captured value for input channel 3. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not + * input channel 3 is supported by a timer instance. + * @rmtoll CCR3 CCR3 LL_TIM_IC_GetCaptureCH3 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH3(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR3)); +} + +/** + * @brief Get captured value for input channel 4. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not + * input channel 4 is supported by a timer instance. + * @rmtoll CCR4 CCR4 LL_TIM_IC_GetCaptureCH4 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH4(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR4)); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Clock_Selection Counter clock selection + * @{ + */ +/** + * @brief Enable external clock mode 2. + * @note When external clock mode 2 is enabled the counter is clocked by any active edge on the ETRF signal. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR ECE LL_TIM_EnableExternalClock + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableExternalClock(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->SMCR, TIM_SMCR_ECE); +} + +/** + * @brief Disable external clock mode 2. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR ECE LL_TIM_DisableExternalClock + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableExternalClock(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->SMCR, TIM_SMCR_ECE); +} + +/** + * @brief Indicate whether external clock mode 2 is enabled. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR ECE LL_TIM_IsEnabledExternalClock + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledExternalClock(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SMCR, TIM_SMCR_ECE) == (TIM_SMCR_ECE)) ? 1UL : 0UL); +} + +/** + * @brief Set the clock source of the counter clock. + * @note when selected clock source is external clock mode 1, the timer input + * the external clock is applied is selected by calling the @ref LL_TIM_SetTriggerInput() + * function. This timer input must be configured by calling + * the @ref LL_TIM_IC_Config() function. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE1_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode1. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR SMS LL_TIM_SetClockSource\n + * SMCR ECE LL_TIM_SetClockSource + * @param TIMx Timer instance + * @param ClockSource This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKSOURCE_INTERNAL + * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE1 + * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE2 + * @retval None + */ +static inline void LL_TIM_SetClockSource(TIM_TypeDef *TIMx, uint32_t ClockSource) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS | TIM_SMCR_ECE, ClockSource); +} + +/** + * @brief Set the encoder interface mode. + * @note Macro IS_TIM_ENCODER_INTERFACE_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports the encoder mode. + * @rmtoll SMCR SMS LL_TIM_SetEncoderMode + * @param TIMx Timer instance + * @param EncoderMode This parameter can be one of the following values: + * @arg @ref LL_TIM_ENCODERMODE_X2_TI1 + * @arg @ref LL_TIM_ENCODERMODE_X2_TI2 + * @arg @ref LL_TIM_ENCODERMODE_X4_TI12 + * @retval None + */ +static inline void LL_TIM_SetEncoderMode(TIM_TypeDef *TIMx, uint32_t EncoderMode) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, EncoderMode); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Timer_Synchronization Timer synchronisation configuration + * @{ + */ +/** + * @brief Set the trigger output (TRGO) used for timer synchronization . + * @note Macro IS_TIM_MASTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance can operate as a master timer. + * @rmtoll CR2 MMS LL_TIM_SetTriggerOutput + * @param TIMx Timer instance + * @param TimerSynchronization This parameter can be one of the following values: + * @arg @ref LL_TIM_TRGO_RESET + * @arg @ref LL_TIM_TRGO_ENABLE + * @arg @ref LL_TIM_TRGO_UPDATE + * @arg @ref LL_TIM_TRGO_CC1IF + * @arg @ref LL_TIM_TRGO_OC1REF + * @arg @ref LL_TIM_TRGO_OC2REF + * @arg @ref LL_TIM_TRGO_OC3REF + * @arg @ref LL_TIM_TRGO_OC4REF + * @retval None + */ +static inline void LL_TIM_SetTriggerOutput(TIM_TypeDef *TIMx, uint32_t TimerSynchronization) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_MMS, TimerSynchronization); +} + +/** + * @brief Set the trigger output 2 (TRGO2) used for ADC synchronization . + * @note Macro IS_TIM_TRGO2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance can be used for ADC synchronization. + * @rmtoll CR2 MMS2 LL_TIM_SetTriggerOutput2 + * @param TIMx Timer Instance + * @param ADCSynchronization This parameter can be one of the following values: + * @arg @ref LL_TIM_TRGO2_RESET + * @arg @ref LL_TIM_TRGO2_ENABLE + * @arg @ref LL_TIM_TRGO2_UPDATE + * @arg @ref LL_TIM_TRGO2_CC1F + * @arg @ref LL_TIM_TRGO2_OC1 + * @arg @ref LL_TIM_TRGO2_OC2 + * @arg @ref LL_TIM_TRGO2_OC3 + * @arg @ref LL_TIM_TRGO2_OC4 + * @arg @ref LL_TIM_TRGO2_OC5 + * @arg @ref LL_TIM_TRGO2_OC6 + * @arg @ref LL_TIM_TRGO2_OC4_RISINGFALLING + * @arg @ref LL_TIM_TRGO2_OC6_RISINGFALLING + * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_RISING + * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_FALLING + * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_RISING + * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_FALLING + * @retval None + */ +static inline void LL_TIM_SetTriggerOutput2(TIM_TypeDef *TIMx, uint32_t ADCSynchronization) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_MMS2, ADCSynchronization); +} + +/** + * @brief Set the synchronization mode of a slave timer. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR SMS LL_TIM_SetSlaveMode + * @param TIMx Timer instance + * @param SlaveMode This parameter can be one of the following values: + * @arg @ref LL_TIM_SLAVEMODE_DISABLED + * @arg @ref LL_TIM_SLAVEMODE_RESET + * @arg @ref LL_TIM_SLAVEMODE_GATED + * @arg @ref LL_TIM_SLAVEMODE_TRIGGER + * @arg @ref LL_TIM_SLAVEMODE_COMBINED_RESETTRIGGER + * @retval None + */ +static inline void LL_TIM_SetSlaveMode(TIM_TypeDef *TIMx, uint32_t SlaveMode) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, SlaveMode); +} + +/** + * @brief Set the selects the trigger input to be used to synchronize the counter. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR TS LL_TIM_SetTriggerInput + * @param TIMx Timer instance + * @param TriggerInput This parameter can be one of the following values: + * @arg @ref LL_TIM_TS_ITR0 + * @arg @ref LL_TIM_TS_ITR1 + * @arg @ref LL_TIM_TS_ITR2 + * @arg @ref LL_TIM_TS_ITR3 + * @arg @ref LL_TIM_TS_ITR4 + * @arg @ref LL_TIM_TS_ITR5 + * @arg @ref LL_TIM_TS_ITR6 + * @arg @ref LL_TIM_TS_ITR7 + * @arg @ref LL_TIM_TS_ITR8 (*) + * @arg @ref LL_TIM_TS_ITR9 (*) + * @arg @ref LL_TIM_TS_ITR10 (*) + * @arg @ref LL_TIM_TS_ITR11 (*) + * @arg @ref LL_TIM_TS_ITR12 (*) + * @arg @ref LL_TIM_TS_ITR13 (*) + * @arg @ref LL_TIM_TS_TI1F_ED + * @arg @ref LL_TIM_TS_TI1FP1 + * @arg @ref LL_TIM_TS_TI2FP2 + * @arg @ref LL_TIM_TS_ETRF + * + * (*) Value not defined in all devices. + * @retval None + */ +static inline void LL_TIM_SetTriggerInput(TIM_TypeDef *TIMx, uint32_t TriggerInput) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_TS, TriggerInput); +} + +/** + * @brief Enable the Master/Slave mode. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR MSM LL_TIM_EnableMasterSlaveMode + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableMasterSlaveMode(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->SMCR, TIM_SMCR_MSM); +} + +/** + * @brief Disable the Master/Slave mode. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR MSM LL_TIM_DisableMasterSlaveMode + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableMasterSlaveMode(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->SMCR, TIM_SMCR_MSM); +} + +/** + * @brief Indicates whether the Master/Slave mode is enabled. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR MSM LL_TIM_IsEnabledMasterSlaveMode + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledMasterSlaveMode(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SMCR, TIM_SMCR_MSM) == (TIM_SMCR_MSM)) ? 1UL : 0UL); +} + +/** + * @brief Configure the external trigger (ETR) input. + * @note Macro IS_TIM_ETR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an external trigger input. + * @rmtoll SMCR ETP LL_TIM_ConfigETR\n + * SMCR ETPS LL_TIM_ConfigETR\n + * SMCR ETF LL_TIM_ConfigETR + * @param TIMx Timer instance + * @param ETRPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_ETR_POLARITY_NONINVERTED + * @arg @ref LL_TIM_ETR_POLARITY_INVERTED + * @param ETRPrescaler This parameter can be one of the following values: + * @arg @ref LL_TIM_ETR_PRESCALER_DIV1 + * @arg @ref LL_TIM_ETR_PRESCALER_DIV2 + * @arg @ref LL_TIM_ETR_PRESCALER_DIV4 + * @arg @ref LL_TIM_ETR_PRESCALER_DIV8 + * @param ETRFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_ETR_FILTER_FDIV1 + * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_ConfigETR(TIM_TypeDef *TIMx, uint32_t ETRPolarity, uint32_t ETRPrescaler, + uint32_t ETRFilter) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_ETP | TIM_SMCR_ETPS | TIM_SMCR_ETF, ETRPolarity | ETRPrescaler | ETRFilter); +} + +/** + * @brief Select the external trigger (ETR) input source. + * @note Macro IS_TIM_ETRSEL_INSTANCE(TIMx) can be used to check whether or + * not a timer instance supports ETR source selection. + * @rmtoll AF1 ETRSEL LL_TIM_SetETRSource + * @param TIMx Timer instance + * @param ETRSource This parameter can be one of the following values: + * For TIM1, the parameter is one of the following values: + * @arg LL_TIM_TIM1_ETRSOURCE_GPIO: TIM1_ETR is connected to GPIO + * @arg LL_TIM_TIM1_ETRSOURCE_COMP1: TIM1_ETR is connected to COMP1 output + * @arg LL_TIM_TIM1_ETRSOURCE_COMP2: TIM1_ETR is connected to COMP2 output + * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD1: TIM1_ETR is connected to ADC1 AWD1 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD2: TIM1_ETR is connected to ADC1 AWD2 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD3: TIM1_ETR is connected to ADC1 AWD3 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD1: TIM1_ETR is connected to ADC3 AWD1 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD2: TIM1_ETR is connected to ADC3 AWD2 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD3: TIM1_ETR is connected to ADC3 AWD3 + * + * For TIM2, the parameter is one of the following values: + * @arg LL_TIM_TIM2_ETRSOURCE_GPIO: TIM2_ETR is connected to GPIO + * @arg LL_TIM_TIM2_ETRSOURCE_COMP1: TIM2_ETR is connected to COMP1 output + * @arg LL_TIM_TIM2_ETRSOURCE_COMP2: TIM2_ETR is connected to COMP2 output + * @arg LL_TIM_TIM2_ETRSOURCE_LSE: TIM2_ETR is connected to LSE + * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSA: TIM2_ETR is connected to SAI1 FS_A + * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSB: TIM2_ETR is connected to SAI1 FS_B + * + * For TIM3, the parameter is one of the following values: + * @arg LL_TIM_TIM3_ETRSOURCE_GPIO: TIM3_ETR is connected to GPIO + * @arg LL_TIM_TIM3_ETRSOURCE_COMP1: TIM3_ETR is connected to COMP1 output + * + * For TIM5, the parameter is one of the following values: + * @arg LL_TIM_TIM5_ETRSOURCE_GPIO: TIM5_ETR is connected to GPIO + * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSA: TIM5_ETR is connected to SAI2 FS_A (*) + * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSB: TIM5_ETR is connected to SAI2 FS_B (*) + * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSA: TIM5_ETR is connected to SAI2 FS_A (*) + * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSB: TIM5_ETR is connected to SAI2 FS_B (*) + * + * For TIM8, the parameter is one of the following values: + * @arg LL_TIM_TIM8_ETRSOURCE_GPIO: TIM8_ETR is connected to GPIO + * @arg LL_TIM_TIM8_ETRSOURCE_COMP1: TIM8_ETR is connected to COMP1 output + * @arg LL_TIM_TIM8_ETRSOURCE_COMP2: TIM8_ETR is connected to COMP2 output + * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD1: TIM8_ETR is connected to ADC2 AWD1 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD2: TIM8_ETR is connected to ADC2 AWD2 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD3: TIM8_ETR is connected to ADC2 AWD3 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD1: TIM8_ETR is connected to ADC3 AWD1 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD2: TIM8_ETR is connected to ADC3 AWD2 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD3: TIM8_ETR is connected to ADC3 AWD3 + * + * For TIM23, the parameter is one of the following values: (*) + * @arg LL_TIM_TIM23_ETRSOURCE_GPIO TIM23_ETR is connected to GPIO + * @arg LL_TIM_TIM23_ETRSOURCE_COMP1 TIM23_ETR is connected to COMP1 output + * @arg LL_TIM_TIM23_ETRSOURCE_COMP2 TIM23_ETR is connected to COMP2 output + * + * For TIM24, the parameter is one of the following values: (*) + * @arg LL_TIM_TIM24_ETRSOURCE_GPIO TIM24_ETR is connected to GPIO + * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSA TIM24_ETR is connected to SAI4 FS_A + * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSB TIM24_ETR is connected to SAI4 FS_B + * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSA TIM24_ETR is connected to SAI1 FS_A + * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSB TIM24_ETR is connected to SAI1 FS_B + * + * (*) Value not defined in all devices. + * @retval None + */ +static inline void LL_TIM_SetETRSource(TIM_TypeDef *TIMx, uint32_t ETRSource) +{ + MODIFY_REG(TIMx->AF1, TIMx_AF1_ETRSEL, ETRSource); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Break_Function Break function configuration + * @{ + */ +/** + * @brief Enable the break function. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR BKE LL_TIM_EnableBRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableBRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BKE); +} + +/** + * @brief Disable the break function. + * @rmtoll BDTR BKE LL_TIM_DisableBRK + * @param TIMx Timer instance + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @retval None + */ +static inline void LL_TIM_DisableBRK(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BKE); +} + +#if defined(TIM_BDTR_BKBID) +/** + * @brief Configure the break input. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @note Bidirectional mode is only supported by advanced timer instances. + * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not + * a timer instance is an advanced-control timer. + * @note In bidirectional mode (BKBID bit set), the Break input is configured both + * in input mode and in open drain output mode. Any active Break event will + * assert a low logic level on the Break input to indicate an internal break + * event to external devices. + * @note When bidirectional mode isn't supported, BreakAFMode must be set to + * LL_TIM_BREAK_AFMODE_INPUT. + * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n + * BDTR BKF LL_TIM_ConfigBRK\n + * BDTR BKBID LL_TIM_ConfigBRK + * @param TIMx Timer instance + * @param BreakPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_POLARITY_LOW + * @arg @ref LL_TIM_BREAK_POLARITY_HIGH + * @param BreakFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 + * @param BreakAFMode This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_AFMODE_INPUT + * @arg @ref LL_TIM_BREAK_AFMODE_BIDIRECTIONAL + * @retval None + */ +static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, uint32_t BreakFilter, + uint32_t BreakAFMode) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF | TIM_BDTR_BKBID, BreakPolarity | BreakFilter | BreakAFMode); +} + +#else +/** + * @brief Configure the break input. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n + * BDTR BKF LL_TIM_ConfigBRK + * @param TIMx Timer instance + * @param BreakPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_POLARITY_LOW + * @arg @ref LL_TIM_BREAK_POLARITY_HIGH + * @param BreakFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, + uint32_t BreakFilter) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF, BreakPolarity | BreakFilter); +} + +#endif /* TIM_BDTR_BKBID */ +#if defined(TIM_BDTR_BKBID) +/** + * @brief Disarm the break input (when it operates in bidirectional mode). + * @note The break input can be disarmed only when it is configured in + * bidirectional mode and when when MOE is reset. + * @note Purpose is to be able to have the input voltage back to high-state, + * whatever the time constant on the output . + * @rmtoll BDTR BKDSRM LL_TIM_DisarmBRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisarmBRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BKDSRM); +} + +#endif /*TIM_BDTR_BKBID */ +/** + * @brief Enable the break 2 function. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @rmtoll BDTR BK2E LL_TIM_EnableBRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableBRK2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BK2E); +} + +/** + * @brief Disable the break 2 function. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @rmtoll BDTR BK2E LL_TIM_DisableBRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableBRK2(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BK2E); +} + +#if defined(TIM_BDTR_BKBID) +/** + * @brief Configure the break 2 input. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @note Bidirectional mode is only supported by advanced timer instances. + * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not + * a timer instance is an advanced-control timer. + * @note In bidirectional mode (BK2BID bit set), the Break 2 input is configured both + * in input mode and in open drain output mode. Any active Break event will + * assert a low logic level on the Break 2 input to indicate an internal break + * event to external devices. + * @note When bidirectional mode isn't supported, Break2AFMode must be set to + * LL_TIM_BREAK2_AFMODE_INPUT. + * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n + * BDTR BK2F LL_TIM_ConfigBRK2\n + * BDTR BK2BID LL_TIM_ConfigBRK2 + * @param TIMx Timer instance + * @param Break2Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_POLARITY_LOW + * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH + * @param Break2Filter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 + * @param Break2AFMode This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_AFMODE_INPUT + * @arg @ref LL_TIM_BREAK2_AFMODE_BIDIRECTIONAL + * @retval None + */ +static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter, + uint32_t Break2AFMode) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F | TIM_BDTR_BK2BID, Break2Polarity | Break2Filter | Break2AFMode); +} + +#else +/** + * @brief Configure the break 2 input. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n + * BDTR BK2F LL_TIM_ConfigBRK2 + * @param TIMx Timer instance + * @param Break2Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_POLARITY_LOW + * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH + * @param Break2Filter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F, Break2Polarity | Break2Filter); +} + +#endif /*TIM_BDTR_BKBID */ +#if defined(TIM_BDTR_BKBID) +/** + * @brief Disarm the break 2 input (when it operates in bidirectional mode). + * @note The break 2 input can be disarmed only when it is configured in + * bidirectional mode and when when MOE is reset. + * @note Purpose is to be able to have the input voltage back to high-state, + * whatever the time constant on the output. + * @rmtoll BDTR BK2DSRM LL_TIM_DisarmBRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisarmBRK2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BK2DSRM); +} + +#endif /*TIM_BDTR_BKBID */ +/** + * @brief Select the outputs off state (enabled v.s. disabled) in Idle and Run modes. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR OSSI LL_TIM_SetOffStates\n + * BDTR OSSR LL_TIM_SetOffStates + * @param TIMx Timer instance + * @param OffStateIdle This parameter can be one of the following values: + * @arg @ref LL_TIM_OSSI_DISABLE + * @arg @ref LL_TIM_OSSI_ENABLE + * @param OffStateRun This parameter can be one of the following values: + * @arg @ref LL_TIM_OSSR_DISABLE + * @arg @ref LL_TIM_OSSR_ENABLE + * @retval None + */ +static inline void LL_TIM_SetOffStates(TIM_TypeDef *TIMx, uint32_t OffStateIdle, uint32_t OffStateRun) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_OSSI | TIM_BDTR_OSSR, OffStateIdle | OffStateRun); +} + +/** + * @brief Enable automatic output (MOE can be set by software or automatically when a break input is active). + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR AOE LL_TIM_EnableAutomaticOutput + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableAutomaticOutput(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_AOE); +} + +/** + * @brief Disable automatic output (MOE can be set only by software). + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR AOE LL_TIM_DisableAutomaticOutput + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableAutomaticOutput(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_AOE); +} + +/** + * @brief Indicate whether automatic output is enabled. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR AOE LL_TIM_IsEnabledAutomaticOutput + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledAutomaticOutput(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->BDTR, TIM_BDTR_AOE) == (TIM_BDTR_AOE)) ? 1UL : 0UL); +} + +/** + * @brief Enable the outputs (set the MOE bit in TIMx_BDTR register). + * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by + * software and is reset in case of break or break2 event + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR MOE LL_TIM_EnableAllOutputs + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableAllOutputs(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_MOE); +} + +/** + * @brief Disable the outputs (reset the MOE bit in TIMx_BDTR register). + * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by + * software and is reset in case of break or break2 event. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR MOE LL_TIM_DisableAllOutputs + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableAllOutputs(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_MOE); +} + +/** + * @brief Indicates whether outputs are enabled. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR MOE LL_TIM_IsEnabledAllOutputs + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledAllOutputs(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->BDTR, TIM_BDTR_MOE) == (TIM_BDTR_MOE)) ? 1UL : 0UL); +} + +#if defined(TIM_BREAK_INPUT_SUPPORT) +/** + * @brief Enable the signals connected to the designated timer break input. + * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether + * or not a timer instance allows for break input selection. + * @rmtoll AF1 BKINE LL_TIM_EnableBreakInputSource\n + * AF1 BKCMP1E LL_TIM_EnableBreakInputSource\n + * AF1 BKCMP2E LL_TIM_EnableBreakInputSource\n + * AF1 BKDF1BK0E LL_TIM_EnableBreakInputSource\n + * AF2 BK2INE LL_TIM_EnableBreakInputSource\n + * AF2 BK2CMP1E LL_TIM_EnableBreakInputSource\n + * AF2 BK2CMP2E LL_TIM_EnableBreakInputSource\n + * AF2 BK2DF1BK1E LL_TIM_EnableBreakInputSource + * @param TIMx Timer instance + * @param BreakInput This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_INPUT_BKIN + * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 + * @param Source This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_SOURCE_BKIN + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 + * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK + * @retval None + */ +static inline void LL_TIM_EnableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) +{ + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); + SET_BIT(*pReg, Source); +} + +/** + * @brief Disable the signals connected to the designated timer break input. + * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether + * or not a timer instance allows for break input selection. + * @rmtoll AF1 BKINE LL_TIM_DisableBreakInputSource\n + * AF1 BKCMP1E LL_TIM_DisableBreakInputSource\n + * AF1 BKCMP2E LL_TIM_DisableBreakInputSource\n + * AF1 BKDF1BK0E LL_TIM_DisableBreakInputSource\n + * AF2 BK2INE LL_TIM_DisableBreakInputSource\n + * AF2 BK2CMP1E LL_TIM_DisableBreakInputSource\n + * AF2 BK2CMP2E LL_TIM_DisableBreakInputSource\n + * AF2 BK2DF1BK1E LL_TIM_DisableBreakInputSource + * @param TIMx Timer instance + * @param BreakInput This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_INPUT_BKIN + * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 + * @param Source This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_SOURCE_BKIN + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 + * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK + * @retval None + */ +static inline void LL_TIM_DisableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) +{ + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); + CLEAR_BIT(*pReg, Source); +} + +/** + * @brief Set the polarity of the break signal for the timer break input. + * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether + * or not a timer instance allows for break input selection. + * @rmtoll AF1 BKINP LL_TIM_SetBreakInputSourcePolarity\n + * AF1 BKCMP1P LL_TIM_SetBreakInputSourcePolarity\n + * AF1 BKCMP2P LL_TIM_SetBreakInputSourcePolarity\n + * AF2 BK2INP LL_TIM_SetBreakInputSourcePolarity\n + * AF2 BK2CMP1P LL_TIM_SetBreakInputSourcePolarity\n + * AF2 BK2CMP2P LL_TIM_SetBreakInputSourcePolarity + * @param TIMx Timer instance + * @param BreakInput This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_INPUT_BKIN + * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 + * @param Source This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_SOURCE_BKIN + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 + * @param Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_POLARITY_LOW + * @arg @ref LL_TIM_BKIN_POLARITY_HIGH + * @retval None + */ +static inline void LL_TIM_SetBreakInputSourcePolarity(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source, + uint32_t Polarity) +{ + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); + MODIFY_REG(*pReg, (TIMx_AF1_BKINP << TIM_POSITION_BRK_SOURCE), (Polarity << TIM_POSITION_BRK_SOURCE)); +} +#endif /* TIM_BREAK_INPUT_SUPPORT */ +/** + * @} + */ + +/** @defgroup TIM_LL_EF_DMA_Burst_Mode DMA burst mode configuration + * @{ + */ +/** + * @brief Configures the timer DMA burst feature. + * @note Macro IS_TIM_DMABURST_INSTANCE(TIMx) can be used to check whether or + * not a timer instance supports the DMA burst mode. + * @rmtoll DCR DBL LL_TIM_ConfigDMABurst\n + * DCR DBA LL_TIM_ConfigDMABurst + * @param TIMx Timer instance + * @param DMABurstBaseAddress This parameter can be one of the following values: + * @arg @ref LL_TIM_DMABURST_BASEADDR_CR1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CR2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_SMCR + * @arg @ref LL_TIM_DMABURST_BASEADDR_DIER + * @arg @ref LL_TIM_DMABURST_BASEADDR_SR + * @arg @ref LL_TIM_DMABURST_BASEADDR_EGR + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCER + * @arg @ref LL_TIM_DMABURST_BASEADDR_CNT + * @arg @ref LL_TIM_DMABURST_BASEADDR_PSC + * @arg @ref LL_TIM_DMABURST_BASEADDR_ARR + * @arg @ref LL_TIM_DMABURST_BASEADDR_RCR + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR3 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR4 + * @arg @ref LL_TIM_DMABURST_BASEADDR_BDTR + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR3 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR5 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR6 + * @arg @ref LL_TIM_DMABURST_BASEADDR_AF1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_AF2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_TISEL + * + * @param DMABurstLength This parameter can be one of the following values: + * @arg @ref LL_TIM_DMABURST_LENGTH_1TRANSFER + * @arg @ref LL_TIM_DMABURST_LENGTH_2TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_3TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_4TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_5TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_6TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_7TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_8TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_9TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_10TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_11TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_12TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_13TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_14TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_15TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_16TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_17TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_18TRANSFERS + * @retval None + */ +static inline void LL_TIM_ConfigDMABurst(TIM_TypeDef *TIMx, uint32_t DMABurstBaseAddress, uint32_t DMABurstLength) +{ + MODIFY_REG(TIMx->DCR, (TIM_DCR_DBL | TIM_DCR_DBA), (DMABurstBaseAddress | DMABurstLength)); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Timer_Inputs_Remapping Timer input remapping + * @{ + */ +/** + * @brief Remap TIM inputs (input channel, internal/external triggers). + * @note Macro IS_TIM_REMAP_INSTANCE(TIMx) can be used to check whether or not + * a some timer inputs can be remapped. + * TIM1: one of the following values: + * @arg LL_TIM_TIM1_TI1_RMP_GPIO: TIM1 TI1 is connected to GPIO + * @arg LL_TIM_TIM1_TI1_RMP_COMP1: TIM1 TI1 is connected to COMP1 output + * + * TIM2: one of the following values: + * @arg LL_TIM_TIM2_TI4_RMP_GPIO: TIM2 TI4 is connected to GPIO + * @arg LL_TIM_TIM2_TI4_RMP_COMP1: TIM2 TI4 is connected to COMP1 output + * @arg LL_TIM_TIM2_TI4_RMP_COMP2: TIM2 TI4 is connected to COMP2 output + * @arg LL_TIM_TIM2_TI4_RMP_COMP1_COMP2: TIM2 TI4 is connected to logical OR between COMP1 and COMP2 output + * + * TIM3: one of the following values: + * @arg LL_TIM_TIM3_TI1_RMP_GPIO: TIM3 TI1 is connected to GPIO + * @arg LL_TIM_TIM3_TI1_RMP_COMP1: TIM3 TI1 is connected to COMP1 output + * @arg LL_TIM_TIM3_TI1_RMP_COMP2: TIM3 TI1 is connected to COMP2 output + * @arg LL_TIM_TIM3_TI1_RMP_COMP1_COMP2: TIM3 TI1 is connected to logical OR between COMP1 and COMP2 output + * + * TIM5: one of the following values: + * @arg LL_TIM_TIM5_TI1_RMP_GPIO: TIM5 TI1 is connected to GPIO + * @arg LL_TIM_TIM5_TI1_RMP_CAN_TMP: TIM5 TI1 is connected to CAN TMP + * @arg LL_TIM_TIM5_TI1_RMP_CAN_RTP: TIM5 TI1 is connected to CAN RTP + * + * TIM8: one of the following values: + * @arg LL_TIM_TIM8_TI1_RMP_GPIO: TIM8 TI1 is connected to GPIO + * @arg LL_TIM_TIM8_TI1_RMP_COMP2: TIM8 TI1 is connected to COMP2 output + * + * TIM12: one of the following values: (*) + * @arg LL_TIM_TIM12_TI1_RMP_GPIO: TIM12 TI1 is connected to GPIO + * @arg LL_TIM_TIM12_TI1_RMP_SPDIF_FS: TIM12 TI1 is connected to SPDIF FS + * + * TIM15: one of the following values: + * @arg LL_TIM_TIM15_TI1_RMP_GPIO: TIM15 TI1 is connected to GPIO + * @arg LL_TIM_TIM15_TI1_RMP_TIM2: TIM15 TI1 is connected to TIM2 CH1 + * @arg LL_TIM_TIM15_TI1_RMP_TIM3: TIM15 TI1 is connected to TIM3 CH1 + * @arg LL_TIM_TIM15_TI1_RMP_TIM4: TIM15 TI1 is connected to TIM4 CH1 + * @arg LL_TIM_TIM15_TI1_RMP_LSE: TIM15 TI1 is connected to LSE + * @arg LL_TIM_TIM15_TI1_RMP_CSI: TIM15 TI1 is connected to CSI + * @arg LL_TIM_TIM15_TI1_RMP_MCO2: TIM15 TI1 is connected to MCO2 + * @arg LL_TIM_TIM15_TI2_RMP_GPIO: TIM15 TI2 is connected to GPIO + * @arg LL_TIM_TIM15_TI2_RMP_TIM2: TIM15 TI2 is connected to TIM2 CH2 + * @arg LL_TIM_TIM15_TI2_RMP_TIM3: TIM15 TI2 is connected to TIM3 CH2 + * @arg LL_TIM_TIM15_TI2_RMP_TIM4: TIM15 TI2 is connected to TIM4 CH2 + * + * TIM16: one of the following values: + * @arg LL_TIM_TIM16_TI1_RMP_GPIO: TIM16 TI1 is connected to GPIO + * @arg LL_TIM_TIM16_TI1_RMP_LSI: TIM16 TI1 is connected to LSI + * @arg LL_TIM_TIM16_TI1_RMP_LSE: TIM16 TI1 is connected to LSE + * @arg LL_TIM_TIM16_TI1_RMP_RTC: TIM16 TI1 is connected to RTC wakeup interrupt + * + * TIM17: one of the following values: + * @arg LL_TIM_TIM17_TI1_RMP_GPIO: TIM17 TI1 is connected to GPIO + * @arg LL_TIM_TIM17_TI1_RMP_SPDIF_FS: TIM17 TI1 is connected to SPDIF FS (*) + * @arg LL_TIM_TIM17_TI1_RMP_HSE_1MHZ: TIM17 TI1 is connected to HSE 1MHz + * @arg LL_TIM_TIM17_TI1_RMP_MCO1: TIM17 TI1 is connected to MCO1 + * + * TIM23: one of the following values: (*) + * @arg LL_TIM_TIM23_TI4_RMP_GPIO TIM23_TI4 is connected to GPIO + * @arg LL_TIM_TIM23_TI4_RMP_COMP1 TIM23_TI4 is connected to COMP1 output + * @arg LL_TIM_TIM23_TI4_RMP_COMP2 TIM23_TI4 is connected to COMP2 output + * @arg LL_TIM_TIM23_TI4_RMP_COMP1_COMP2 TIM23_TI4 is connected to COMP2 output + * + * TIM24: one of the following values: (*) + * @arg LL_TIM_TIM24_TI1_RMP_GPIO TIM24_TI1 is connected to GPIO + * @arg LL_TIM_TIM24_TI1_RMP_CAN_TMP TIM24_TI1 is connected to CAN_TMP + * @arg LL_TIM_TIM24_TI1_RMP_CAN_RTP TIM24_TI1 is connected to CAN_RTP + * @arg LL_TIM_TIM24_TI1_RMP_CAN_SOC TIM24_TI1 is connected to CAN_SOC + * + * (*) Value not defined in all devices. \n + * @retval None + */ +static inline void LL_TIM_SetRemap(TIM_TypeDef *TIMx, uint32_t Remap) +{ + MODIFY_REG(TIMx->TISEL, (TIM_TISEL_TI1SEL | TIM_TISEL_TI2SEL | TIM_TISEL_TI3SEL | TIM_TISEL_TI4SEL), Remap); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_FLAG_Management FLAG-Management + * @{ + */ +/** + * @brief Clear the update interrupt flag (UIF). + * @rmtoll SR UIF LL_TIM_ClearFlag_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_UPDATE(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_UIF)); +} + +/** + * @brief Indicate whether update interrupt flag (UIF) is set (update interrupt is pending). + * @rmtoll SR UIF LL_TIM_IsActiveFlag_UPDATE + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_UPDATE(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_UIF) == (TIM_SR_UIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 1 interrupt flag (CC1F). + * @rmtoll SR CC1IF LL_TIM_ClearFlag_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC1(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC1IF)); +} + +/** + * @brief Indicate whether Capture/Compare 1 interrupt flag (CC1F) is set (Capture/Compare 1 interrupt is pending). + * @rmtoll SR CC1IF LL_TIM_IsActiveFlag_CC1 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC1(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC1IF) == (TIM_SR_CC1IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 2 interrupt flag (CC2F). + * @rmtoll SR CC2IF LL_TIM_ClearFlag_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC2(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC2IF)); +} + +/** + * @brief Indicate whether Capture/Compare 2 interrupt flag (CC2F) is set (Capture/Compare 2 interrupt is pending). + * @rmtoll SR CC2IF LL_TIM_IsActiveFlag_CC2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC2IF) == (TIM_SR_CC2IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 3 interrupt flag (CC3F). + * @rmtoll SR CC3IF LL_TIM_ClearFlag_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC3(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC3IF)); +} + +/** + * @brief Indicate whether Capture/Compare 3 interrupt flag (CC3F) is set (Capture/Compare 3 interrupt is pending). + * @rmtoll SR CC3IF LL_TIM_IsActiveFlag_CC3 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC3(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC3IF) == (TIM_SR_CC3IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 4 interrupt flag (CC4F). + * @rmtoll SR CC4IF LL_TIM_ClearFlag_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC4(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC4IF)); +} + +/** + * @brief Indicate whether Capture/Compare 4 interrupt flag (CC4F) is set (Capture/Compare 4 interrupt is pending). + * @rmtoll SR CC4IF LL_TIM_IsActiveFlag_CC4 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC4(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC4IF) == (TIM_SR_CC4IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 5 interrupt flag (CC5F). + * @rmtoll SR CC5IF LL_TIM_ClearFlag_CC5 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC5(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC5IF)); +} + +/** + * @brief Indicate whether Capture/Compare 5 interrupt flag (CC5F) is set (Capture/Compare 5 interrupt is pending). + * @rmtoll SR CC5IF LL_TIM_IsActiveFlag_CC5 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC5(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC5IF) == (TIM_SR_CC5IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 6 interrupt flag (CC6F). + * @rmtoll SR CC6IF LL_TIM_ClearFlag_CC6 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC6(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC6IF)); +} + +/** + * @brief Indicate whether Capture/Compare 6 interrupt flag (CC6F) is set (Capture/Compare 6 interrupt is pending). + * @rmtoll SR CC6IF LL_TIM_IsActiveFlag_CC6 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC6(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC6IF) == (TIM_SR_CC6IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the commutation interrupt flag (COMIF). + * @rmtoll SR COMIF LL_TIM_ClearFlag_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_COM(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_COMIF)); +} + +/** + * @brief Indicate whether commutation interrupt flag (COMIF) is set (commutation interrupt is pending). + * @rmtoll SR COMIF LL_TIM_IsActiveFlag_COM + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_COM(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_COMIF) == (TIM_SR_COMIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the trigger interrupt flag (TIF). + * @rmtoll SR TIF LL_TIM_ClearFlag_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_TRIG(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_TIF)); +} + +/** + * @brief Indicate whether trigger interrupt flag (TIF) is set (trigger interrupt is pending). + * @rmtoll SR TIF LL_TIM_IsActiveFlag_TRIG + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_TRIG(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_TIF) == (TIM_SR_TIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the break interrupt flag (BIF). + * @rmtoll SR BIF LL_TIM_ClearFlag_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_BRK(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_BIF)); +} + +/** + * @brief Indicate whether break interrupt flag (BIF) is set (break interrupt is pending). + * @rmtoll SR BIF LL_TIM_IsActiveFlag_BRK + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_BRK(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_BIF) == (TIM_SR_BIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the break 2 interrupt flag (B2IF). + * @rmtoll SR B2IF LL_TIM_ClearFlag_BRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_BRK2(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_B2IF)); +} + +/** + * @brief Indicate whether break 2 interrupt flag (B2IF) is set (break 2 interrupt is pending). + * @rmtoll SR B2IF LL_TIM_IsActiveFlag_BRK2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_BRK2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_B2IF) == (TIM_SR_B2IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 1 over-capture interrupt flag (CC1OF). + * @rmtoll SR CC1OF LL_TIM_ClearFlag_CC1OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC1OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC1OF)); +} + +/** + * @brief Indicate whether Capture/Compare 1 over-capture interrupt flag (CC1OF) is set + * (Capture/Compare 1 interrupt is pending). + * @rmtoll SR CC1OF LL_TIM_IsActiveFlag_CC1OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC1OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC1OF) == (TIM_SR_CC1OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 2 over-capture interrupt flag (CC2OF). + * @rmtoll SR CC2OF LL_TIM_ClearFlag_CC2OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC2OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC2OF)); +} + +/** + * @brief Indicate whether Capture/Compare 2 over-capture interrupt flag (CC2OF) is set + * (Capture/Compare 2 over-capture interrupt is pending). + * @rmtoll SR CC2OF LL_TIM_IsActiveFlag_CC2OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC2OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC2OF) == (TIM_SR_CC2OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 3 over-capture interrupt flag (CC3OF). + * @rmtoll SR CC3OF LL_TIM_ClearFlag_CC3OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC3OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC3OF)); +} + +/** + * @brief Indicate whether Capture/Compare 3 over-capture interrupt flag (CC3OF) is set + * (Capture/Compare 3 over-capture interrupt is pending). + * @rmtoll SR CC3OF LL_TIM_IsActiveFlag_CC3OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC3OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC3OF) == (TIM_SR_CC3OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 4 over-capture interrupt flag (CC4OF). + * @rmtoll SR CC4OF LL_TIM_ClearFlag_CC4OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC4OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC4OF)); +} + +/** + * @brief Indicate whether Capture/Compare 4 over-capture interrupt flag (CC4OF) is set + * (Capture/Compare 4 over-capture interrupt is pending). + * @rmtoll SR CC4OF LL_TIM_IsActiveFlag_CC4OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC4OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC4OF) == (TIM_SR_CC4OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the system break interrupt flag (SBIF). + * @rmtoll SR SBIF LL_TIM_ClearFlag_SYSBRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_SYSBRK(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_SBIF)); +} + +/** + * @brief Indicate whether system break interrupt flag (SBIF) is set (system break interrupt is pending). + * @rmtoll SR SBIF LL_TIM_IsActiveFlag_SYSBRK + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_SYSBRK(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_SBIF) == (TIM_SR_SBIF)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_IT_Management IT-Management + * @{ + */ +/** + * @brief Enable update interrupt (UIE). + * @rmtoll DIER UIE LL_TIM_EnableIT_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_UPDATE(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_UIE); +} + +/** + * @brief Disable update interrupt (UIE). + * @rmtoll DIER UIE LL_TIM_DisableIT_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_UPDATE(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_UIE); +} + +/** + * @brief Indicates whether the update interrupt (UIE) is enabled. + * @rmtoll DIER UIE LL_TIM_IsEnabledIT_UPDATE + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_UPDATE(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_UIE) == (TIM_DIER_UIE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 1 interrupt (CC1IE). + * @rmtoll DIER CC1IE LL_TIM_EnableIT_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC1(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC1IE); +} + +/** + * @brief Disable capture/compare 1 interrupt (CC1IE). + * @rmtoll DIER CC1IE LL_TIM_DisableIT_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC1(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1IE); +} + +/** + * @brief Indicates whether the capture/compare 1 interrupt (CC1IE) is enabled. + * @rmtoll DIER CC1IE LL_TIM_IsEnabledIT_CC1 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC1(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1IE) == (TIM_DIER_CC1IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 2 interrupt (CC2IE). + * @rmtoll DIER CC2IE LL_TIM_EnableIT_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC2IE); +} + +/** + * @brief Disable capture/compare 2 interrupt (CC2IE). + * @rmtoll DIER CC2IE LL_TIM_DisableIT_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC2(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2IE); +} + +/** + * @brief Indicates whether the capture/compare 2 interrupt (CC2IE) is enabled. + * @rmtoll DIER CC2IE LL_TIM_IsEnabledIT_CC2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2IE) == (TIM_DIER_CC2IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 3 interrupt (CC3IE). + * @rmtoll DIER CC3IE LL_TIM_EnableIT_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC3(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC3IE); +} + +/** + * @brief Disable capture/compare 3 interrupt (CC3IE). + * @rmtoll DIER CC3IE LL_TIM_DisableIT_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC3(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3IE); +} + +/** + * @brief Indicates whether the capture/compare 3 interrupt (CC3IE) is enabled. + * @rmtoll DIER CC3IE LL_TIM_IsEnabledIT_CC3 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC3(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3IE) == (TIM_DIER_CC3IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 4 interrupt (CC4IE). + * @rmtoll DIER CC4IE LL_TIM_EnableIT_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC4(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC4IE); +} + +/** + * @brief Disable capture/compare 4 interrupt (CC4IE). + * @rmtoll DIER CC4IE LL_TIM_DisableIT_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC4(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4IE); +} + +/** + * @brief Indicates whether the capture/compare 4 interrupt (CC4IE) is enabled. + * @rmtoll DIER CC4IE LL_TIM_IsEnabledIT_CC4 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC4(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4IE) == (TIM_DIER_CC4IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable commutation interrupt (COMIE). + * @rmtoll DIER COMIE LL_TIM_EnableIT_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_COM(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_COMIE); +} + +/** + * @brief Disable commutation interrupt (COMIE). + * @rmtoll DIER COMIE LL_TIM_DisableIT_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_COM(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_COMIE); +} + +/** + * @brief Indicates whether the commutation interrupt (COMIE) is enabled. + * @rmtoll DIER COMIE LL_TIM_IsEnabledIT_COM + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_COM(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_COMIE) == (TIM_DIER_COMIE)) ? 1UL : 0UL); +} + +/** + * @brief Enable trigger interrupt (TIE). + * @rmtoll DIER TIE LL_TIM_EnableIT_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_TRIG(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_TIE); +} + +/** + * @brief Disable trigger interrupt (TIE). + * @rmtoll DIER TIE LL_TIM_DisableIT_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_TRIG(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_TIE); +} + +/** + * @brief Indicates whether the trigger interrupt (TIE) is enabled. + * @rmtoll DIER TIE LL_TIM_IsEnabledIT_TRIG + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_TRIG(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_TIE) == (TIM_DIER_TIE)) ? 1UL : 0UL); +} + +/** + * @brief Enable break interrupt (BIE). + * @rmtoll DIER BIE LL_TIM_EnableIT_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_BRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_BIE); +} + +/** + * @brief Disable break interrupt (BIE). + * @rmtoll DIER BIE LL_TIM_DisableIT_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_BRK(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_BIE); +} + +/** + * @brief Indicates whether the break interrupt (BIE) is enabled. + * @rmtoll DIER BIE LL_TIM_IsEnabledIT_BRK + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_BRK(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_BIE) == (TIM_DIER_BIE)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_DMA_Management DMA Management + * @{ + */ +/** + * @brief Enable update DMA request (UDE). + * @rmtoll DIER UDE LL_TIM_EnableDMAReq_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_UPDATE(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_UDE); +} + +/** + * @brief Disable update DMA request (UDE). + * @rmtoll DIER UDE LL_TIM_DisableDMAReq_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_UPDATE(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_UDE); +} + +/** + * @brief Indicates whether the update DMA request (UDE) is enabled. + * @rmtoll DIER UDE LL_TIM_IsEnabledDMAReq_UPDATE + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_UPDATE(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_UDE) == (TIM_DIER_UDE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 1 DMA request (CC1DE). + * @rmtoll DIER CC1DE LL_TIM_EnableDMAReq_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC1(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC1DE); +} + +/** + * @brief Disable capture/compare 1 DMA request (CC1DE). + * @rmtoll DIER CC1DE LL_TIM_DisableDMAReq_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC1(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1DE); +} + +/** + * @brief Indicates whether the capture/compare 1 DMA request (CC1DE) is enabled. + * @rmtoll DIER CC1DE LL_TIM_IsEnabledDMAReq_CC1 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC1(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1DE) == (TIM_DIER_CC1DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 2 DMA request (CC2DE). + * @rmtoll DIER CC2DE LL_TIM_EnableDMAReq_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC2DE); +} + +/** + * @brief Disable capture/compare 2 DMA request (CC2DE). + * @rmtoll DIER CC2DE LL_TIM_DisableDMAReq_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC2(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2DE); +} + +/** + * @brief Indicates whether the capture/compare 2 DMA request (CC2DE) is enabled. + * @rmtoll DIER CC2DE LL_TIM_IsEnabledDMAReq_CC2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2DE) == (TIM_DIER_CC2DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 3 DMA request (CC3DE). + * @rmtoll DIER CC3DE LL_TIM_EnableDMAReq_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC3(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC3DE); +} + +/** + * @brief Disable capture/compare 3 DMA request (CC3DE). + * @rmtoll DIER CC3DE LL_TIM_DisableDMAReq_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC3(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3DE); +} + +/** + * @brief Indicates whether the capture/compare 3 DMA request (CC3DE) is enabled. + * @rmtoll DIER CC3DE LL_TIM_IsEnabledDMAReq_CC3 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC3(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3DE) == (TIM_DIER_CC3DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 4 DMA request (CC4DE). + * @rmtoll DIER CC4DE LL_TIM_EnableDMAReq_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC4(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC4DE); +} + +/** + * @brief Disable capture/compare 4 DMA request (CC4DE). + * @rmtoll DIER CC4DE LL_TIM_DisableDMAReq_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC4(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4DE); +} + +/** + * @brief Indicates whether the capture/compare 4 DMA request (CC4DE) is enabled. + * @rmtoll DIER CC4DE LL_TIM_IsEnabledDMAReq_CC4 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC4(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4DE) == (TIM_DIER_CC4DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable commutation DMA request (COMDE). + * @rmtoll DIER COMDE LL_TIM_EnableDMAReq_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_COM(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_COMDE); +} + +/** + * @brief Disable commutation DMA request (COMDE). + * @rmtoll DIER COMDE LL_TIM_DisableDMAReq_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_COM(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_COMDE); +} + +/** + * @brief Indicates whether the commutation DMA request (COMDE) is enabled. + * @rmtoll DIER COMDE LL_TIM_IsEnabledDMAReq_COM + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_COM(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_COMDE) == (TIM_DIER_COMDE)) ? 1UL : 0UL); +} + +/** + * @brief Enable trigger interrupt (TDE). + * @rmtoll DIER TDE LL_TIM_EnableDMAReq_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_TRIG(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_TDE); +} + +/** + * @brief Disable trigger interrupt (TDE). + * @rmtoll DIER TDE LL_TIM_DisableDMAReq_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_TRIG(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_TDE); +} + +/** + * @brief Indicates whether the trigger interrupt (TDE) is enabled. + * @rmtoll DIER TDE LL_TIM_IsEnabledDMAReq_TRIG + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_TRIG(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_TDE) == (TIM_DIER_TDE)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_EVENT_Management EVENT-Management + * @{ + */ +/** + * @brief Generate an update event. + * @rmtoll EGR UG LL_TIM_GenerateEvent_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_UPDATE(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_UG); +} + +/** + * @brief Generate Capture/Compare 1 event. + * @rmtoll EGR CC1G LL_TIM_GenerateEvent_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC1(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC1G); +} + +/** + * @brief Generate Capture/Compare 2 event. + * @rmtoll EGR CC2G LL_TIM_GenerateEvent_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC2G); +} + +/** + * @brief Generate Capture/Compare 3 event. + * @rmtoll EGR CC3G LL_TIM_GenerateEvent_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC3(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC3G); +} + +/** + * @brief Generate Capture/Compare 4 event. + * @rmtoll EGR CC4G LL_TIM_GenerateEvent_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC4(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC4G); +} + +/** + * @brief Generate commutation event. + * @rmtoll EGR COMG LL_TIM_GenerateEvent_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_COM(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_COMG); +} + +/** + * @brief Generate trigger event. + * @rmtoll EGR TG LL_TIM_GenerateEvent_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_TRIG(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_TG); +} + +/** + * @brief Generate break event. + * @rmtoll EGR BG LL_TIM_GenerateEvent_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_BRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_BG); +} + +/** + * @brief Generate break 2 event. + * @rmtoll EGR B2G LL_TIM_GenerateEvent_BRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_BRK2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_B2G); +} + +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_EF_Init Initialisation and deinitialisation functions + * @{ + */ + +ErrorStatus LL_TIM_DeInit(const TIM_TypeDef *TIMx); +void LL_TIM_StructInit(LL_TIM_InitTypeDef *TIM_InitStruct); +ErrorStatus LL_TIM_Init(TIM_TypeDef *TIMx, const LL_TIM_InitTypeDef *TIM_InitStruct); +void LL_TIM_OC_StructInit(LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); +ErrorStatus LL_TIM_OC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); +void LL_TIM_IC_StructInit(LL_TIM_IC_InitTypeDef *TIM_ICInitStruct); +ErrorStatus LL_TIM_IC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_IC_InitTypeDef *TIM_IC_InitStruct); +void LL_TIM_ENCODER_StructInit(LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); +ErrorStatus LL_TIM_ENCODER_Init(TIM_TypeDef *TIMx, const LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); +void LL_TIM_HALLSENSOR_StructInit(LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); +ErrorStatus LL_TIM_HALLSENSOR_Init(TIM_TypeDef *TIMx, const LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); +void LL_TIM_BDTR_StructInit(LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); +ErrorStatus LL_TIM_BDTR_Init(TIM_TypeDef *TIMx, const LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** + * @} + */ + +/** + * @} + */ + +#endif /* TIM1 || TIM2 || TIM3 || TIM4 || TIM5 || TIM6 || TIM7 || TIM8 || TIM12 || TIM13 ||TIM14 || TIM15 || TIM16 || TIM17 || TIM23 || TIM24 */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32H7xx_LL_TIM_H */ diff --git a/Inc/MockedDrivers/tim_register_definitions.hpp b/Inc/MockedDrivers/tim_register_definitions.hpp new file mode 100644 index 000000000..1788be399 --- /dev/null +++ b/Inc/MockedDrivers/tim_register_definitions.hpp @@ -0,0 +1,914 @@ +#pragma once +/******************************************************************************/ +/* */ +/* TIM */ +/* */ +/******************************************************************************/ +#define TIM_BREAK_INPUT_SUPPORT /*! Date: Wed, 3 Dec 2025 15:53:09 +0100 Subject: [PATCH 029/281] bridge between LL MMIO Timer and user defined TIMER --- Inc/MockedDrivers/mocked_ll_tim.hpp | 68 +++++++++++++++++++++++ Src/MockedDrivers/mocked_ll_tim.cpp | 85 +++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 Inc/MockedDrivers/mocked_ll_tim.hpp create mode 100644 Src/MockedDrivers/mocked_ll_tim.cpp diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp new file mode 100644 index 000000000..b3dc95056 --- /dev/null +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -0,0 +1,68 @@ +#pragma once +#include +#include "MockedDrivers/common.hpp" +#include "MockedDrivers/tim_register_definitions.hpp" +class TIM_TypeDef{ +public: + TIM_TypeDef(void(* irq_handler)(void)): + callback{irq_handler} + {} + void simulate_ticking(); + void generate_update(); + volatile uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ + volatile uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ + volatile uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + volatile uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + volatile uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ + volatile uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ + volatile uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + volatile uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + volatile uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + volatile uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ + volatile uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ + volatile uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + volatile uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + volatile uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + volatile uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + volatile uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + volatile uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + volatile uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + volatile uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + volatile uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + uint32_t RESERVED1; /*!< Reserved, 0x50 */ + volatile uint32_t CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ + volatile uint32_t CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ + volatile uint32_t CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ + volatile uint32_t AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + volatile uint32_t AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + volatile uint32_t TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ +private: + // ======================================================================== + // Internal Hardware State (Shadow Registers & Hidden Counters) + // ======================================================================== + + // Internal counter for the prescaler (counts 0 to active_PSC) + uint32_t internal_psc_cnt = 0; + + // Internal counter for repetition (counts down from active_RCR to 0) + uint32_t internal_rcr_cnt = 0; + + // "Shadow" registers. These hold the values currently being used by the hardware logic. + // They are updated from the public registers (Preload registers) only on an Update Event (UEV). + uint32_t active_PSC = 0; + uint32_t active_ARR = 0; + uint32_t active_RCR = 0; + void(*callback)(); +}; + +#define DECLARE_TIMER(TIM_IDX) \ + extern TIM_TypeDef* TIM_IDX##_BASE; \ + extern "C"{ \ + void TIM_IDX##_IRQHandler(void); \ + } +#define INSTANTIATE_TIMER(TIM_IDX) \ + TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler}; \ + TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; + +DECLARE_TIMER(TIM1) +DECLARE_TIMER(TIM2) diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp new file mode 100644 index 000000000..f0bf81beb --- /dev/null +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -0,0 +1,85 @@ +#include "MockedDrivers/mocked_ll_tim.hpp" + +#include + +INSTANTIATE_TIMER(TIM2) +void TIM_TypeDef::generate_update() { + active_PSC = PSC; + active_ARR = ARR; + active_RCR = RCR; + internal_rcr_cnt = active_RCR; + internal_psc_cnt = 0; + CNT = 0; // Usually UEV also resets CNT unless configured otherwise + SR &= ~(1U << 0); // Clear UIF if needed, or set it depending on CR1 +} +void TIM_TypeDef::simulate_ticking() { + // Bit definitions for clarity + const uint32_t CR1_CEN = (1U << 0); // Counter Enable + const uint32_t CR1_UDIS = (1U << 1); // Update Disable + const uint32_t CR1_ARPE = (1U << 7); // Auto-Reload Preload Enable + const uint32_t SR_UIF = (1U << 0); // Update Interrupt Flag + + // 1. Check if Counter is Enabled + if (!(CR1 & CR1_CEN)) { + std::cout<<"TIMER IS NOT ENABLED!!\n"; + return; + } + + // 2. Prescaler Logic + // The internal prescaler counts from 0 up to active_PSC. + // We check if we reached the limit *before* incrementing to ensure accurate + // behavior for PSC=0 or PSC=1. + bool main_counter_tick = false; + + if (internal_psc_cnt >= active_PSC) { + internal_psc_cnt = 0; // Rollover + main_counter_tick = true; + } else { + internal_psc_cnt++; // Increment + } + + // If prescaler didn't overflow, the main counter doesn't move. + if (!main_counter_tick) { + return; + } + + // 3. Main Counter Logic + CNT +=1; + + // Determine the current Auto-Reload limit. + // If ARPE is set, use the buffered (shadow) value. + // If ARPE is clear, use the immediate register value. + uint32_t current_limit = (CR1 & CR1_ARPE) ? active_ARR : ARR; + + // Check for Overflow + if (CNT > current_limit) { + std::cout<<"timer overflow\n"; + CNT = 0; // Rollover main counter + + // 4. Repetition Counter & Update Event Logic + // The Update Event (UEV) is generated when the Repetition Counter underflows. + if (internal_rcr_cnt == 0) { + + // --- GENERATE UPDATE EVENT (UEV) --- + + // A. Update Shadow Registers from Preload Registers + active_PSC = PSC; + active_ARR = ARR; + active_RCR = RCR; + + // B. Set Update Interrupt Flag (UIF) + // Only if UDIS (Update Disable) is NOT set + if (!(CR1 & CR1_UDIS)) { + SR |= SR_UIF; + callback(); + } + + // C. Reload Repetition Counter with new value + internal_rcr_cnt = active_RCR; + + } else { + // No UEV yet, just decrement Repetition Counter + internal_rcr_cnt--; + } + } +} \ No newline at end of file From 53bddb9add05d9c1562a3fc56e8cd07d39eb1051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:54:44 +0100 Subject: [PATCH 030/281] reduce the number of ugly macros --- Inc/HALAL/Services/Time/Scheduler.hpp | 17 ++----- Src/HALAL/Services/Time/Scheduler.cpp | 64 ++++++++------------------- 2 files changed, 23 insertions(+), 58 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index cb06984aa..7306123c7 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -8,6 +8,8 @@ #ifndef TESTING_ENV #include "stm32h7xx_ll_tim.h" +#else + #include "MockedDrivers/ll_tim_interface.h" #endif #include #include @@ -20,22 +22,15 @@ # define SCHEDULER_TIMER_IDX 2 #endif -#ifndef TESTING_ENV #define glue_(a,b) a ## b #define glue(a,b) glue_(a,b) #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) // Used to reserve a TimerPeripheral +#ifndef TESTING_ENV #include "stm32h7xx_hal_tim.h" #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; -#else - - struct FakeTimer{ - int64_t CNT; - int64_t ARR; - }; - extern FakeTimer* Scheduler_global_timer; #endif struct Scheduler { using callback_t = void (*)(); @@ -60,11 +55,7 @@ struct Scheduler { // static void global_timer_callback(); // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise - #ifndef TESTING_ENV - static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; - #else - static void simulate_ticking(); - #endif + //static const uint32_t global_timer_base = SCHEDULER_TIMER_BASE; static void on_timer_update(); #ifndef TESTING_ENV diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9003bad12..1b782961e 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -15,17 +15,16 @@ #include #include -#ifndef TESTING_ENV - /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ - #define SCHEDULER_RCC_TIMER_ENABLE \ - glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) - #define SCHEDULER_GLOBAL_TIMER_IRQn \ - glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) - #define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ - extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) - - #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) -#endif + +/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ +#define SCHEDULER_RCC_TIMER_ENABLE \ + glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) +#define SCHEDULER_GLOBAL_TIMER_IRQn \ + glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) +#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ + extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) + +#define Scheduler_global_timer (SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; @@ -63,31 +62,15 @@ inline void Scheduler::pop_front() { // ---------------------------- inline void Scheduler::global_timer_disable() { -#ifndef TESTING_ENV LL_TIM_DisableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 &= ~TIM_CR1_CEN; -#endif } inline void Scheduler::global_timer_enable() { -#ifndef TESTING_ENV LL_TIM_EnableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 |= TIM_CR1_CEN; -#endif } // ---------------------------- -#ifdef TESTING_ENV - FakeTimer* Scheduler_global_timer; - void TimerCallback(); - void Scheduler::simulate_ticking(){ - Scheduler_global_timer->CNT++; - if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ - TimerCallback(); - std::cout<<"overflow\n"; - Scheduler_global_timer->CNT = -1; - } - } -#endif void Scheduler::start() { static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); @@ -101,6 +84,7 @@ void Scheduler::start() { TimerPeripheral perif_reserve(&SCHEDULER_HAL_TIM, std::move(init_data), (std::string)"timer2"); RCC->APB1LENR |= SCHEDULER_RCC_TIMER_ENABLE; +#endif Scheduler_global_timer->PSC = (uint16_t)prescaler; Scheduler_global_timer->ARR = 0; Scheduler_global_timer->DIER |= LL_TIM_DIER_UIE; @@ -111,28 +95,18 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ - NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); + //NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() - // Scheduler::global_timer_enable(); -#else - active_task_count_ = 0; - Scheduler_global_timer = new FakeTimer(); - Scheduler_global_timer->CNT = 0; - Scheduler_global_timer->ARR = 0; -#endif - Scheduler::schedule_next_interval(); + Scheduler::global_timer_enable(); + //Scheduler::schedule_next_interval(); } -#ifndef TESTING_ENV - SCHEDULER_GLOBAL_TIMER_CALLBACK() { - Scheduler_global_timer->SR &= ~TIM_SR_UIF; -#else - void TimerCallback(){ -#endif - - Scheduler::on_timer_update(); - } +SCHEDULER_GLOBAL_TIMER_CALLBACK() { + Scheduler_global_timer->SR &= ~TIM_SR_UIF; + std::cout<<"OVERFLOW\nn"; + Scheduler::on_timer_update(); +} void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); From b94ffbc6671ff90db2a9fad3f9c611aac26e7af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:55:23 +0100 Subject: [PATCH 031/281] compile the new mock file --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45d1e7b2f..372715e8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$:${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> ) From 51676f60ec0dc4fd6966cbc3f322a293403a1cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:55:32 +0100 Subject: [PATCH 032/281] update test --- Tests/Time/scheduler_test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index e090f3dfd..ab9f91f59 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -21,8 +21,10 @@ TEST(SchedulerTests, TaskExecution) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); constexpr int NUM_TICKS = 1'000'000; + TIM2_BASE->ARR = 500; + TIM2_BASE->generate_update(); for(int i = 0; i <= NUM_TICKS; i++){ - Scheduler::simulate_ticking(); + TIM2_BASE->simulate_ticking(); Scheduler::update(); } // one tick is 1us, and we register a task that executes every 10us From 4dcc328b8a3151b5b04f5b056789e9a535315270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:56:03 +0100 Subject: [PATCH 033/281] enable debugging of tests with TestMate C++ extension --- .vscode/settings.json | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d161326bb..a6efcd554 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,27 @@ "files.associations": { "mem.h": "c", "tinydir.h": "c", - "dirent.h": "c" - } + "dirent.h": "c", + "compare": "cpp", + "cstdint": "cpp", + "iostream": "cpp" + }, + "testMate.cpp.debug.configTemplate": { + "type": "cppdbg", + "MIMode": "gdb", + "program": "${exec}", + "args": "${args}", + "cwd": "${cwd}", + + "externalConsole": false, + // This setupCommands block often fixes generic "pause" issues in GDB + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] +} } \ No newline at end of file From d0d23e52221b5536584896e9aab3e8f23b1cefe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:54:20 +0100 Subject: [PATCH 034/281] feat: add DSB and ISB intructions in x86_64 --- Inc/MockedDrivers/compiler_specific.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index fdad61521..448976082 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -1,5 +1,5 @@ #pragma once - +#include /* This file contains implementatios or altername names for @@ -8,3 +8,6 @@ ARM GCC compiler that don't work in x86_64 */ #define __RBIT #define __CLZ __builtin_clz +#define __COMPILER_BARRIER() asm volatile("" ::: "memory") +#define __DSB() __asm__ volatile ("mfence" ::: "memory"); +#define __ISB() __asm__ volatile ("lfence" ::: "memory"); \ No newline at end of file From 884c2ab21ee9081ad0723353962c3c693f8bf7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:54:35 +0100 Subject: [PATCH 035/281] feat: add NVIC --- CMakeLists.txt | 2 +- Inc/MockedDrivers/NVIC.hpp | 184 +++++++++++++++++++++++++++++++++++++ Src/MockedDrivers/NVIC.cpp | 38 ++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 Inc/MockedDrivers/NVIC.hpp create mode 100644 Src/MockedDrivers/NVIC.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 372715e8a..84a2e7d1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,7 +222,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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 diff --git a/Inc/MockedDrivers/NVIC.hpp b/Inc/MockedDrivers/NVIC.hpp new file mode 100644 index 000000000..7e8b03234 --- /dev/null +++ b/Inc/MockedDrivers/NVIC.hpp @@ -0,0 +1,184 @@ +#pragma once + + +#include "MockedDrivers/common.hpp" +#include "MockedDrivers/compiler_specific.hpp" + +class NVIC_Type +{ + public: + volatile uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + volatile uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RESERVED1[24U]; + volatile uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + volatile uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + volatile uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + volatile uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + volatile uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +}; +enum IRQn_Type +{ +/****** Cortex-M Processor Exceptions Numbers *****************************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13, /*!< 3 Cortex-M Hard Fault Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M System Tick Interrupt */ +/****** STM32 specific Interrupt Numbers **********************************************************************/ + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt ( wwdg1_it, wwdg2_it) */ + PVD_AVD_IRQn = 1, /*!< PVD/AVD through EXTI Line detection Interrupt */ + TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ + DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ + DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ + DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ + DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ + DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ + DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ + ADC_IRQn = 18, /*!< ADC1 and ADC2 global Interrupts */ + FDCAN1_IT0_IRQn = 19, /*!< FDCAN1 Interrupt line 0 */ + FDCAN2_IT0_IRQn = 20, /*!< FDCAN2 Interrupt line 0 */ + FDCAN1_IT1_IRQn = 21, /*!< FDCAN1 Interrupt line 1 */ + FDCAN2_IT1_IRQn = 22, /*!< FDCAN2 Interrupt line 1 */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */ + TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ + TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ + TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ + TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ + TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ + DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ + FMC_IRQn = 48, /*!< FMC global Interrupt */ + SDMMC1_IRQn = 49, /*!< SDMMC1 global Interrupt */ + TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + UART4_IRQn = 52, /*!< UART4 global Interrupt */ + UART5_IRQn = 53, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn = 55, /*!< TIM7 global interrupt */ + DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ + DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ + DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ + DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ + DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ + ETH_IRQn = 61, /*!< Ethernet global Interrupt */ + ETH_WKUP_IRQn = 62, /*!< Ethernet Wakeup through EXTI line Interrupt */ + FDCAN_CAL_IRQn = 63, /*!< FDCAN Calibration unit Interrupt */ + DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ + DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ + DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ + USART6_IRQn = 71, /*!< USART6 global interrupt */ + I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ + I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ + OTG_HS_EP1_OUT_IRQn = 74, /*!< USB OTG HS End Point 1 Out global interrupt */ + OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */ + OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */ + OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */ + DCMI_PSSI_IRQn = 78, /*!< DCMI and PSSI global interrupt */ + RNG_IRQn = 80, /*!< RNG global interrupt */ + FPU_IRQn = 81, /*!< FPU global interrupt */ + UART7_IRQn = 82, /*!< UART7 global interrupt */ + UART8_IRQn = 83, /*!< UART8 global interrupt */ + SPI4_IRQn = 84, /*!< SPI4 global Interrupt */ + SPI5_IRQn = 85, /*!< SPI5 global Interrupt */ + SPI6_IRQn = 86, /*!< SPI6 global Interrupt */ + SAI1_IRQn = 87, /*!< SAI1 global Interrupt */ + LTDC_IRQn = 88, /*!< LTDC global Interrupt */ + LTDC_ER_IRQn = 89, /*!< LTDC Error global Interrupt */ + DMA2D_IRQn = 90, /*!< DMA2D global Interrupt */ + OCTOSPI1_IRQn = 92, /*!< OCTOSPI1 global interrupt */ + LPTIM1_IRQn = 93, /*!< LP TIM1 interrupt */ + CEC_IRQn = 94, /*!< HDMI-CEC global Interrupt */ + I2C4_EV_IRQn = 95, /*!< I2C4 Event Interrupt */ + I2C4_ER_IRQn = 96, /*!< I2C4 Error Interrupt */ + SPDIF_RX_IRQn = 97, /*!< SPDIF-RX global Interrupt */ + DMAMUX1_OVR_IRQn = 102, /*!= 0) + { + __COMPILER_BARRIER(); + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __COMPILER_BARRIER(); + } +} + +uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + +void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} \ No newline at end of file From 29aeea58bc2793e581f05a4bfffc9d6d0aed4dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:54:48 +0100 Subject: [PATCH 036/281] add NVIC logic --- Inc/MockedDrivers/mocked_ll_tim.hpp | 10 +++++++--- Src/MockedDrivers/mocked_ll_tim.cpp | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index b3dc95056..c235cd97e 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,11 +1,14 @@ #pragma once #include #include "MockedDrivers/common.hpp" +#include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/tim_register_definitions.hpp" + + class TIM_TypeDef{ public: - TIM_TypeDef(void(* irq_handler)(void)): - callback{irq_handler} + TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): + callback{irq_handler},irq_n{irq_n} {} void simulate_ticking(); void generate_update(); @@ -53,6 +56,7 @@ class TIM_TypeDef{ uint32_t active_ARR = 0; uint32_t active_RCR = 0; void(*callback)(); + IRQn_Type irq_n; }; #define DECLARE_TIMER(TIM_IDX) \ @@ -61,7 +65,7 @@ class TIM_TypeDef{ void TIM_IDX##_IRQHandler(void); \ } #define INSTANTIATE_TIMER(TIM_IDX) \ - TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler}; \ + TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler,TIM_IDX##_IRQn}; \ TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; DECLARE_TIMER(TIM1) diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index f0bf81beb..31f3d95ef 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -71,7 +71,9 @@ void TIM_TypeDef::simulate_ticking() { // Only if UDIS (Update Disable) is NOT set if (!(CR1 & CR1_UDIS)) { SR |= SR_UIF; - callback(); + if(NVIC_GetEnableIRQ(irq_n)){ + callback(); + } } // C. Reload Repetition Counter with new value From 0ad4c7b61afaf357b7f421ac447548205e82a420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:55:01 +0100 Subject: [PATCH 037/281] feat: use NVIC and remove print --- Src/HALAL/Services/Time/Scheduler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 1b782961e..3e03ad00f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -95,7 +95,7 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ - //NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); + NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() Scheduler::global_timer_enable(); @@ -104,7 +104,6 @@ void Scheduler::start() { SCHEDULER_GLOBAL_TIMER_CALLBACK() { Scheduler_global_timer->SR &= ~TIM_SR_UIF; - std::cout<<"OVERFLOW\nn"; Scheduler::on_timer_update(); } void Scheduler::update() { From 244eb9028f1c4f906eac12361a3d52be67aa0a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:05:54 +0100 Subject: [PATCH 038/281] fix: move extern"C" block to allow using --- Inc/MockedDrivers/ll_tim_interface.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/ll_tim_interface.h b/Inc/MockedDrivers/ll_tim_interface.h index dfb2587b9..7feab09f3 100644 --- a/Inc/MockedDrivers/ll_tim_interface.h +++ b/Inc/MockedDrivers/ll_tim_interface.h @@ -20,12 +20,13 @@ #ifndef __STM32H7xx_LL_TIM_H #define __STM32H7xx_LL_TIM_H +#include "mocked_ll_tim.hpp" + #ifdef __cplusplus extern "C" { #endif #include -#include "mocked_ll_tim.hpp" #define TIM1 From a3a4a784fdbc0e6dd9d35bff6f956968470b6466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:06:49 +0100 Subject: [PATCH 039/281] add Register class to allow for side effects --- Inc/MockedDrivers/Register.hpp | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Inc/MockedDrivers/Register.hpp diff --git a/Inc/MockedDrivers/Register.hpp b/Inc/MockedDrivers/Register.hpp new file mode 100644 index 000000000..e133993a7 --- /dev/null +++ b/Inc/MockedDrivers/Register.hpp @@ -0,0 +1,116 @@ +#pragma once +#include +#include + + +template +struct RegisterTraits { + static void write(uint32_t& target, uint32_t val) { + target = val; + } +}; + + +template +class RegisterBase { +public: + uint32_t reg = 0; + + RegisterBase() = default; + RegisterBase(uint32_t val) : reg(val) {} + + RegisterBase& operator=(uint32_t val) { + set(val); + return *this; + } + RegisterBase& operator+=(uint32_t val){ + set(reg+val); + return *this; + } + RegisterBase& operator-=(uint32_t val){ + set(reg-val); + return *this; + } + + RegisterBase& operator&=(uint32_t mask) { + set(reg & mask); + return *this; + } + + RegisterBase& operator|=(uint32_t mask) { + set(reg | mask); + return *this; + } + + RegisterBase& operator^=(uint32_t mask) { + set(reg ^ mask); + return *this; + } + RegisterBase& operator<<=(int shift) { + set(reg << shift); // Triggers Traits + return *this; + } + + RegisterBase& operator>>=(int shift) { + set(reg >> shift); // Triggers Traits + return *this; + } + + // --- Shift Read (Does NOT modify Register) --- + // Usage: uint32_t val = REG >> 4; + uint32_t operator<<(int shift) const { + return reg << shift; + } + + uint32_t operator>>(int shift) const { + return reg >> shift; + } + RegisterBase& operator++() { + set(reg + 1); + return *this; + } + + // --- Postfix Increment (REG++) --- + // int argument is a dummy flag for C++ to distinguish postfix + uint32_t operator++(int) { + uint32_t old_val = reg; + set(reg + 1); + return old_val; + } + + RegisterBase& operator--() { + set(reg - 1); + return *this; + } + + uint32_t operator--(int) { + uint32_t old_val = reg; + set(reg - 1); + return old_val; + } + /** + * COMPARISON + */ + bool operator!=(uint32_t val) const { + return reg != val; + } + bool operator==(uint32_t val) const { + return reg == val; + } + /** + * BITWISE COMPARISONS + */ + operator uint32_t(){ + return reg; + } + operator uint32_t() const volatile { + return reg; + } + operator uint32_t() const { + return reg; + } +private: + void set(uint32_t val) { + RegisterTraits::write(this->reg, val); + } +}; \ No newline at end of file From b09fe57a185a2e9f9e7d21bd321984014b1e6aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:07:26 +0100 Subject: [PATCH 040/281] feat: use newly created Register class for side effects, neat trick in CNT write --- Inc/MockedDrivers/mocked_ll_tim.hpp | 115 +++++++++++++++++++++------- Src/MockedDrivers/mocked_ll_tim.cpp | 58 ++++---------- 2 files changed, 103 insertions(+), 70 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index c235cd97e..ba103f1d4 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -3,6 +3,24 @@ #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/tim_register_definitions.hpp" +#include "MockedDrivers/Register.hpp" +#include +enum class TimRegs { + CR1, CR2, SMCR, DIER, SR, EGR, CCMR1, CCMR2, CCER, CNT, PSC, ARR, RCR, + CCR1, CCR2, CCR3, CCR4, BDTR, DCR, DMAR, CCMR3, CCR5, CCR6, AF1, AF2, TISEL +}; +using enum TimRegs; + + + +template +class TimerRegister : public RegisterBase { +public: + using RegisterBase::RegisterBase; + using RegisterBase::operator=; +}; + +static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); class TIM_TypeDef{ @@ -10,36 +28,34 @@ class TIM_TypeDef{ TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): callback{irq_handler},irq_n{irq_n} {} - void simulate_ticking(); void generate_update(); - volatile uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ - volatile uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ - volatile uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ - volatile uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ - volatile uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ - volatile uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ - volatile uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ - volatile uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ - volatile uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ - volatile uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ - volatile uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ - volatile uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ - volatile uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ - volatile uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ - volatile uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ - volatile uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ - volatile uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ - volatile uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ - volatile uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ - volatile uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ + TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ + TimerRegister SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + TimerRegister DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + TimerRegister SR; /*!< TIM status register, Address offset: 0x10 */ + TimerRegister EGR; /*!< TIM event generation register, Address offset: 0x14 */ + TimerRegister CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ + TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ + TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + TimerRegister CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + TimerRegister CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + TimerRegister CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + TimerRegister BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + TimerRegister DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + TimerRegister DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ uint32_t RESERVED1; /*!< Reserved, 0x50 */ - volatile uint32_t CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ - volatile uint32_t CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ - volatile uint32_t CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ - volatile uint32_t AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ - volatile uint32_t AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ - volatile uint32_t TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ -private: + TimerRegister CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ + TimerRegister CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ + TimerRegister CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ + TimerRegister AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + TimerRegister AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + TimerRegister TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ // ======================================================================== // Internal Hardware State (Shadow Registers & Hidden Counters) // ======================================================================== @@ -55,9 +71,52 @@ class TIM_TypeDef{ uint32_t active_PSC = 0; uint32_t active_ARR = 0; uint32_t active_RCR = 0; + void(*callback)(); IRQn_Type irq_n; + bool check_CNT_increase_preconditions(){ + // Bit definitions for clarity + const uint32_t CR1_CEN = (1U << 0); // Counter Enable + + // 1. Check if Counter is Enabled + if (!(CR1 & CR1_CEN)) { + std::cout<<"TIMER IS NOT ENABLED!!\n"; + return false; + } + // 2. Prescaler Logic + // The internal prescaler counts from 0 up to active_PSC. + // We check if we reached the limit *before* incrementing to ensure accurate + // behavior for PSC=0 or PSC=1. + bool main_counter_tick = false; + + if (internal_psc_cnt >= active_PSC) { + internal_psc_cnt = 0; // Rollover + main_counter_tick = true; + } else { + internal_psc_cnt++; // Increment + } + + // If prescaler didn't overflow, the main counter doesn't move. + if (!main_counter_tick) { + return false; + } + return true; + } }; +static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); +void simulate_ticks(TIM_TypeDef* tim); + +template<> +struct RegisterTraits { + static void write(uint32_t& target, uint32_t val) { + TIM_TypeDef* timer = (TIM_TypeDef*)(((uint8_t*)&target)-offsetof(TIM_TypeDef, CNT)); + target = val; + if(val != 0 && timer->check_CNT_increase_preconditions()){ + simulate_ticks(timer); + } + } +}; + #define DECLARE_TIMER(TIM_IDX) \ extern TIM_TypeDef* TIM_IDX##_BASE; \ diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index 31f3d95ef..4f4ceb413 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -3,6 +3,7 @@ #include INSTANTIATE_TIMER(TIM2) + void TIM_TypeDef::generate_update() { active_PSC = PSC; active_ARR = ARR; @@ -12,76 +13,49 @@ void TIM_TypeDef::generate_update() { CNT = 0; // Usually UEV also resets CNT unless configured otherwise SR &= ~(1U << 0); // Clear UIF if needed, or set it depending on CR1 } -void TIM_TypeDef::simulate_ticking() { +void simulate_ticks(TIM_TypeDef* tim){ + // Bit definitions for clarity - const uint32_t CR1_CEN = (1U << 0); // Counter Enable const uint32_t CR1_UDIS = (1U << 1); // Update Disable const uint32_t CR1_ARPE = (1U << 7); // Auto-Reload Preload Enable const uint32_t SR_UIF = (1U << 0); // Update Interrupt Flag - // 1. Check if Counter is Enabled - if (!(CR1 & CR1_CEN)) { - std::cout<<"TIMER IS NOT ENABLED!!\n"; - return; - } - - // 2. Prescaler Logic - // The internal prescaler counts from 0 up to active_PSC. - // We check if we reached the limit *before* incrementing to ensure accurate - // behavior for PSC=0 or PSC=1. - bool main_counter_tick = false; - - if (internal_psc_cnt >= active_PSC) { - internal_psc_cnt = 0; // Rollover - main_counter_tick = true; - } else { - internal_psc_cnt++; // Increment - } - - // If prescaler didn't overflow, the main counter doesn't move. - if (!main_counter_tick) { - return; - } - - // 3. Main Counter Logic - CNT +=1; - // Determine the current Auto-Reload limit. // If ARPE is set, use the buffered (shadow) value. // If ARPE is clear, use the immediate register value. - uint32_t current_limit = (CR1 & CR1_ARPE) ? active_ARR : ARR; + uint32_t current_limit = (tim->CR1 & CR1_ARPE) ? tim->active_ARR : tim->ARR.reg; // Check for Overflow - if (CNT > current_limit) { + if (tim->CNT > current_limit) { std::cout<<"timer overflow\n"; - CNT = 0; // Rollover main counter + tim->CNT = 0; // Rollover main counter // 4. Repetition Counter & Update Event Logic // The Update Event (UEV) is generated when the Repetition Counter underflows. - if (internal_rcr_cnt == 0) { + if (tim->internal_rcr_cnt == 0) { // --- GENERATE UPDATE EVENT (UEV) --- // A. Update Shadow Registers from Preload Registers - active_PSC = PSC; - active_ARR = ARR; - active_RCR = RCR; + tim->active_PSC = tim->PSC; + tim->active_ARR = tim->ARR; + tim->active_RCR = tim->RCR; // B. Set Update Interrupt Flag (UIF) // Only if UDIS (Update Disable) is NOT set - if (!(CR1 & CR1_UDIS)) { - SR |= SR_UIF; - if(NVIC_GetEnableIRQ(irq_n)){ - callback(); + if (!(tim->CR1 & CR1_UDIS)) { + tim->SR |= SR_UIF; + if(NVIC_GetEnableIRQ(tim->irq_n)){ + tim->callback(); } } // C. Reload Repetition Counter with new value - internal_rcr_cnt = active_RCR; + tim->internal_rcr_cnt = tim->active_RCR; } else { // No UEV yet, just decrement Repetition Counter - internal_rcr_cnt--; + tim->internal_rcr_cnt--; } } } \ No newline at end of file From c97c4a264f6316d2fafb6a05aabebf6559ff07be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:07:50 +0100 Subject: [PATCH 041/281] feat: be as realistic as possible in test, by using CNT++ --- Tests/Time/scheduler_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index ab9f91f59..dd61a421e 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -24,7 +24,7 @@ TEST(SchedulerTests, TaskExecution) { TIM2_BASE->ARR = 500; TIM2_BASE->generate_update(); for(int i = 0; i <= NUM_TICKS; i++){ - TIM2_BASE->simulate_ticking(); + TIM2_BASE->CNT++; Scheduler::update(); } // one tick is 1us, and we register a task that executes every 10us From eb8094c403a3b1cde76bde0bd6f256443955eaf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:09:41 +0100 Subject: [PATCH 042/281] feat: remove unnecessary include --- Src/HALAL/Services/Time/Scheduler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 3e03ad00f..76b2c5c3f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -9,8 +9,6 @@ #ifndef TESTING_ENV // This is needed to register a TimerPeripheral #include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" -#else - #include #endif #include #include From f763f0e77c1ed690f5843fcf21ef512886a7cb64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:17:39 +0100 Subject: [PATCH 043/281] feat: add an __RBIT impl for x86_64 --- Inc/MockedDrivers/compiler_specific.hpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index 448976082..a1a29cd3c 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -6,7 +6,29 @@ This file contains implementatios or altername names for ARM GCC compiler that don't work in x86_64 */ -#define __RBIT +static inline uint32_t __RBIT(uint32_t val) { + // 1. Hardware Byte Swap (Optimization: handles the large movements) + // MSVC uses _byteswap_ulong, GCC/Clang uses __builtin_bswap32 +#if defined(_MSC_VER) + val = _byteswap_ulong(val); +#else + val = __builtin_bswap32(val); +#endif + + // 2. Swap Nibbles (within bytes) + // 0xF0 = 1111 0000 -> shifts to 0000 1111 + val = ((val & 0xF0F0F0F0) >> 4) | ((val & 0x0F0F0F0F) << 4); + + // 3. Swap Bit-Pairs (within nibbles) + // 0xCC = 1100 1100 -> shifts to 0011 0011 + val = ((val & 0xCCCCCCCC) >> 2) | ((val & 0x33333333) << 2); + + // 4. Swap Single Bits (within pairs) + // 0xAA = 1010 1010 -> shifts to 0101 0101 + val = ((val & 0xAAAAAAAA) >> 1) | ((val & 0x55555555) << 1); + + return val; +} #define __CLZ __builtin_clz #define __COMPILER_BARRIER() asm volatile("" ::: "memory") #define __DSB() __asm__ volatile ("mfence" ::: "memory"); From 49e4f50bbbe58258cf804292a9c5c6a38c53b941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:36:39 +0100 Subject: [PATCH 044/281] fix: compilation --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 76b2c5c3f..869672516 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -22,7 +22,7 @@ #define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) -#define Scheduler_global_timer (SCHEDULER_TIMER_BASE) +#define Scheduler_global_timer ((TIM_TypeDef*)SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; From cc4d72b03fd24735e99c014d8814fe838d6ff430 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 4 Dec 2025 15:44:45 +0100 Subject: [PATCH 045/281] fix: used_bitmap_ -> free_bitmap_ --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index d080bb181..ef3f976fc 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -74,7 +74,7 @@ struct Scheduler { static std::size_t active_task_count_; static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); static uint32_t ready_bitmap_; - static uint32_t used_bitmap_; + static uint32_t free_bitmap_; static uint64_t global_tick_us_; static uint64_t current_interval_us_; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 7b056a2eb..a457612ed 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -32,7 +32,7 @@ uint64_t Scheduler::sorted_task_ids_ = 0; std::size_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; -uint32_t Scheduler::used_bitmap_{0}; +uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; uint64_t Scheduler::current_interval_us_{0}; @@ -125,20 +125,19 @@ inline uint8_t Scheduler::allocate_slot() { * clz(0) = 32 -> 32 - clz(0) = 0 * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks */ - uint32_t idx = 32 - __builtin_clz(~Scheduler::used_bitmap_); + uint32_t idx = __builtin_ffs(~Scheduler::free_bitmap_) - 1; if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); Scheduler::active_task_count_++; - Scheduler::used_bitmap_ |= (1UL << idx); + Scheduler::free_bitmap_ &= ~(1UL << idx); return static_cast(idx); } inline void Scheduler::release_slot(uint8_t id) { // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert if(id >= kMaxTasks) [[unlikely]] return; - uint32_t clearmask = ~(1u << id); - ready_bitmap_ &= clearmask; - used_bitmap_ &= clearmask; + ready_bitmap_ &= ~(1u << id); + free_bitmap_ |= (1u << id); Scheduler::active_task_count_--; } @@ -282,7 +281,7 @@ uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repea bool Scheduler::unregister_task(uint8_t id) { if (id >= kMaxTasks) return false; - if (!(used_bitmap_ & (1UL << id))) return false; + if (free_bitmap_ & (1UL << id)) return false; remove_sorted(id); release_slot(id); From 51f073c285b7639ecc0fdfe7cc9c603c40b2690c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 17:11:05 +0100 Subject: [PATCH 046/281] Added tests check in CI/CD --- .github/workflows/tests.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..64ae8a43f --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: Run tests + +on: + workflow_dispatch: + pull_request: + branches: [ development ] + +jobs: + tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake ninja-build build-essential + + - name: Configure (CMake) + run: | + cmake --preset simulator + + - name: Build + run: | + cmake --build build/tests + + - name: Run tests (ctest) + working-directory: build/tests + run: | + ctest --output-on-failure From 74e86d34c04acabe5e97b9419d60e47e24dda9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 17:13:59 +0100 Subject: [PATCH 047/281] fix(ci/cd): output folder --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 64ae8a43f..d3150e416 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,9 +24,9 @@ jobs: - name: Build run: | - cmake --build build/tests + cmake --build out/build/simulator - name: Run tests (ctest) - working-directory: build/tests + working-directory: out/build/simulator run: | ctest --output-on-failure From 292cc08e5f76251b3b6c86bf94cda03094e8306b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 18:08:29 +0100 Subject: [PATCH 048/281] Added ARM specific instructions to be able to compile in ARM hosts (Mac) --- Inc/MockedDrivers/compiler_specific.hpp | 44 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index a1a29cd3c..18fd8d437 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -1,11 +1,11 @@ #pragma once #include -/* -This file contains implementatios or altername names for -ARM GCC compiler that don't work in x86_64 +/* + * This file contains implementations or alternate names for + * ARM GCC intrinsics that don't work on x86_64 / host platforms. + */ -*/ static inline uint32_t __RBIT(uint32_t val) { // 1. Hardware Byte Swap (Optimization: handles the large movements) // MSVC uses _byteswap_ulong, GCC/Clang uses __builtin_bswap32 @@ -17,19 +17,39 @@ static inline uint32_t __RBIT(uint32_t val) { // 2. Swap Nibbles (within bytes) // 0xF0 = 1111 0000 -> shifts to 0000 1111 - val = ((val & 0xF0F0F0F0) >> 4) | ((val & 0x0F0F0F0F) << 4); + val = ((val & 0xF0F0F0F0u) >> 4) | ((val & 0x0F0F0F0Fu) << 4); // 3. Swap Bit-Pairs (within nibbles) // 0xCC = 1100 1100 -> shifts to 0011 0011 - val = ((val & 0xCCCCCCCC) >> 2) | ((val & 0x33333333) << 2); + val = ((val & 0xCCCCCCCCu) >> 2) | ((val & 0x33333333u) << 2); // 4. Swap Single Bits (within pairs) // 0xAA = 1010 1010 -> shifts to 0101 0101 - val = ((val & 0xAAAAAAAA) >> 1) | ((val & 0x55555555) << 1); + val = ((val & 0xAAAAAAAAu) >> 1) | ((val & 0x55555555u) << 1); return val; -} -#define __CLZ __builtin_clz -#define __COMPILER_BARRIER() asm volatile("" ::: "memory") -#define __DSB() __asm__ volatile ("mfence" ::: "memory"); -#define __ISB() __asm__ volatile ("lfence" ::: "memory"); \ No newline at end of file +} + +#define __CLZ __builtin_clz +#define __COMPILER_BARRIER() asm volatile("" ::: "memory") + +// Architecture-specific definitions for barrier intrinsics used in mocks +#if defined(__x86_64__) || defined(_M_X64) + +// Host x86_64 +# define __DSB() __asm__ volatile("mfence" ::: "memory") +# define __ISB() __asm__ volatile("lfence" ::: "memory") + +#elif defined(__aarch64__) || defined(_M_ARM64) + +// Host ARM64 +# define __DSB() __asm__ volatile("dmb ish" ::: "memory") +# define __ISB() __asm__ volatile("isb" ::: "memory") + +#else + +// Any other host architecture: compiler barrier only +# define __DSB() __COMPILER_BARRIER() +# define __ISB() __COMPILER_BARRIER() + +#endif \ No newline at end of file From 44e8d8c0b72f0c99b218fc73a8b17fcc5f32abb6 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:07:17 +0100 Subject: [PATCH 049/281] Fix: compiler barrier for msvc, hopefully works --- Inc/MockedDrivers/compiler_specific.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index 18fd8d437..405e03d10 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -31,6 +31,15 @@ static inline uint32_t __RBIT(uint32_t val) { } #define __CLZ __builtin_clz + +#if defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__) +void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) +#define __COMPILER_BARRIER() _ReadWriteBarrier() +#define __DSB() __COMPILER_BARRIER() +#define __ISB() __COMPILER_BARRIER() +#else + #define __COMPILER_BARRIER() asm volatile("" ::: "memory") // Architecture-specific definitions for barrier intrinsics used in mocks @@ -52,4 +61,5 @@ static inline uint32_t __RBIT(uint32_t val) { # define __DSB() __COMPILER_BARRIER() # define __ISB() __COMPILER_BARRIER() +#endif #endif \ No newline at end of file From a3fc792b0d69bf0faf9a6706f4278ebc080b824e Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:13:13 +0100 Subject: [PATCH 050/281] Fix: Try to fix -Wchanges-meaning warning --- Inc/MockedDrivers/mocked_ll_tim.hpp | 74 +++++++++++++++-------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index ba103f1d4..fffe2d5b6 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -5,22 +5,24 @@ #include "MockedDrivers/tim_register_definitions.hpp" #include "MockedDrivers/Register.hpp" #include -enum class TimRegs { - CR1, CR2, SMCR, DIER, SR, EGR, CCMR1, CCMR2, CCER, CNT, PSC, ARR, RCR, - CCR1, CCR2, CCR3, CCR4, BDTR, DCR, DMAR, CCMR3, CCR5, CCR6, AF1, AF2, TISEL +enum class TimReg { + Reg_CR1, Reg_CR2, Reg_SMCR, Reg_DIER, Reg_SR, Reg_EGR, + Reg_CCMR1, Reg_CCMR2, Reg_CCER, Reg_CNT, Reg_PSC, Reg_ARR, Reg_RCR, + Reg_CCR1, Reg_CCR2, Reg_CCR3, Reg_CCR4, Reg_BDTR, Reg_DCR, + Reg_DMAR, Reg_CCMR3, Reg_CCR5, Reg_CCR6, Reg_AF1, Reg_AF2, Reg_TISEL }; -using enum TimRegs; +using enum TimReg; -template -class TimerRegister : public RegisterBase { +template +class TimerRegister : public RegisterBase { public: - using RegisterBase::RegisterBase; - using RegisterBase::operator=; + using RegisterBase::RegisterBase; + using RegisterBase::operator=; }; -static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); +static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); class TIM_TypeDef{ @@ -29,33 +31,33 @@ class TIM_TypeDef{ callback{irq_handler},irq_n{irq_n} {} void generate_update(); - TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ - TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ - TimerRegister SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ - TimerRegister DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ - TimerRegister SR; /*!< TIM status register, Address offset: 0x10 */ - TimerRegister EGR; /*!< TIM event generation register, Address offset: 0x14 */ - TimerRegister CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ - TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ - TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ - TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ - TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ - TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ - TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ - TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ - TimerRegister CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ - TimerRegister CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ - TimerRegister CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ - TimerRegister BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ - TimerRegister DCR; /*!< TIM DMA control register, Address offset: 0x48 */ - TimerRegister DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ + TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ + TimerRegister SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + TimerRegister DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + TimerRegister SR; /*!< TIM status register, Address offset: 0x10 */ + TimerRegister EGR; /*!< TIM event generation register, Address offset: 0x14 */ + TimerRegister CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ + TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ + TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + TimerRegister CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + TimerRegister CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + TimerRegister CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + TimerRegister BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + TimerRegister DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + TimerRegister DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ uint32_t RESERVED1; /*!< Reserved, 0x50 */ - TimerRegister CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ - TimerRegister CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ - TimerRegister CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ - TimerRegister AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ - TimerRegister AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ - TimerRegister TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ + TimerRegister CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ + TimerRegister CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ + TimerRegister CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ + TimerRegister AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + TimerRegister AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + TimerRegister TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ // ======================================================================== // Internal Hardware State (Shadow Registers & Hidden Counters) // ======================================================================== @@ -103,7 +105,7 @@ class TIM_TypeDef{ return true; } }; -static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); +static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); void simulate_ticks(TIM_TypeDef* tim); template<> From 869883c9753228595720ef7b7227cb6185b33cd4 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:16:36 +0100 Subject: [PATCH 051/281] Fix typo --- Inc/MockedDrivers/mocked_ll_tim.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index fffe2d5b6..41897a666 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -109,7 +109,7 @@ static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); void simulate_ticks(TIM_TypeDef* tim); template<> -struct RegisterTraits { +struct RegisterTraits { static void write(uint32_t& target, uint32_t val) { TIM_TypeDef* timer = (TIM_TypeDef*)(((uint8_t*)&target)-offsetof(TIM_TypeDef, CNT)); target = val; From 7e5fe46e683810720bcbd469dfbfaf3f156e7a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20L=C3=B3pez?= <120128034+victor-Lopez25@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:25:41 +0100 Subject: [PATCH 052/281] Update Inc/MockedDrivers/common.hpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#discussion_r2599324887 Co-authored-by: Jorge Sáez <125664643+jorgesg82@users.noreply.github.com> --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index b7f33c2bc..da459f1f5 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -41,7 +41,7 @@ typedef enum #define CLEAR_REG(REG) ((REG) = (0x0)) -#define WRITE_REG(REG, VAL) ((REG) = (VAL)) +#define WRITE_REG(REG, VAL) ((REG) = static_cast(VAL)) #define READ_REG(REG) ((REG)) From 7e42ef9fb65587af61c322600db3dbcb9a3b96c0 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:31:31 +0100 Subject: [PATCH 053/281] Actually do the change github didn't do :/ --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index da459f1f5..40fcf626a 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -35,7 +35,7 @@ typedef enum #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) &= = static_cast(static_cast(REG) & ~static_cast(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) From 712bd60e3536f0e47f461abb46dc457f1900ecc0 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:56:07 +0100 Subject: [PATCH 054/281] Fix typo p2 --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 40fcf626a..bde9174fb 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -35,7 +35,7 @@ typedef enum #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) &= = static_cast(static_cast(REG) & ~static_cast(BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) From 82acd27921d688e4e8aa624071cb834640571c49 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:57:26 +0100 Subject: [PATCH 055/281] Fix another typo --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index bde9174fb..e94fd853a 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -35,7 +35,7 @@ typedef enum #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT))) #define READ_BIT(REG, BIT) ((REG) & (BIT)) From c0d563973855877fda16012cb5bcce16f90cde42 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 21:02:03 +0100 Subject: [PATCH 056/281] Fix unsigned long - 64bit when testing using LL functions --- Src/HALAL/Services/Time/Scheduler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4767f6934..199fa559f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -94,14 +94,15 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); - Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ + LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() Scheduler::global_timer_enable(); //Scheduler::schedule_next_interval(); } SCHEDULER_GLOBAL_TIMER_CALLBACK() { - Scheduler_global_timer->SR &= ~TIM_SR_UIF; + /* clear update interrupt flag */ + LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); Scheduler::on_timer_update(); } void Scheduler::update() { From 91a3b75b329baec4c2d4bb1fa7bcdccf4db438e7 Mon Sep 17 00:00:00 2001 From: StefanCostea Date: Sun, 7 Dec 2025 00:45:00 +0100 Subject: [PATCH 057/281] Minor fixes to scheduler Rebased from remotes/origin/MockTim --- Inc/MockedDrivers/common.hpp | 10 ++-- Src/HALAL/Services/Time/Scheduler.cpp | 14 +++-- Tests/Time/scheduler_test.cpp | 83 +++++++++++++++++++++++---- 3 files changed, 86 insertions(+), 21 deletions(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index e94fd853a..80f9d3c91 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -45,7 +45,7 @@ typedef enum #define READ_REG(REG) ((REG)) -#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) @@ -65,7 +65,7 @@ typedef enum do { \ uint32_t val; \ do { \ - val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \ + val = __LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(BIT); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) @@ -74,7 +74,7 @@ typedef enum do { \ uint32_t val; \ do { \ - val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(CLEARMSK)) | (SETMASK); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) @@ -92,7 +92,7 @@ typedef enum do { \ uint16_t val; \ do { \ - val = __LDREXH((__IO uint16_t *)&(REG)) & ~(BIT); \ + val = __LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(BIT); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) @@ -101,6 +101,6 @@ typedef enum do { \ uint16_t val; \ do { \ - val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(CLEARMSK)) | (SETMASK); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 199fa559f..eb90bdb2f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -40,7 +40,7 @@ uint64_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; uint32_t shift = (idx & 7) << 2; - return (((uint32_t*)sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; + return (((uint32_t*)&sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; } inline void Scheduler::set_at(uint8_t idx, uint8_t id) { uint32_t shift = idx*4; @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)sorted_task_ids_)[0] & 0xF; + return ((uint32_t*)&sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 @@ -94,17 +94,17 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); - LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); + CLEAR_BIT(Scheduler_global_timer->SR, LL_TIM_SR_UIF); /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() Scheduler::global_timer_enable(); //Scheduler::schedule_next_interval(); } -SCHEDULER_GLOBAL_TIMER_CALLBACK() { - /* clear update interrupt flag */ - LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); +SCHEDULER_GLOBAL_TIMER_CALLBACK() { + CLEAR_BIT(Scheduler_global_timer->SR, TIM_SR_UIF); Scheduler::on_timer_update(); } + void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); @@ -183,6 +183,7 @@ void Scheduler::insert_sorted(uint8_t id) { } sorted_task_ids_ = ((uint64_t)hi << 32) | lo; + active_task_count_++; } void Scheduler::remove_sorted(uint8_t id) { @@ -215,6 +216,7 @@ void Scheduler::remove_sorted(uint8_t id) { // Remove element (lower part | higher pushing nibble out of mask) Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); + active_task_count_--; } void Scheduler::schedule_next_interval() { diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index dd61a421e..76d21e778 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -2,32 +2,95 @@ #include #include #include "HALAL/Services/Time/Scheduler.hpp" + int count = 0; void fake_workload(){ count++; } -TEST(SchedulerTests, UsedBitmap) { +class SchedulerTests : public ::testing::Test { +protected: + void SetUp() override { + Scheduler::active_task_count_ = 0; + Scheduler::used_bitmap_ = 0; + Scheduler::ready_bitmap_ = 0; + Scheduler::sorted_task_ids_ = 0; + Scheduler::global_tick_us_ = 0; + Scheduler::current_interval_us_ = 0; + + // Reset global callback task count + count = 0; + + // Reset Timer + TIM2_BASE->CNT = 0; + TIM2_BASE->ARR = 0; + TIM2_BASE->SR = 0; + TIM2_BASE->CR1 = 0; + TIM2_BASE->DIER = 0; + } +}; + +TEST_F(SchedulerTests, UsedBitmap) { Scheduler::register_task(10,&fake_workload); EXPECT_EQ(Scheduler::used_bitmap_,1); } -TEST(SchedulerTests, TaskRegistration) { +TEST_F(SchedulerTests, TaskRegistration) { Scheduler::register_task(10,&fake_workload); EXPECT_EQ(Scheduler::tasks_[0].callback,fake_workload); } -TEST(SchedulerTests, TaskExecution) { +TEST_F(SchedulerTests, TaskExecutionShort) { + Scheduler::register_task(10,&fake_workload); + Scheduler::start(); + // TIM2_BASE->ARR = 500; + // TIM2_BASE->generate_update(); + + constexpr int NUM_TICKS = 1'000; + for(int i = 0; i < NUM_TICKS; i++){ + TIM2_BASE->CNT++; + Scheduler::update(); + } + // 1000 ticks / 10 ticks/task = 100 executions. + EXPECT_EQ(count, 100); +} + +TEST_F(SchedulerTests, TaskExecutionLong) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); + // TIM2_BASE->ARR = 500; + // TIM2_BASE->generate_update(); + constexpr int NUM_TICKS = 1'000'000; - TIM2_BASE->ARR = 500; - TIM2_BASE->generate_update(); - for(int i = 0; i <= NUM_TICKS; i++){ + for(int i = 0; i < NUM_TICKS; i++){ TIM2_BASE->CNT++; Scheduler::update(); } - // one tick is 1us, and we register a task that executes every 10us - // thus it should execute NUM_TICKS/10 - EXPECT_EQ(count,100'000); -} \ No newline at end of file + EXPECT_EQ(count, 100'000); +} + +TEST_F(SchedulerTests, SetTimeout) { + Scheduler::set_timeout(10, &fake_workload); + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++){ + TIM2_BASE->CNT++; + Scheduler::update(); + } + EXPECT_EQ(count, 1); +} + +TEST_F(SchedulerTests, GlobalTickOverflow) { + Scheduler::global_tick_us_ = 0xFFFFFFF0ULL; // Near 32-bit max + Scheduler::register_task(20, &fake_workload); + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++){ + TIM2_BASE->CNT++; + Scheduler::update(); + } + // 100 ticks /20 ticks/task = 5 executions. + EXPECT_EQ(count, 5); +} From 1ab3d5c9b277ad27e9139cd5404238de1483e530 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:45:39 +0100 Subject: [PATCH 058/281] Fix: uint32_t* cast of a word instead of the ptr --- Src/HALAL/Services/Time/Scheduler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 199fa559f..eca2d7b98 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -40,7 +40,7 @@ uint64_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; uint32_t shift = (idx & 7) << 2; - return (((uint32_t*)sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; + return (((uint32_t*)&sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; } inline void Scheduler::set_at(uint8_t idx, uint8_t id) { uint32_t shift = idx*4; @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)sorted_task_ids_)[0] & 0xF; + return ((uint32_t*)&sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From 069a28847046c6f79a80d52c3a13ff00e8a86a18 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:48:14 +0100 Subject: [PATCH 059/281] Fix: remove active_task_count_ decrement in pop_front() https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#discussion_r2601565840 --- Src/HALAL/Services/Time/Scheduler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index eb90bdb2f..fb7f809ce 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -53,7 +53,6 @@ inline uint8_t Scheduler::front_id() { } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 - Scheduler::active_task_count_--; Scheduler::sorted_task_ids_ >>= 4; } From fb5b90a608157e1e8fac6a25894fa5d5f16169d8 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:53:15 +0100 Subject: [PATCH 060/281] Try fix Wstrict-aliasing in front_id --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index fb7f809ce..af2e12a8b 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)&sorted_task_ids_)[0] & 0xF; + return ((uint32_t*)(void*)&sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From 065cdad1e41087a2b8b1a28f685e55b1efb54172 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:57:24 +0100 Subject: [PATCH 061/281] Try fix Wstrict-aliasing again --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index af2e12a8b..ea23e5e59 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)(void*)&sorted_task_ids_)[0] & 0xF; + return *((uint8_t*)&sorted_task_ids_) & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From 11a3aabc3d7e728af89725e1c04dae6b1f318e7f Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 14:43:59 +0100 Subject: [PATCH 062/281] Fix typo in allocate_slot --- Src/HALAL/Services/Time/Scheduler.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ea23e5e59..4aead65f8 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -121,11 +121,7 @@ inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } // void Scheduler::global_timer_callback() { on_timer_update(); } inline uint8_t Scheduler::allocate_slot() { - /* https://developer.arm.com/documentation/dui0204/j/arm-and-thumb-instructions/general-data-processing-instructions/clz - * clz(0) = 32 -> 32 - clz(0) = 0 - * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks - */ - uint32_t idx = __builtin_ffs(~Scheduler::free_bitmap_) - 1; + uint32_t idx = __builtin_ffs(Scheduler::free_bitmap_) - 1; if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); Scheduler::active_task_count_++; From dee98799d58fc944634b8d7c4af6f9a138a54305 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 14:47:37 +0100 Subject: [PATCH 063/281] fix: test UsedBitmap -> FreeBitmap --- Tests/Time/scheduler_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 76d21e778..4b4fbddfb 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -30,9 +30,9 @@ class SchedulerTests : public ::testing::Test { } }; -TEST_F(SchedulerTests, UsedBitmap) { +TEST_F(SchedulerTests, FreeBitmap) { Scheduler::register_task(10,&fake_workload); - EXPECT_EQ(Scheduler::used_bitmap_,1); + EXPECT_EQ(Scheduler::free_bitmap_, 0xFFFF'FFFE); } TEST_F(SchedulerTests, TaskRegistration) { From 8038b7bbcc57a9fa4224249802a6b9e7fd6d307f Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 14:53:24 +0100 Subject: [PATCH 064/281] used_bitmap_ -> free_bitmap_ in test part 2 --- Tests/Time/scheduler_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 4b4fbddfb..5062311d4 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -12,7 +12,7 @@ class SchedulerTests : public ::testing::Test { protected: void SetUp() override { Scheduler::active_task_count_ = 0; - Scheduler::used_bitmap_ = 0; + Scheduler::free_bitmap_ = 0xFFFF'FFFF; Scheduler::ready_bitmap_ = 0; Scheduler::sorted_task_ids_ = 0; Scheduler::global_tick_us_ = 0; From e7fdc30af0369d6b5941a28bbaa818e04115f13e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Tue, 9 Dec 2025 19:35:21 +0100 Subject: [PATCH 065/281] fixed tests discovery --- CMakeLists.txt | 3 +++ Tests/CMakeLists.txt | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a2e7d1f..c814f9a96 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) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 38eb7334c..c06522432 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,32 +1,36 @@ -cmake_minimum_required(VERSION 3.14) if(DEFINED STLIB_NAME_SUFFIX) set(STLIB_TEST_EXECUTABLE st-lib-${STLIB_NAME_SUFFIX}-test) else() set(STLIB_TEST_EXECUTABLE st-lib-test) endif() -project( ${STLIB_TEST_EXECUTABLE}) + 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}/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} GTest::gtest_main ${STLIB_LIBRARY} ) + if(MINGW OR CYGWIN) - # Force static linking of libgcc and libstdc++ to avoid DLL version mismatches target_link_options(${STLIB_TEST_EXECUTABLE} PRIVATE -static) endif() @@ -43,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 78ffa8230a673546c0e8cefc00543f322021d583 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 23:04:15 +0100 Subject: [PATCH 066/281] fix: set_timeout() test --- Src/HALAL/Services/Time/Scheduler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4aead65f8..92402ac54 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -53,6 +53,7 @@ inline uint8_t Scheduler::front_id() { } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 + Scheduler::active_task_count_--; Scheduler::sorted_task_ids_ >>= 4; } @@ -124,7 +125,6 @@ inline uint8_t Scheduler::allocate_slot() { uint32_t idx = __builtin_ffs(Scheduler::free_bitmap_) - 1; if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); - Scheduler::active_task_count_++; Scheduler::free_bitmap_ &= ~(1UL << idx); return static_cast(idx); } @@ -134,7 +134,6 @@ inline void Scheduler::release_slot(uint8_t id) { if(id >= kMaxTasks) [[unlikely]] return; ready_bitmap_ &= ~(1u << id); free_bitmap_ |= (1u << id); - Scheduler::active_task_count_--; } void Scheduler::insert_sorted(uint8_t id) { From 26a69f2fee497848e28fdf42430626a2d60881b1 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 22:53:59 +0100 Subject: [PATCH 067/281] Add a test, fix the error (kind of) --- Inc/HALAL/Services/Time/Scheduler.hpp | 11 ++++++++++- Tests/Time/scheduler_test.cpp | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 5b3a54152..47c3cb3f3 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -50,7 +50,16 @@ struct Scheduler { if(microseconds == 0) [[unlikely]] microseconds = 1; return register_task(microseconds, func, false); } - static inline void cancel_timeout(uint8_t id) { unregister_task(id); } + static inline void cancel_timeout(uint8_t id) { + /* NOTE: This does not fix this case: + 1. id = set_timeout(x, func) + 2. timeout ends, func gets called and removed internally + 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 + 4. clear_timeout(id) -> will remove the second timeout + */ + if(!tasks_[id].repeating) return; + unregister_task(id); + } // static void global_timer_callback(); diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 5062311d4..7dc8f9fb7 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -94,3 +94,22 @@ TEST_F(SchedulerTests, GlobalTickOverflow) { // 100 ticks /20 ticks/task = 5 executions. EXPECT_EQ(count, 5); } + +TEST_F(SchedulerTests, TimeoutClearAddTask) { + uint8_t timeout_id = Scheduler::set_timeout(10, &fake_workload); + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++) { + TIM2_BASE->CNT++; + Scheduler::update(); + } + + // timeout is already done here + uint8_t task_id = Scheduler::register_task(20, &fake_workload); + + // after timeout, cancel task + Scheduler::cancel_timeout(timeout_id); + + EXPECT_EQ(Scheduler::active_task_count_, 1); +} From 12a50f3b36bb8ba70d57a18d2ad0ac8570320d9f Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 23:19:47 +0100 Subject: [PATCH 068/281] Fix: underflow in schedule_next_interval --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 92402ac54..f2d1bf89b 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -223,7 +223,7 @@ void Scheduler::schedule_next_interval() { Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; - uint64_t delta = (next_task.next_fire_us > (global_tick_us_ - 1ULL)) + uint64_t delta = ((next_task.next_fire_us + 1ULL) > global_tick_us_) ? (next_task.next_fire_us - global_tick_us_) : 1ULL; if (delta > kMaxIntervalUs) [[unlikely]] { From 6b0674082c1d8c448da107f3831e64ceafc5402f Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 23:51:16 +0100 Subject: [PATCH 069/281] Fix: call schedule_next_interval() in start() --- Src/HALAL/Services/Time/Scheduler.cpp | 5 ++--- Tests/Time/scheduler_test.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index f2d1bf89b..9dff58465 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -95,9 +95,8 @@ void Scheduler::start() { NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); CLEAR_BIT(Scheduler_global_timer->SR, LL_TIM_SR_UIF); /* clear update interrupt flag */ - // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() - Scheduler::global_timer_enable(); - //Scheduler::schedule_next_interval(); + + Scheduler::schedule_next_interval(); } SCHEDULER_GLOBAL_TIMER_CALLBACK() { diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 7dc8f9fb7..e3278f26f 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -59,7 +59,7 @@ TEST_F(SchedulerTests, TaskExecutionLong) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); // TIM2_BASE->ARR = 500; - // TIM2_BASE->generate_update(); + TIM2_BASE->generate_update(); constexpr int NUM_TICKS = 1'000'000; for(int i = 0; i < NUM_TICKS; i++){ From 21c5c15f57c177fbb09622e8f41c9156e1e47a65 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 23:56:20 +0100 Subject: [PATCH 070/281] Fix: invert condition, that was stupid --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 47c3cb3f3..fa8573923 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -57,7 +57,7 @@ struct Scheduler { 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 4. clear_timeout(id) -> will remove the second timeout */ - if(!tasks_[id].repeating) return; + if(tasks_[id].repeating) return; unregister_task(id); } From 6cfd3f3fa5143437db6278142d11024a2b13a540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Fri, 12 Dec 2025 01:05:54 +0100 Subject: [PATCH 071/281] feat: add test showcasing possible usage within StateMachine logic --- Tests/Time/scheduler_test.cpp | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index e3278f26f..1d2674cd3 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -113,3 +113,43 @@ TEST_F(SchedulerTests, TimeoutClearAddTask) { EXPECT_EQ(Scheduler::active_task_count_, 1); } + +static volatile int connecting_execs{0}; +static volatile int operational_execs{0}; +static volatile int fault_execs{0}; +void connecting_cyclic(){ + connecting_execs++; +} +void operational_cyclic(){ + operational_execs++; +} +void fault_cyclic(){ + fault_execs++; +} +TEST_F(SchedulerTests, TaskDe_ReRegistration) { + uint8_t connecting_task = Scheduler::register_task(10, &connecting_cyclic); + uint8_t operational_task = 0; + uint8_t fault_task = 0; + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++) { + TIM2_BASE->CNT++; + if(i == 21){ + Scheduler::unregister_task(connecting_task); + operational_task = Scheduler::register_task(10,operational_cyclic); + } + if(i == 45){ + Scheduler::unregister_task(operational_task); + fault_task = Scheduler::register_task(10,fault_cyclic); + } + if( i == 70){ + Scheduler::unregister_task(fault_task); + i = 100; // finish test + } + Scheduler::update(); + } + EXPECT_EQ(connecting_execs, 2); + EXPECT_EQ(operational_execs, 2); + EXPECT_EQ(fault_execs, 2); +} From 1ac4c8ce64c3e6cd33db683841da8e7854ee59f2 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 13 Dec 2025 22:37:31 +0100 Subject: [PATCH 072/281] fix: Calculate correct prescaler & add to HALAL.hpp --- Inc/HALAL/HALAL.hpp | 1 + Inc/HALAL/Services/Time/Scheduler.hpp | 17 ++++---- Src/HALAL/Services/Time/Scheduler.cpp | 61 +++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index d1c0438ce..9d5da6bd9 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -18,6 +18,7 @@ #include "HALAL/Services/PWM/DualPhasedPWM/DualPhasedPWM.hpp" #include "HALAL/Services/Time/Time.hpp" +#include "HALAL/Services/Time/Scheduler.hpp" #include "HALAL/Services/Time/RTC.hpp" #include "HALAL/Services/InputCapture/InputCapture.hpp" diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index fa8573923..5e7bde703 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -22,16 +22,17 @@ # define SCHEDULER_TIMER_IDX 2 #endif - #define glue_(a,b) a ## b - #define glue(a,b) glue_(a,b) - #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) +#define glue_(a,b) a ## b +#define glue(a,b) glue_(a,b) +#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) // Used to reserve a TimerPeripheral #ifndef TESTING_ENV - #include "stm32h7xx_hal_tim.h" - #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) - extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; +#include "stm32h7xx_hal_tim.h" +#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) +extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; #endif + struct Scheduler { using callback_t = void (*)(); static constexpr uint32_t INVALID_ID = 0xFFu; @@ -79,14 +80,14 @@ struct Scheduler { static constexpr std::size_t kMaxTasks = 16; static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); - static constexpr uint32_t kBaseClockHz = 1'000'000u; + static constexpr uint32_t FREQUENCY = 1'000'000u; // 1 MHz -> 1us precision static std::array tasks_; static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); /* sorted_task_ids_ is a sorted queue with 4bits for each id in the scheduler's current ids */ static uint64_t sorted_task_ids_; - static std::size_t active_task_count_; + static uint32_t active_task_count_; static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); static uint32_t ready_bitmap_; static uint32_t free_bitmap_; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9dff58465..bd4b840b2 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -30,7 +30,7 @@ constexpr uint64_t kMaxIntervalUs = std::array Scheduler::tasks_{}; uint64_t Scheduler::sorted_task_ids_ = 0; -std::size_t Scheduler::active_task_count_{0}; +uint32_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; @@ -70,10 +70,54 @@ inline void Scheduler::global_timer_enable() { // ---------------------------- void Scheduler::start() { - static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); + static_assert((Scheduler::FREQUENCY % 1'000'000) == 0u, "frequenct must be a multiple of 1MHz"); + + + uint32_t prescaler = (SystemCoreClock / Scheduler::FREQUENCY); + // setup prescaler + { + // ref manual: section 8.7.7 RCC domain 1 clock configuration register + uint32_t ahb_prescaler = RCC->D1CFGR & RCC_D1CFGR_HPRE_Msk; + if((ahb_prescaler & 0b1000) != 0) { + switch(ahb_prescaler) { + case 0b1000: prescaler /= 2; break; + case 0b1001: prescaler /= 4; break; + case 0b1010: prescaler /= 8; break; + case 0b1011: prescaler /= 16; break; + case 0b1100: prescaler /= 64; break; + case 0b1101: prescaler /= 128; break; + case 0b1110: prescaler /= 256; break; + case 0b1111: prescaler /= 512; break; + } + } + + // ref manual: section 8.7.8: RCC domain 2 clock configuration register + uint32_t apb1_prescaler = (RCC->D2CFGR & RCC_D2CFGR_D2PPRE1_Msk) >> RCC_D2CFGR_D2PPRE1_Pos; + if((apb1_prescaler & 0b100) != 0) { + switch(apb1_prescaler) { + case 0b100: prescaler /= 2; break; + case 0b101: prescaler /= 4; break; + case 0b110: prescaler /= 8; break; + case 0b111: prescaler /= 16; break; + } + } + // tim2clk = 2 x pclk1 when apb1_prescaler != 1 + if(apb1_prescaler != 1) { + prescaler *= 2; + } + + if(prescaler > 1) { + prescaler--; + } + } - const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; - static_assert(prescaler < 0xFFFF'FFFF, "Prescaler is 16 bit, so it must be in that range"); + // TODO: Fault when any of the next 2 static asserts happen (needs to be runtime bcos of SystemCoreClock) + if(prescaler == 0 || prescaler > 0xFFFF) { + // error here + } + + //static_assert(prescaler < 0xFFFF, "Prescaler is 16 bit, so it must be in that range"); + //static_assert(prescaler != 0, "Prescaler must be in the range [1, 65535]"); #ifndef TESTING_ENV // Register a TimerPeripheral so it's not used anywhere else @@ -140,7 +184,7 @@ void Scheduler::insert_sorted(uint8_t id) { // binary search on logical range [0, active_task_count_) std::size_t left = 0; - std::size_t right = active_task_count_; + std::size_t right = Scheduler::active_task_count_; while (left < right) { std::size_t mid = left + ((right - left) / 2); const Task& mid_task = tasks_[Scheduler::get_at(mid)]; @@ -155,6 +199,7 @@ void Scheduler::insert_sorted(uint8_t id) { uint32_t lo = (uint32_t)sorted_task_ids_; uint32_t hi = (uint32_t)(sorted_task_ids_ >> 32); + // take the shift for only high or low 32 bits uint32_t shift = (pos & 7) << 2; uint32_t id_shifted = id << shift; @@ -167,7 +212,7 @@ void Scheduler::insert_sorted(uint8_t id) { uint32_t hi_spilled = (hi << 4) | (lo >> 28); - if (pos >= 8) { //this can be done without branching + if (pos >= 8) { hi = hi_modified; // lo remains unchanged } else { @@ -176,7 +221,7 @@ void Scheduler::insert_sorted(uint8_t id) { } sorted_task_ids_ = ((uint64_t)hi << 32) | lo; - active_task_count_++; + Scheduler::active_task_count_++; } void Scheduler::remove_sorted(uint8_t id) { @@ -209,7 +254,7 @@ void Scheduler::remove_sorted(uint8_t id) { // Remove element (lower part | higher pushing nibble out of mask) Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); - active_task_count_--; + Scheduler::active_task_count_--; } void Scheduler::schedule_next_interval() { From 03aad19fadfa4eb46a8702b8006ec6268e0c6638 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 13 Dec 2025 23:19:12 +0100 Subject: [PATCH 073/281] Try to fix tests --- CMakeLists.txt | 1 + Inc/MockedDrivers/stm32h723xx_wrapper.h | 11 +++++++++++ Src/MockedDrivers/mocked_system_stm32h7xx.c | 3 +++ Tests/Time/scheduler_test.cpp | 3 +++ 4 files changed, 18 insertions(+) create mode 100644 Inc/MockedDrivers/stm32h723xx_wrapper.h create mode 100644 Src/MockedDrivers/mocked_system_stm32h7xx.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c814f9a96..5b4290400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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/mocked_system_stm32h7xx.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h new file mode 100644 index 000000000..5b4e5de63 --- /dev/null +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -0,0 +1,11 @@ +#ifndef STM32H723xx_WRAPPER_H +#define STM32H723xx_WRAPPER_H + +#include "stm32h723xx.h" + +#undef RCC + +RCC_TypeDef RCC_struct; +RCC_TypeDef *RCC = &RCC_struct; + +#endif // STM32H723xx_WRAPPER_H diff --git a/Src/MockedDrivers/mocked_system_stm32h7xx.c b/Src/MockedDrivers/mocked_system_stm32h7xx.c new file mode 100644 index 000000000..869e20d3c --- /dev/null +++ b/Src/MockedDrivers/mocked_system_stm32h7xx.c @@ -0,0 +1,3 @@ +#include + +uint32_t SystemCoreClock = 64000000; diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 1d2674cd3..9988ca927 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -1,6 +1,9 @@ #include #include #include + +#include "stm32h723xx_wrapper.h" + #include "HALAL/Services/Time/Scheduler.hpp" int count = 0; From b15ae757d236fbc1a97e1bc27af48b561082390b Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 13 Dec 2025 23:25:14 +0100 Subject: [PATCH 074/281] try to fix tests part 2 --- Tests/Time/scheduler_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 9988ca927..cda8586b3 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "stm32h723xx_wrapper.h" +#include "Inc/MockedDrivers/stm32h723xx_wrapper.h" #include "HALAL/Services/Time/Scheduler.hpp" From 0c4bb2493758cf01bb35bc2f8d527508225beb13 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 00:34:04 +0100 Subject: [PATCH 075/281] Try to fix tests part 3 --- Inc/MockedDrivers/stm32h723xx_wrapper.h | 3 +-- Src/MockedDrivers/stm32h723xx_wrapper.c | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Src/MockedDrivers/stm32h723xx_wrapper.c diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index 5b4e5de63..a7cf435f3 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -5,7 +5,6 @@ #undef RCC -RCC_TypeDef RCC_struct; -RCC_TypeDef *RCC = &RCC_struct; +extern RCC_TypeDef *RCC; #endif // STM32H723xx_WRAPPER_H diff --git a/Src/MockedDrivers/stm32h723xx_wrapper.c b/Src/MockedDrivers/stm32h723xx_wrapper.c new file mode 100644 index 000000000..cdb9e487a --- /dev/null +++ b/Src/MockedDrivers/stm32h723xx_wrapper.c @@ -0,0 +1,4 @@ +#include "stm32h7xx_wrapper.h" + +static RCC_TypeDef RCC_struct; +RCC_TypeDef *RCC = &RCC_struct; From 8095c72a5f99cb38f47527335bbf79fe46981ab1 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 00:35:12 +0100 Subject: [PATCH 076/281] part 4 - add the wrapper.c to cmake, will this work? --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b4290400..fc25b9ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,6 +226,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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/mocked_system_stm32h7xx.c> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h7xx_wrapper.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) From 18c99154aced561d4fe439fff8f7b60874a0043c Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 00:44:10 +0100 Subject: [PATCH 077/281] part 5 - fix cmake stm32h723xx_wrapper.c path --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc25b9ef2..dca4d5b5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,7 +226,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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/mocked_system_stm32h7xx.c> - $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h7xx_wrapper.c> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h723xx_wrapper.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) From 662df4537a0b0e694c74854a2108804f83b41c93 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 11:56:59 +0100 Subject: [PATCH 078/281] fix: try to fix tests part 6 --- CMakeLists.txt | 6 +- Inc/MockedDrivers/NVIC.hpp | 154 +----------------------- Inc/MockedDrivers/compiler_specific.hpp | 8 ++ Inc/MockedDrivers/ll_tim_interface.h | 3 +- Inc/MockedDrivers/mocked_ll_tim.hpp | 3 + Inc/MockedDrivers/stm32h723xx_wrapper.h | 21 ++++ Src/MockedDrivers/stm32h723xx_wrapper.c | 2 +- Tests/Time/scheduler_test.cpp | 2 - 8 files changed, 41 insertions(+), 158 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dca4d5b5f..e964ddf1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,8 +274,10 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE target_include_directories(${STLIB_LIBRARY} PUBLIC # CMSIS + HAL - $<$:${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include> - $<$:${STM32CUBEH7}/Drivers/CMSIS/Include> + #$<$:${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include> + #$<$:${STM32CUBEH7}/Drivers/CMSIS/Include> + ${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include + ${STM32CUBEH7}/Drivers/CMSIS/Include $<$:${STM32CUBEH7}/Drivers/CMSIS/Core_A/Include> $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc> $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy> diff --git a/Inc/MockedDrivers/NVIC.hpp b/Inc/MockedDrivers/NVIC.hpp index 7e8b03234..4694f9011 100644 --- a/Inc/MockedDrivers/NVIC.hpp +++ b/Inc/MockedDrivers/NVIC.hpp @@ -1,6 +1,6 @@ #pragma once - +#include "stm32h723xx_wrapper.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/compiler_specific.hpp" @@ -21,157 +21,7 @@ class NVIC_Type uint32_t RESERVED5[644U]; volatile uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ }; -enum IRQn_Type -{ -/****** Cortex-M Processor Exceptions Numbers *****************************************************************/ - NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ - HardFault_IRQn = -13, /*!< 3 Cortex-M Hard Fault Interrupt */ - MemoryManagement_IRQn = -12, /*!< 4 Cortex-M Memory Management Interrupt */ - BusFault_IRQn = -11, /*!< 5 Cortex-M Bus Fault Interrupt */ - UsageFault_IRQn = -10, /*!< 6 Cortex-M Usage Fault Interrupt */ - SVCall_IRQn = -5, /*!< 11 Cortex-M SV Call Interrupt */ - DebugMonitor_IRQn = -4, /*!< 12 Cortex-M Debug Monitor Interrupt */ - PendSV_IRQn = -2, /*!< 14 Cortex-M Pend SV Interrupt */ - SysTick_IRQn = -1, /*!< 15 Cortex-M System Tick Interrupt */ -/****** STM32 specific Interrupt Numbers **********************************************************************/ - WWDG_IRQn = 0, /*!< Window WatchDog Interrupt ( wwdg1_it, wwdg2_it) */ - PVD_AVD_IRQn = 1, /*!< PVD/AVD through EXTI Line detection Interrupt */ - TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ - RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ - FLASH_IRQn = 4, /*!< FLASH global Interrupt */ - RCC_IRQn = 5, /*!< RCC global Interrupt */ - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ - EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ - EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ - EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ - DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ - DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ - DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ - DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ - DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ - DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ - DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ - ADC_IRQn = 18, /*!< ADC1 and ADC2 global Interrupts */ - FDCAN1_IT0_IRQn = 19, /*!< FDCAN1 Interrupt line 0 */ - FDCAN2_IT0_IRQn = 20, /*!< FDCAN2 Interrupt line 0 */ - FDCAN1_IT1_IRQn = 21, /*!< FDCAN1 Interrupt line 1 */ - FDCAN2_IT1_IRQn = 22, /*!< FDCAN2 Interrupt line 1 */ - EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ - TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */ - TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ - TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */ - TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ - TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ - TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ - TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ - I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ - I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ - I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ - I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ - SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ - SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ - USART1_IRQn = 37, /*!< USART1 global Interrupt */ - USART2_IRQn = 38, /*!< USART2 global Interrupt */ - USART3_IRQn = 39, /*!< USART3 global Interrupt */ - EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ - RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ - TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ - TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ - TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ - TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ - DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ - FMC_IRQn = 48, /*!< FMC global Interrupt */ - SDMMC1_IRQn = 49, /*!< SDMMC1 global Interrupt */ - TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ - SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ - UART4_IRQn = 52, /*!< UART4 global Interrupt */ - UART5_IRQn = 53, /*!< UART5 global Interrupt */ - TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ - TIM7_IRQn = 55, /*!< TIM7 global interrupt */ - DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ - DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ - DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ - DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ - DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ - ETH_IRQn = 61, /*!< Ethernet global Interrupt */ - ETH_WKUP_IRQn = 62, /*!< Ethernet Wakeup through EXTI line Interrupt */ - FDCAN_CAL_IRQn = 63, /*!< FDCAN Calibration unit Interrupt */ - DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ - DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ - DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ - USART6_IRQn = 71, /*!< USART6 global interrupt */ - I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ - I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ - OTG_HS_EP1_OUT_IRQn = 74, /*!< USB OTG HS End Point 1 Out global interrupt */ - OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */ - OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */ - OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */ - DCMI_PSSI_IRQn = 78, /*!< DCMI and PSSI global interrupt */ - RNG_IRQn = 80, /*!< RNG global interrupt */ - FPU_IRQn = 81, /*!< FPU global interrupt */ - UART7_IRQn = 82, /*!< UART7 global interrupt */ - UART8_IRQn = 83, /*!< UART8 global interrupt */ - SPI4_IRQn = 84, /*!< SPI4 global Interrupt */ - SPI5_IRQn = 85, /*!< SPI5 global Interrupt */ - SPI6_IRQn = 86, /*!< SPI6 global Interrupt */ - SAI1_IRQn = 87, /*!< SAI1 global Interrupt */ - LTDC_IRQn = 88, /*!< LTDC global Interrupt */ - LTDC_ER_IRQn = 89, /*!< LTDC Error global Interrupt */ - DMA2D_IRQn = 90, /*!< DMA2D global Interrupt */ - OCTOSPI1_IRQn = 92, /*!< OCTOSPI1 global interrupt */ - LPTIM1_IRQn = 93, /*!< LP TIM1 interrupt */ - CEC_IRQn = 94, /*!< HDMI-CEC global Interrupt */ - I2C4_EV_IRQn = 95, /*!< I2C4 Event Interrupt */ - I2C4_ER_IRQn = 96, /*!< I2C4 Error Interrupt */ - SPDIF_RX_IRQn = 97, /*!< SPDIF-RX global Interrupt */ - DMAMUX1_OVR_IRQn = 102, /*! -#define TIM1 +//#define TIM1 /** @addtogroup STM32H7xx_LL_Driver * @{ diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 41897a666..091d8b435 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include "MockedDrivers/stm32h723xx_wrapper.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/tim_register_definitions.hpp" @@ -129,5 +130,7 @@ struct RegisterTraits { TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler,TIM_IDX##_IRQn}; \ TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; +#undef TIM1_BASE DECLARE_TIMER(TIM1) +#undef TIM2_BASE DECLARE_TIMER(TIM2) diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index a7cf435f3..543ccc993 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -1,8 +1,29 @@ #ifndef STM32H723xx_WRAPPER_H #define STM32H723xx_WRAPPER_H +#include +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __IO volatile + +// necessary remove of some warnings due to cmsis made for 32 bit arch and not 64 bit arch +#define __RBIT __RBIT__CMSIS +#define TIM_TypeDef TIM_TypeDef__CMSIS +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" + +// don't do anything in "core_cm7.h" +#define __CORE_CM7_H_GENERIC +#define __CORE_CM7_H_DEPENDANT #include "stm32h723xx.h" +#pragma GCC diagnostic pop +#undef __RBIT +#undef TIM_TypeDef + #undef RCC extern RCC_TypeDef *RCC; diff --git a/Src/MockedDrivers/stm32h723xx_wrapper.c b/Src/MockedDrivers/stm32h723xx_wrapper.c index cdb9e487a..f8da31ebb 100644 --- a/Src/MockedDrivers/stm32h723xx_wrapper.c +++ b/Src/MockedDrivers/stm32h723xx_wrapper.c @@ -1,4 +1,4 @@ -#include "stm32h7xx_wrapper.h" +#include "MockedDrivers/stm32h723xx_wrapper.h" static RCC_TypeDef RCC_struct; RCC_TypeDef *RCC = &RCC_struct; diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index cda8586b3..8ef34f56f 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -2,8 +2,6 @@ #include #include -#include "Inc/MockedDrivers/stm32h723xx_wrapper.h" - #include "HALAL/Services/Time/Scheduler.hpp" int count = 0; From de82133018d7c6ba5d1386d110f77e49d586b7dd Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 12:00:36 +0100 Subject: [PATCH 079/281] fix: volatile warnings --- Tests/Time/scheduler_test.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 8ef34f56f..6a57b9374 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -119,13 +119,16 @@ static volatile int connecting_execs{0}; static volatile int operational_execs{0}; static volatile int fault_execs{0}; void connecting_cyclic(){ - connecting_execs++; + auto next_connecting_execs = connecting_execs + 1; + connecting_execs = next_connecting_execs; } void operational_cyclic(){ - operational_execs++; + auto next_operational_execs = operational_execs + 1; + operational_execs = next_operational_execs; } void fault_cyclic(){ - fault_execs++; + auto next_fault_execs = fault_execs + 1; + fault_execs = next_fault_execs; } TEST_F(SchedulerTests, TaskDe_ReRegistration) { uint8_t connecting_task = Scheduler::register_task(10, &connecting_cyclic); From e8a914139a55086ae9046f425fa5a2bbaa03f38a Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 12:42:26 +0100 Subject: [PATCH 080/281] fix: active_PSC is now set when PSC is set --- Inc/MockedDrivers/Register.hpp | 3 ++- Inc/MockedDrivers/mocked_ll_tim.hpp | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Inc/MockedDrivers/Register.hpp b/Inc/MockedDrivers/Register.hpp index e133993a7..bce0d5dba 100644 --- a/Inc/MockedDrivers/Register.hpp +++ b/Inc/MockedDrivers/Register.hpp @@ -109,7 +109,8 @@ class RegisterBase { operator uint32_t() const { return reg; } -private: + +protected: void set(uint32_t val) { RegisterTraits::write(this->reg, val); } diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 091d8b435..9ecc3c473 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -23,14 +23,29 @@ class TimerRegister : public RegisterBase { using RegisterBase::operator=; }; + static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); class TIM_TypeDef{ public: TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): - callback{irq_handler},irq_n{irq_n} +// PSC(*this), callback{irq_handler}, irq_n{irq_n} + callback{irq_handler}, irq_n{irq_n} {} + + // NOTE: This ruins the address offsets but I couldn't get it to work any other way + template + struct PrescalerRegister : public RegisterBase { + PrescalerRegister& operator=(uint32_t val) { + this->set(val); + // esto es lo más feo que he hecho en mucho tiempo pero no he conseguido otra cosa + TIM_TypeDef *parent = (TIM_TypeDef*)((uint8_t*)&this->reg - offsetof(TIM_TypeDef, PSC)); + parent->active_PSC = val; + return *this; + } + }; + void generate_update(); TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ @@ -42,7 +57,7 @@ class TIM_TypeDef{ TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ - TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ + PrescalerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ From a0ad409a01d760b6181f28477746cc324db6ec6e Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 12:50:12 +0100 Subject: [PATCH 081/281] fix: remove outdated comment --- Inc/MockedDrivers/mocked_ll_tim.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 9ecc3c473..118b6e8cb 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -34,7 +34,6 @@ class TIM_TypeDef{ callback{irq_handler}, irq_n{irq_n} {} - // NOTE: This ruins the address offsets but I couldn't get it to work any other way template struct PrescalerRegister : public RegisterBase { PrescalerRegister& operator=(uint32_t val) { From 0d627b4a0423c60ed3da633426239ce817fd8c43 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 16:04:46 +0100 Subject: [PATCH 082/281] fix: tests part 7, should work now --- Inc/MockedDrivers/mocked_ll_tim.hpp | 5 ++++- Src/MockedDrivers/mocked_ll_tim.cpp | 9 ++++++++- Tests/Time/scheduler_test.cpp | 25 +++++++++++++++---------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 118b6e8cb..032656be5 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -119,10 +119,13 @@ class TIM_TypeDef{ } return true; } + + void inc_cnt_and_check(uint32_t val); }; static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); void simulate_ticks(TIM_TypeDef* tim); +/* template<> struct RegisterTraits { static void write(uint32_t& target, uint32_t val) { @@ -133,7 +136,7 @@ struct RegisterTraits { } } }; - +*/ #define DECLARE_TIMER(TIM_IDX) \ extern TIM_TypeDef* TIM_IDX##_BASE; \ diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index 4f4ceb413..2d1dd0edb 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -10,7 +10,7 @@ void TIM_TypeDef::generate_update() { active_RCR = RCR; internal_rcr_cnt = active_RCR; internal_psc_cnt = 0; - CNT = 0; // Usually UEV also resets CNT unless configured otherwise + *((uint32_t*)&CNT) = 0; // Usually UEV also resets CNT unless configured otherwise SR &= ~(1U << 0); // Clear UIF if needed, or set it depending on CR1 } void simulate_ticks(TIM_TypeDef* tim){ @@ -58,4 +58,11 @@ void simulate_ticks(TIM_TypeDef* tim){ tim->internal_rcr_cnt--; } } +} + +void TIM_TypeDef::inc_cnt_and_check(uint32_t val) { + if(val != 0 && this->check_CNT_increase_preconditions()){ + this->CNT += val; + simulate_ticks(this); + } } \ No newline at end of file diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 6a57b9374..e111dc3e8 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -44,12 +44,11 @@ TEST_F(SchedulerTests, TaskRegistration) { TEST_F(SchedulerTests, TaskExecutionShort) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); - // TIM2_BASE->ARR = 500; - // TIM2_BASE->generate_update(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 1'000; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } // 1000 ticks / 10 ticks/task = 100 executions. @@ -61,10 +60,11 @@ TEST_F(SchedulerTests, TaskExecutionLong) { Scheduler::start(); // TIM2_BASE->ARR = 500; TIM2_BASE->generate_update(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 1'000'000; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } EXPECT_EQ(count, 100'000); @@ -73,10 +73,11 @@ TEST_F(SchedulerTests, TaskExecutionLong) { TEST_F(SchedulerTests, SetTimeout) { Scheduler::set_timeout(10, &fake_workload); Scheduler::start(); - + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } EXPECT_EQ(count, 1); @@ -86,10 +87,12 @@ TEST_F(SchedulerTests, GlobalTickOverflow) { Scheduler::global_tick_us_ = 0xFFFFFFF0ULL; // Near 32-bit max Scheduler::register_task(20, &fake_workload); Scheduler::start(); - + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); + Scheduler::update(); } // 100 ticks /20 ticks/task = 5 executions. @@ -99,10 +102,11 @@ TEST_F(SchedulerTests, GlobalTickOverflow) { TEST_F(SchedulerTests, TimeoutClearAddTask) { uint8_t timeout_id = Scheduler::set_timeout(10, &fake_workload); Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++) { - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } @@ -135,10 +139,11 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { uint8_t operational_task = 0; uint8_t fault_task = 0; Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++) { - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); if(i == 21){ Scheduler::unregister_task(connecting_task); operational_task = Scheduler::register_task(10,operational_cyclic); From 978b28291213cd18ff6d8bc085b9647e503bf7cb Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 16:07:04 +0100 Subject: [PATCH 083/281] fix: remove unecessary if, return if cancelled in cancel_timeout --- Inc/HALAL/Services/Time/Scheduler.hpp | 6 +++--- Src/HALAL/Services/Time/Scheduler.cpp | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 5e7bde703..66602aac7 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -51,15 +51,15 @@ struct Scheduler { if(microseconds == 0) [[unlikely]] microseconds = 1; return register_task(microseconds, func, false); } - static inline void cancel_timeout(uint8_t id) { + static inline bool cancel_timeout(uint8_t id) { /* NOTE: This does not fix this case: 1. id = set_timeout(x, func) 2. timeout ends, func gets called and removed internally 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 4. clear_timeout(id) -> will remove the second timeout */ - if(tasks_[id].repeating) return; - unregister_task(id); + if(tasks_[id].repeating) return false; + return unregister_task(id); } // static void global_timer_callback(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index bd4b840b2..4a671ca5e 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -173,8 +173,6 @@ inline uint8_t Scheduler::allocate_slot() { } inline void Scheduler::release_slot(uint8_t id) { - // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert - if(id >= kMaxTasks) [[unlikely]] return; ready_bitmap_ &= ~(1u << id); free_bitmap_ |= (1u << id); } From 4f27b482300dafcc842d86fb3b76ff1369bcabf3 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 12:11:31 +0100 Subject: [PATCH 084/281] Pop all due tasks, several might be due in the same tick --- Src/HALAL/Services/Time/Scheduler.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4a671ca5e..3cb0fd0ea 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -288,14 +288,20 @@ inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { void Scheduler::on_timer_update() { global_tick_us_ += current_interval_us_; - uint8_t candidate_id = Scheduler::front_id(); - Task& task = tasks_[candidate_id]; - pop_front(); - ready_bitmap_ |= (1u << candidate_id); // mark task as ready - - if (task.repeating) [[likely]] { - task.next_fire_us = global_tick_us_ + task.period_us; - insert_sorted(candidate_id); + // pop all due tasks, several might be due in the same tick + while(active_task_count_ > 0) { + uint8_t candidate_id = Scheduler::front_id(); + Task& task = tasks_[candidate_id]; + if(task.next_fire_us > Scheduler::global_tick_us_) [[likely]] { + break; // task is in the future, stop processing + } + pop_front(); + ready_bitmap_ |= (1u << candidate_id); // mark task as ready + + if (task.repeating) [[likely]] { + task.next_fire_us = global_tick_us_ + task.period_us; + insert_sorted(candidate_id); + } } schedule_next_interval(); From 6014d290104354bb85903668554f840b507628c6 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 12:58:50 +0100 Subject: [PATCH 085/281] Revert force-push --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 34 +++++++++++++-------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 66602aac7..fe513682b 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -92,7 +92,7 @@ struct Scheduler { static uint32_t ready_bitmap_; static uint32_t free_bitmap_; static uint64_t global_tick_us_; - static uint64_t current_interval_us_; + static uint32_t current_interval_us_; static inline uint8_t allocate_slot(); static inline void release_slot(uint8_t id); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 3cb0fd0ea..24b7aa3fa 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -25,7 +25,7 @@ #define Scheduler_global_timer ((TIM_TypeDef*)SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = - static_cast(std::numeric_limits::max()) + 1ULL; + static_cast(std::numeric_limits::max())/2 + 1ULL; } std::array Scheduler::tasks_{}; @@ -35,7 +35,7 @@ uint32_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; -uint64_t Scheduler::current_interval_us_{0}; +uint32_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; @@ -160,8 +160,6 @@ void Scheduler::update() { } } -inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } - // void Scheduler::global_timer_callback() { on_timer_update(); } inline uint8_t Scheduler::allocate_slot() { @@ -186,7 +184,7 @@ void Scheduler::insert_sorted(uint8_t id) { while (left < right) { std::size_t mid = left + ((right - left) / 2); const Task& mid_task = tasks_[Scheduler::get_at(mid)]; - if (mid_task.next_fire_us <= task.next_fire_us) { + if ((int32_t)(task.next_fire_us - mid_task.next_fire_us) >= 0) { left = mid + 1; } else { right = mid; @@ -265,14 +263,14 @@ void Scheduler::schedule_next_interval() { Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; - uint64_t delta = ((next_task.next_fire_us + 1ULL) > global_tick_us_) - ? (next_task.next_fire_us - global_tick_us_) : 1ULL; - - if (delta > kMaxIntervalUs) [[unlikely]] { - current_interval_us_ = kMaxIntervalUs; + int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); + uint32_t delta; + if (diff <= 0) [[unlikely]]{ + delta = 1; // Task is due or overdue } else { - current_interval_us_ = delta; + delta = static_cast(diff); } + current_interval_us_ = delta; configure_timer_for_interval(current_interval_us_); } @@ -288,18 +286,18 @@ inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { void Scheduler::on_timer_update() { global_tick_us_ += current_interval_us_; - // pop all due tasks, several might be due in the same tick - while(active_task_count_ > 0) { + while (active_task_count_ > 0) { //Pop all due tasks, several might be due in the same tick uint8_t candidate_id = Scheduler::front_id(); Task& task = tasks_[candidate_id]; - if(task.next_fire_us > Scheduler::global_tick_us_) [[likely]] { - break; // task is in the future, stop processing + int32_t diff = (int32_t)(task.next_fire_us - static_cast(global_tick_us_)); + if (diff > 0) [[likely]]{ + break; // Task is in the future, stop processing } pop_front(); ready_bitmap_ |= (1u << candidate_id); // mark task as ready if (task.repeating) [[likely]] { - task.next_fire_us = global_tick_us_ + task.period_us; + task.next_fire_us = static_cast(global_tick_us_ + task.period_us); insert_sorted(candidate_id); } } @@ -309,6 +307,7 @@ void Scheduler::on_timer_update() { uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repeating) { if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + if(period_us >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); uint8_t slot = allocate_slot(); if(slot == Scheduler::INVALID_ID) return slot; @@ -317,8 +316,7 @@ uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repea task.callback = func; task.period_us = period_us; task.repeating = repeating; - task.next_fire_us = global_tick_us_ + period_us; - + task.next_fire_us = static_cast(global_tick_us_ + period_us); insert_sorted(slot); schedule_next_interval(); return slot; From a11f4bc6f9b45390a446d389cf5baca7dc902443 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 13:10:57 +0100 Subject: [PATCH 086/281] fix: off by one error + configure_timer_for_interval should use uint32_t --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index fe513682b..140382a49 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -99,7 +99,7 @@ struct Scheduler { static void insert_sorted(uint8_t id); static void remove_sorted(uint8_t id); static void schedule_next_interval(); - static inline void configure_timer_for_interval(uint64_t microseconds); + static inline void configure_timer_for_interval(uint32_t microseconds); static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); // helpers diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 24b7aa3fa..e77d74d02 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -265,8 +265,8 @@ void Scheduler::schedule_next_interval() { Task& next_task = tasks_[next_id]; int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); uint32_t delta; - if (diff <= 0) [[unlikely]]{ - delta = 1; // Task is due or overdue + if (diff <= 1) [[unlikely]]{ + delta = 2; // Task is due or overdue } else { delta = static_cast(diff); } @@ -275,7 +275,7 @@ void Scheduler::schedule_next_interval() { configure_timer_for_interval(current_interval_us_); } -inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { +inline void Scheduler::configure_timer_for_interval(uint32_t microseconds) { // NOTE(vic): disabling the timer _might_ be necessary to prevent the timer from firing in the middle of configuring it, highly unlikely since it has a period of at least 1 microsecond // TODO(vic): Validation: check arr is set correctly here: https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#pullrequestreview-3529132356 Scheduler_global_timer->ARR = static_cast(microseconds - 1u); From f38b7624d71595478fa9831f3c03f87c78c88bfc Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 15:53:20 +0100 Subject: [PATCH 087/281] fix: off by one error in schedule_next_interval() --- Inc/MockedDrivers/mocked_ll_tim.hpp | 5 +---- Src/HALAL/Services/Time/Scheduler.cpp | 12 ++++++------ Tests/Time/scheduler_test.cpp | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 032656be5..2132cfb78 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -114,10 +114,7 @@ class TIM_TypeDef{ } // If prescaler didn't overflow, the main counter doesn't move. - if (!main_counter_tick) { - return false; - } - return true; + return main_counter_tick; } void inc_cnt_and_check(uint32_t val); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index e77d74d02..9124e3476 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -264,15 +264,15 @@ void Scheduler::schedule_next_interval() { uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); - uint32_t delta; if (diff <= 1) [[unlikely]]{ - delta = 2; // Task is due or overdue + current_interval_us_ = 1; + Scheduler_global_timer->ARR = 1; + Scheduler_global_timer->CNT = 1; + Scheduler::global_timer_enable(); } else { - delta = static_cast(diff); + current_interval_us_ = static_cast(diff); + configure_timer_for_interval(current_interval_us_); } - current_interval_us_ = delta; - - configure_timer_for_interval(current_interval_us_); } inline void Scheduler::configure_timer_for_interval(uint32_t microseconds) { diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index e111dc3e8..c635f9452 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -162,3 +162,26 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { EXPECT_EQ(operational_execs, 2); EXPECT_EQ(fault_execs, 2); } + +int multiple_task1count = 0; +void multiple_task_1(void) { + multiple_task1count++; +} +int multiple_task2count = 0; +void multiple_task_2(void) { + multiple_task2count++; +} +TEST_F(SchedulerTests, MultipleTasks) { + uint8_t taskid1 = Scheduler::register_task(2, &multiple_task_1); + uint8_t taskid2 = Scheduler::register_task(3, &multiple_task_2); + + Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 30; + for(int i = 0; i < NUM_TICKS; i++) { + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); + Scheduler::update(); + } + EXPECT_EQ(multiple_task1count, 15); + EXPECT_EQ(multiple_task2count, 10); +} From 79f327e466c81ebcea61f39b7e65d9625dc6247c Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 16:44:59 +0100 Subject: [PATCH 088/281] All 15 tasks in MultipleTasks test, and it works --- Tests/Time/scheduler_test.cpp | 45 +++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index c635f9452..41b390c88 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -163,17 +163,35 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { EXPECT_EQ(fault_execs, 2); } -int multiple_task1count = 0; -void multiple_task_1(void) { - multiple_task1count++; -} -int multiple_task2count = 0; -void multiple_task_2(void) { - multiple_task2count++; -} +#define multiple_tasks \ + X(1) \ + X(2) \ + X(3) \ + X(4) \ + X(5) \ + X(6) \ + X(7) \ + X(8) \ + X(9) \ + X(10) \ + X(11) \ + X(12) \ + X(13) \ + X(14) \ + X(15) + +#define X(n) \ + int multiple_task##n##count = 0; \ + void multiple_task_##n(void) { \ + multiple_task##n##count++; \ + } +multiple_tasks +#undef X TEST_F(SchedulerTests, MultipleTasks) { - uint8_t taskid1 = Scheduler::register_task(2, &multiple_task_1); - uint8_t taskid2 = Scheduler::register_task(3, &multiple_task_2); +#define X(n) uint8_t taskid##n = Scheduler::register_task(n, &multiple_task_##n); \ + (void) taskid##n; + multiple_tasks +#undef X Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test @@ -182,6 +200,9 @@ TEST_F(SchedulerTests, MultipleTasks) { for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } - EXPECT_EQ(multiple_task1count, 15); - EXPECT_EQ(multiple_task2count, 10); + +#define X(n) EXPECT_EQ(multiple_task##n##count, NUM_TICKS / n); + multiple_tasks +#undef X } + From 344618d6607a5e3f0e497fd0b691dcebc62cd86a Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 16:51:18 +0100 Subject: [PATCH 089/281] Add SameTaskMultipleTimes test, does all 16 tasks too --- Tests/Time/scheduler_test.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 41b390c88..cc9d26335 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -178,7 +178,8 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { X(12) \ X(13) \ X(14) \ - X(15) + X(15) \ + X(16) #define X(n) \ int multiple_task##n##count = 0; \ @@ -189,7 +190,7 @@ multiple_tasks #undef X TEST_F(SchedulerTests, MultipleTasks) { #define X(n) uint8_t taskid##n = Scheduler::register_task(n, &multiple_task_##n); \ - (void) taskid##n; + (void)taskid##n; multiple_tasks #undef X @@ -206,3 +207,21 @@ TEST_F(SchedulerTests, MultipleTasks) { #undef X } + +TEST_F(SchedulerTests, SameTaskMultipleTimes) { +#define X(n) uint8_t taskid_##n = Scheduler::register_task(n, &multiple_task_1); \ + (void)taskid_##n; + multiple_tasks +#undef X + + Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 30; + for(int i = 0; i < NUM_TICKS; i++) { + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); + Scheduler::update(); + } + +#define X(n) NUM_TICKS / n + + EXPECT_EQ(multiple_task1count, multiple_tasks 0); +} From 5d3aa612cc49a94a797a4881a3b8923e68c62c38 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 16:52:09 +0100 Subject: [PATCH 090/281] larger NUM_TICKS just in case --- Tests/Time/scheduler_test.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index cc9d26335..00e6f6db5 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -196,7 +196,7 @@ TEST_F(SchedulerTests, MultipleTasks) { Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test - constexpr int NUM_TICKS = 30; + constexpr int NUM_TICKS = 300; for(int i = 0; i < NUM_TICKS; i++) { for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); @@ -207,7 +207,6 @@ TEST_F(SchedulerTests, MultipleTasks) { #undef X } - TEST_F(SchedulerTests, SameTaskMultipleTimes) { #define X(n) uint8_t taskid_##n = Scheduler::register_task(n, &multiple_task_1); \ (void)taskid_##n; @@ -216,7 +215,7 @@ TEST_F(SchedulerTests, SameTaskMultipleTimes) { Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test - constexpr int NUM_TICKS = 30; + constexpr int NUM_TICKS = 300; for(int i = 0; i < NUM_TICKS; i++) { for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); From 238c062227c0b689bfe8fe0ec1335e0796ec1cd3 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 23:17:39 +0100 Subject: [PATCH 091/281] fix bug mentioned in previous cancel_timeout() --- Inc/HALAL/Services/Time/Scheduler.hpp | 30 ++++----------- Src/HALAL/Services/Time/Scheduler.cpp | 54 +++++++++++++++++++++++---- Tests/Time/scheduler_test.cpp | 2 +- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 140382a49..4be680084 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -41,26 +41,11 @@ struct Scheduler { static void update(); static inline uint64_t get_global_tick(); - static inline uint8_t register_task(uint32_t period_us, callback_t func) { - if(period_us == 0) [[unlikely]] period_us = 1; - return register_task(period_us, func, true); - } - static bool unregister_task(uint8_t id); - - static inline uint8_t set_timeout(uint32_t microseconds, callback_t func) { - if(microseconds == 0) [[unlikely]] microseconds = 1; - return register_task(microseconds, func, false); - } - static inline bool cancel_timeout(uint8_t id) { - /* NOTE: This does not fix this case: - 1. id = set_timeout(x, func) - 2. timeout ends, func gets called and removed internally - 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 - 4. clear_timeout(id) -> will remove the second timeout - */ - if(tasks_[id].repeating) return false; - return unregister_task(id); - } + static uint32_t register_task(uint32_t period_us, callback_t func); + static bool unregister_task(uint32_t id); + + static uint32_t set_timeout(uint32_t microseconds, callback_t func); + static bool cancel_timeout(uint32_t id); // static void global_timer_callback(); @@ -72,9 +57,10 @@ struct Scheduler { private: #endif struct Task { - uint64_t next_fire_us{0}; + uint32_t next_fire_us{0}; callback_t callback{}; uint32_t period_us{0}; + uint32_t id; bool repeating{false}; }; @@ -93,6 +79,7 @@ struct Scheduler { static uint32_t free_bitmap_; static uint64_t global_tick_us_; static uint32_t current_interval_us_; + static uint32_t timeout_idx_; static inline uint8_t allocate_slot(); static inline void release_slot(uint8_t id); @@ -100,7 +87,6 @@ struct Scheduler { static void remove_sorted(uint8_t id); static void schedule_next_interval(); static inline void configure_timer_for_interval(uint32_t microseconds); - static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); // helpers static inline uint8_t get_at(uint8_t idx); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9124e3476..0883a1289 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -36,6 +36,7 @@ uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; uint32_t Scheduler::current_interval_us_{0}; +uint32_t Scheduler::timeout_idx_{1}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; @@ -305,8 +306,9 @@ void Scheduler::on_timer_update() { schedule_next_interval(); } -uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repeating) { - if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); +uint32_t Scheduler::register_task(uint32_t period_us, callback_t func) { + if(func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + if(period_us == 0) [[unlikely]] period_us = 1; if(period_us >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); uint8_t slot = allocate_slot(); @@ -315,16 +317,54 @@ uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repea Task& task = tasks_[slot]; task.callback = func; task.period_us = period_us; - task.repeating = repeating; + task.repeating = true; task.next_fire_us = static_cast(global_tick_us_ + period_us); + task.id = static_cast(slot); insert_sorted(slot); schedule_next_interval(); - return slot; + return task.id; +} + +uint32_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { + if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + if(microseconds == 0) [[unlikely]] microseconds = 1; + if(microseconds >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + + uint8_t slot = allocate_slot(); + if(slot == Scheduler::INVALID_ID) return slot; + + Task& task = tasks_[slot]; + task.callback = func; + task.period_us = microseconds; + task.repeating = false; + task.next_fire_us = static_cast(global_tick_us_ + microseconds); + task.id = slot + Scheduler::timeout_idx_ * Scheduler::kMaxTasks; + + // Add 2 instead of 1 so overflow doesn't make timeout_idx == 0, + // we need it to never be 0 + Scheduler::timeout_idx_ += 2; + + insert_sorted(slot); + schedule_next_interval(); + return task.id; +} + +bool Scheduler::unregister_task(uint32_t id) { + if(id >= kMaxTasks) return false; + if(free_bitmap_ & (1UL << id)) return false; + + remove_sorted(id); + release_slot(id); + schedule_next_interval(); + return true; } -bool Scheduler::unregister_task(uint8_t id) { - if (id >= kMaxTasks) return false; - if (free_bitmap_ & (1UL << id)) return false; +bool Scheduler::cancel_timeout(uint32_t id) { + static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); + uint32_t idx = id & Scheduler::kMaxTasks; + if(tasks_[idx].repeating) return false; + if(tasks_[idx].id != id) return false; + if(free_bitmap_ & (1UL << id)) return false; remove_sorted(id); release_slot(id); diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 00e6f6db5..f32f13639 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -111,7 +111,7 @@ TEST_F(SchedulerTests, TimeoutClearAddTask) { } // timeout is already done here - uint8_t task_id = Scheduler::register_task(20, &fake_workload); + uint8_t timeout_id_2 = Scheduler::set_timeout(20, &fake_workload); // after timeout, cancel task Scheduler::cancel_timeout(timeout_id); From 09fc585c87140f0ca7aac415749ca0c81160b195 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 16 Dec 2025 08:47:14 +0100 Subject: [PATCH 092/281] fix: id uint32_t -> uint16_t + bug fix --- Inc/HALAL/Services/Time/Scheduler.hpp | 12 ++++++------ Src/HALAL/Services/Time/Scheduler.cpp | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 4be680084..1d246b45c 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -41,11 +41,11 @@ struct Scheduler { static void update(); static inline uint64_t get_global_tick(); - static uint32_t register_task(uint32_t period_us, callback_t func); - static bool unregister_task(uint32_t id); + static uint16_t register_task(uint32_t period_us, callback_t func); + static bool unregister_task(uint16_t id); - static uint32_t set_timeout(uint32_t microseconds, callback_t func); - static bool cancel_timeout(uint32_t id); + static uint16_t set_timeout(uint32_t microseconds, callback_t func); + static bool cancel_timeout(uint16_t id); // static void global_timer_callback(); @@ -60,7 +60,7 @@ struct Scheduler { uint32_t next_fire_us{0}; callback_t callback{}; uint32_t period_us{0}; - uint32_t id; + uint16_t id; bool repeating{false}; }; @@ -79,7 +79,7 @@ struct Scheduler { static uint32_t free_bitmap_; static uint64_t global_tick_us_; static uint32_t current_interval_us_; - static uint32_t timeout_idx_; + static uint16_t timeout_idx_; static inline uint8_t allocate_slot(); static inline void release_slot(uint8_t id); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 0883a1289..f6d3cf9fb 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -36,7 +36,7 @@ uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; uint32_t Scheduler::current_interval_us_{0}; -uint32_t Scheduler::timeout_idx_{1}; +uint16_t Scheduler::timeout_idx_{1}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; @@ -306,7 +306,7 @@ void Scheduler::on_timer_update() { schedule_next_interval(); } -uint32_t Scheduler::register_task(uint32_t period_us, callback_t func) { +uint16_t Scheduler::register_task(uint32_t period_us, callback_t func) { if(func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); if(period_us == 0) [[unlikely]] period_us = 1; if(period_us >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); @@ -325,7 +325,7 @@ uint32_t Scheduler::register_task(uint32_t period_us, callback_t func) { return task.id; } -uint32_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { +uint16_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); if(microseconds == 0) [[unlikely]] microseconds = 1; if(microseconds >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); @@ -349,7 +349,7 @@ uint32_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { return task.id; } -bool Scheduler::unregister_task(uint32_t id) { +bool Scheduler::unregister_task(uint16_t id) { if(id >= kMaxTasks) return false; if(free_bitmap_ & (1UL << id)) return false; @@ -359,15 +359,15 @@ bool Scheduler::unregister_task(uint32_t id) { return true; } -bool Scheduler::cancel_timeout(uint32_t id) { +bool Scheduler::cancel_timeout(uint16_t id) { static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); - uint32_t idx = id & Scheduler::kMaxTasks; + uint32_t idx = id & (Scheduler::kMaxTasks - 1UL); if(tasks_[idx].repeating) return false; if(tasks_[idx].id != id) return false; - if(free_bitmap_ & (1UL << id)) return false; + if(free_bitmap_ & (1UL << idx)) return false; - remove_sorted(id); - release_slot(id); + remove_sorted(idx); + release_slot(idx); schedule_next_interval(); return true; } From 04ed0f79c8bd12c0ac7b4bb8f5fb4083901d4b6b Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 16 Dec 2025 19:17:56 +0100 Subject: [PATCH 093/281] fix: remove TimerPeripheral::start and Time::start from HALAL::start --- Src/HALAL/HALAL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/HALAL.cpp b/Src/HALAL/HALAL.cpp index 2ee470ed9..3a309fb2d 100644 --- a/Src/HALAL/HALAL.cpp +++ b/Src/HALAL/HALAL.cpp @@ -72,8 +72,8 @@ static void common_start(UART::Peripheral &printf_peripheral) { #ifdef HAL_TIM_MODULE_ENABLED Encoder::start(); Global_RTC::start_rtc(); - TimerPeripheral::start(); - Time::start(); + //TimerPeripheral::start(); + //Time::start(); #endif #ifdef HAL_EXTI_MODULE_ENABLED From 9dcffe12cf7750843079f83d2a8521c85a35f243 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 12:59:08 +0100 Subject: [PATCH 094/281] try to fix ci/cd --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c9f88bc4..bb7ae0a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,14 @@ message(STATUS "${PROJECT_NAME} Ethernet: ${USE_ETHERNET}") message(STATUS "${PROJECT_NAME} Nucleo: ${TARGET_NUCLEO}") message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) + execute_process( + COMMAND git submodule update --init + ) + execute_process( + COMMAND git submodule update --init --depth 1 STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx + ) +endif() if(NOT CMAKE_CROSSCOMPILING) message(STATUS "Compiling for simulator") From b92aebc94282f43985d0b3eec3cd3d4441727d6f Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 13:04:21 +0100 Subject: [PATCH 095/281] try to fix ci/cd part 2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb7ae0a22..2a6ce7206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM3 COMMAND git submodule update --init ) execute_process( - COMMAND git submodule update --init --depth 1 STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx + COMMAND git submodule update --init --depth 1 ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx ) endif() From 181590a1a522c00c6a413714f79fb5e8a8d8c973 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 13:09:38 +0100 Subject: [PATCH 096/281] try to fix ci/cd part 3 --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a6ce7206..9d0033860 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,10 +23,11 @@ message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) execute_process( - COMMAND git submodule update --init + COMMAND git submodule update --init --depth 1 ) execute_process( - COMMAND git submodule update --init --depth 1 ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx + COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 ) endif() From d48e00af2e3cb92c977aa729a6af3e2fe4f11dfa Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 13:12:47 +0100 Subject: [PATCH 097/281] clean up ci/cd fix --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d0033860..e390832cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,14 @@ message(STATUS "${PROJECT_NAME} Ethernet: ${USE_ETHERNET}") message(STATUS "${PROJECT_NAME} Nucleo: ${TARGET_NUCLEO}") message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") -if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers) execute_process( COMMAND git submodule update --init --depth 1 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} ) +endif() + +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) execute_process( COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 From a210bc25a92ef5ecfc89bc9da5cd0dcd6351754f Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 17:10:32 +0100 Subject: [PATCH 098/281] Remove unnecessary warning ignore --- Inc/MockedDrivers/stm32h723xx_wrapper.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index 543ccc993..f363cee7f 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -9,18 +9,14 @@ #endif #define __IO volatile -// necessary remove of some warnings due to cmsis made for 32 bit arch and not 64 bit arch #define __RBIT __RBIT__CMSIS #define TIM_TypeDef TIM_TypeDef__CMSIS -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // don't do anything in "core_cm7.h" #define __CORE_CM7_H_GENERIC #define __CORE_CM7_H_DEPENDANT #include "stm32h723xx.h" -#pragma GCC diagnostic pop #undef __RBIT #undef TIM_TypeDef From 01b24b67e42eff176a2f1c51d5d53257c6f6057a Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:29:22 +0100 Subject: [PATCH 099/281] fix: use wrapper instead of interface for stm32h7xx_ll_tim.h --- CMakeLists.txt | 3 +- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Inc/MockedDrivers/common.hpp | 85 +- Inc/MockedDrivers/ll_tim_interface.h | 5217 ----------------------- Inc/MockedDrivers/mocked_ll_tim.hpp | 3 +- Inc/MockedDrivers/stm32h723xx_wrapper.h | 13 +- 6 files changed, 26 insertions(+), 5297 deletions(-) delete mode 100644 Inc/MockedDrivers/ll_tim_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e390832cf..dfb2cfe6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,7 +292,8 @@ target_include_directories(${STLIB_LIBRARY} PUBLIC ${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include ${STM32CUBEH7}/Drivers/CMSIS/Include $<$:${STM32CUBEH7}/Drivers/CMSIS/Core_A/Include> - $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc> + #$<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc> + ${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy> # LWIP includes diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 1d246b45c..256afe309 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -9,7 +9,7 @@ #ifndef TESTING_ENV #include "stm32h7xx_ll_tim.h" #else - #include "MockedDrivers/ll_tim_interface.h" + #include "MockedDrivers/stm32h7xx_ll_tim_wrapper.h" #endif #include #include diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 80f9d3c91..76326dc42 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -13,25 +13,20 @@ #define __OM volatile /*! Defines 'write only' structure member permissions */ #define __IOM volatile /*! Defines 'read / write' structure member permissions */ -typedef enum -{ - RESET = 0, - SET = !RESET -} FlagStatus, ITStatus; - -typedef enum -{ - DISABLE = 0, - ENABLE = !DISABLE -} FunctionalState; #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) -typedef enum -{ - SUCCESS = 0, - ERROR = !SUCCESS -} ErrorStatus; - +#ifdef SET_BIT +# undef SET_BIT +#endif +#ifdef CLEAR_BIT +# undef CLEAR_BIT +#endif +#ifdef WRITE_REG +# undef WRITE_REG +#endif +#ifdef MODIFY_REG +# undef MODIFY_REG +#endif #define SET_BIT(REG, BIT) ((REG) |= (BIT)) @@ -48,59 +43,3 @@ typedef enum #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) - - -/* Use of CMSIS compiler intrinsics for register exclusive access */ -/* Atomic 32-bit register access macro to set one or several bits */ -#define ATOMIC_SET_BIT(REG, BIT) \ - do { \ - uint32_t val; \ - do { \ - val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \ - } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 32-bit register access macro to clear one or several bits */ -#define ATOMIC_CLEAR_BIT(REG, BIT) \ - do { \ - uint32_t val; \ - do { \ - val = __LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(BIT); \ - } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 32-bit register access macro to clear and set one or several bits */ -#define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \ - do { \ - uint32_t val; \ - do { \ - val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(CLEARMSK)) | (SETMASK); \ - } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 16-bit register access macro to set one or several bits */ -#define ATOMIC_SETH_BIT(REG, BIT) \ - do { \ - uint16_t val; \ - do { \ - val = __LDREXH((__IO uint16_t *)&(REG)) | (BIT); \ - } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 16-bit register access macro to clear one or several bits */ -#define ATOMIC_CLEARH_BIT(REG, BIT) \ - do { \ - uint16_t val; \ - do { \ - val = __LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(BIT); \ - } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 16-bit register access macro to clear and set one or several bits */ -#define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) \ - do { \ - uint16_t val; \ - do { \ - val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(CLEARMSK)) | (SETMASK); \ - } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ - } while(0) diff --git a/Inc/MockedDrivers/ll_tim_interface.h b/Inc/MockedDrivers/ll_tim_interface.h deleted file mode 100644 index 60d63a387..000000000 --- a/Inc/MockedDrivers/ll_tim_interface.h +++ /dev/null @@ -1,5217 +0,0 @@ -/** - ****************************************************************************** - * @file stm32h7xx_ll_tim.h - * @author MCD Application Team - * @brief Header file of TIM LL 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_LL_TIM_H -#define __STM32H7xx_LL_TIM_H - -#include "stm32h723xx_wrapper.h" -#include "mocked_ll_tim.hpp" - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -//#define TIM1 - -/** @addtogroup STM32H7xx_LL_Driver - * @{ - */ - -#if defined (TIM1) || defined (TIM2) || defined (TIM3) || defined (TIM4) || defined (TIM5) || defined (TIM6) || defined (TIM7) || defined (TIM8) || defined (TIM12) || defined (TIM13) || defined (TIM14) || defined (TIM15) || defined (TIM16) || defined (TIM17) || defined (TIM23) || defined (TIM24) - -/** @defgroup TIM_LL TIM - * @{ - */ - -/* Private types -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/** @defgroup TIM_LL_Private_Variables TIM Private Variables - * @{ - */ -static const uint8_t OFFSET_TAB_CCMRx[] = -{ - 0x00U, /* 0: TIMx_CH1 */ - 0x00U, /* 1: TIMx_CH1N */ - 0x00U, /* 2: TIMx_CH2 */ - 0x00U, /* 3: TIMx_CH2N */ - 0x04U, /* 4: TIMx_CH3 */ - 0x04U, /* 5: TIMx_CH3N */ - 0x04U, /* 6: TIMx_CH4 */ - 0x3CU, /* 7: TIMx_CH5 */ - 0x3CU /* 8: TIMx_CH6 */ -}; - -static const uint8_t SHIFT_TAB_OCxx[] = -{ - 0U, /* 0: OC1M, OC1FE, OC1PE */ - 0U, /* 1: - NA */ - 8U, /* 2: OC2M, OC2FE, OC2PE */ - 0U, /* 3: - NA */ - 0U, /* 4: OC3M, OC3FE, OC3PE */ - 0U, /* 5: - NA */ - 8U, /* 6: OC4M, OC4FE, OC4PE */ - 0U, /* 7: OC5M, OC5FE, OC5PE */ - 8U /* 8: OC6M, OC6FE, OC6PE */ -}; - -static const uint8_t SHIFT_TAB_ICxx[] = -{ - 0U, /* 0: CC1S, IC1PSC, IC1F */ - 0U, /* 1: - NA */ - 8U, /* 2: CC2S, IC2PSC, IC2F */ - 0U, /* 3: - NA */ - 0U, /* 4: CC3S, IC3PSC, IC3F */ - 0U, /* 5: - NA */ - 8U, /* 6: CC4S, IC4PSC, IC4F */ - 0U, /* 7: - NA */ - 0U /* 8: - NA */ -}; - -static const uint8_t SHIFT_TAB_CCxP[] = -{ - 0U, /* 0: CC1P */ - 2U, /* 1: CC1NP */ - 4U, /* 2: CC2P */ - 6U, /* 3: CC2NP */ - 8U, /* 4: CC3P */ - 10U, /* 5: CC3NP */ - 12U, /* 6: CC4P */ - 16U, /* 7: CC5P */ - 20U /* 8: CC6P */ -}; - -static const uint8_t SHIFT_TAB_OISx[] = -{ - 0U, /* 0: OIS1 */ - 1U, /* 1: OIS1N */ - 2U, /* 2: OIS2 */ - 3U, /* 3: OIS2N */ - 4U, /* 4: OIS3 */ - 5U, /* 5: OIS3N */ - 6U, /* 6: OIS4 */ - 8U, /* 7: OIS5 */ - 10U /* 8: OIS6 */ -}; -/** - * @} - */ - -/* Private constants ---------------------------------------------------------*/ -/** @defgroup TIM_LL_Private_Constants TIM Private Constants - * @{ - */ - -#if defined(TIM_BREAK_INPUT_SUPPORT) -/* Defines used for the bit position in the register and perform offsets */ -#define TIM_POSITION_BRK_SOURCE (POSITION_VAL(Source) & 0x1FUL) - -/* Generic bit definitions for TIMx_AF1 register */ -#define TIMx_AF1_BKINP TIM1_AF1_BKINP /*!< BRK BKIN input polarity */ -#define TIMx_AF1_ETRSEL TIM1_AF1_ETRSEL /*!< TIMx ETR source selection */ -#endif /* TIM_BREAK_INPUT_SUPPORT */ - - -/* Mask used to set the TDG[x:0] of the DTG bits of the TIMx_BDTR register */ -#define DT_DELAY_1 ((uint8_t)0x7F) -#define DT_DELAY_2 ((uint8_t)0x3F) -#define DT_DELAY_3 ((uint8_t)0x1F) -#define DT_DELAY_4 ((uint8_t)0x1F) - -/* Mask used to set the DTG[7:5] bits of the DTG bits of the TIMx_BDTR register */ -#define DT_RANGE_1 ((uint8_t)0x00) -#define DT_RANGE_2 ((uint8_t)0x80) -#define DT_RANGE_3 ((uint8_t)0xC0) -#define DT_RANGE_4 ((uint8_t)0xE0) - - -/** - * @} - */ - -/* Private macros ------------------------------------------------------------*/ -/** @defgroup TIM_LL_Private_Macros TIM Private Macros - * @{ - */ -/** @brief Convert channel id into channel index. - * @param __CHANNEL__ This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval none - */ -#define TIM_GET_CHANNEL_INDEX( __CHANNEL__) \ - (((__CHANNEL__) == LL_TIM_CHANNEL_CH1) ? 0U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH1N) ? 1U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH2) ? 2U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH2N) ? 3U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH3) ? 4U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH3N) ? 5U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH4) ? 6U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH5) ? 7U : 8U) - -/** @brief Calculate the deadtime sampling period(in ps). - * @param __TIMCLK__ timer input clock frequency (in Hz). - * @param __CKD__ This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - * @retval none - */ -#define TIM_CALC_DTS(__TIMCLK__, __CKD__) \ - (((__CKD__) == LL_TIM_CLOCKDIVISION_DIV1) ? ((uint64_t)1000000000000U/(__TIMCLK__)) : \ - ((__CKD__) == LL_TIM_CLOCKDIVISION_DIV2) ? ((uint64_t)1000000000000U/((__TIMCLK__) >> 1U)) : \ - ((uint64_t)1000000000000U/((__TIMCLK__) >> 2U))) -/** - * @} - */ - - -/* Exported types ------------------------------------------------------------*/ -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_ES_INIT TIM Exported Init structure - * @{ - */ - -/** - * @brief TIM Time Base configuration structure definition. - */ -typedef struct -{ - uint16_t Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock. - This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetPrescaler().*/ - - uint32_t CounterMode; /*!< Specifies the counter mode. - This parameter can be a value of @ref TIM_LL_EC_COUNTERMODE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetCounterMode().*/ - - uint32_t Autoreload; /*!< Specifies the auto reload value to be loaded into the active - Auto-Reload Register at the next update event. - This parameter must be a number between Min_Data=0x0000 and Max_Data=0xFFFF. - Some timer instances may support 32 bits counters. In that case this parameter must - be a number between 0x0000 and 0xFFFFFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetAutoReload().*/ - - uint32_t ClockDivision; /*!< Specifies the clock division. - This parameter can be a value of @ref TIM_LL_EC_CLOCKDIVISION. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetClockDivision().*/ - - uint32_t RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter - reaches zero, an update event is generated and counting restarts - from the RCR value (N). - This means in PWM mode that (N+1) corresponds to: - - the number of PWM periods in edge-aligned mode - - the number of half PWM period in center-aligned mode - GP timers: this parameter must be a number between Min_Data = 0x00 and - Max_Data = 0xFF. - Advanced timers: this parameter must be a number between Min_Data = 0x0000 and - Max_Data = 0xFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetRepetitionCounter().*/ -} LL_TIM_InitTypeDef; - -/** - * @brief TIM Output Compare configuration structure definition. - */ -typedef struct -{ - uint32_t OCMode; /*!< Specifies the output mode. - This parameter can be a value of @ref TIM_LL_EC_OCMODE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetMode().*/ - - uint32_t OCState; /*!< Specifies the TIM Output Compare state. - This parameter can be a value of @ref TIM_LL_EC_OCSTATE. - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ - - uint32_t OCNState; /*!< Specifies the TIM complementary Output Compare state. - This parameter can be a value of @ref TIM_LL_EC_OCSTATE. - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ - - uint32_t CompareValue; /*!< Specifies the Compare value to be loaded into the Capture Compare Register. - This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. - - This feature can be modified afterwards using unitary function - LL_TIM_OC_SetCompareCHx (x=1..6).*/ - - uint32_t OCPolarity; /*!< Specifies the output polarity. - This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetPolarity().*/ - - uint32_t OCNPolarity; /*!< Specifies the complementary output polarity. - This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetPolarity().*/ - - - uint32_t OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. - This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetIdleState().*/ - - uint32_t OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. - This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetIdleState().*/ -} LL_TIM_OC_InitTypeDef; - -/** - * @brief TIM Input Capture configuration structure definition. - */ - -typedef struct -{ - - uint32_t ICPolarity; /*!< Specifies the active edge of the input signal. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t ICActiveInput; /*!< Specifies the input. - This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetActiveInput().*/ - - uint32_t ICPrescaler; /*!< Specifies the Input Capture Prescaler. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t ICFilter; /*!< Specifies the input capture filter. - This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ -} LL_TIM_IC_InitTypeDef; - - -/** - * @brief TIM Encoder interface configuration structure definition. - */ -typedef struct -{ - uint32_t EncoderMode; /*!< Specifies the encoder resolution (x2 or x4). - This parameter can be a value of @ref TIM_LL_EC_ENCODERMODE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetEncoderMode().*/ - - uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t IC1ActiveInput; /*!< Specifies the TI1 input source - This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetActiveInput().*/ - - uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t IC1Filter; /*!< Specifies the TI1 input filter. - This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ - - uint32_t IC2Polarity; /*!< Specifies the active edge of TI2 input. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t IC2ActiveInput; /*!< Specifies the TI2 input source - This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetActiveInput().*/ - - uint32_t IC2Prescaler; /*!< Specifies the TI2 input prescaler value. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t IC2Filter; /*!< Specifies the TI2 input filter. - This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ - -} LL_TIM_ENCODER_InitTypeDef; - -/** - * @brief TIM Hall sensor interface configuration structure definition. - */ -typedef struct -{ - - uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. - Prescaler must be set to get a maximum counter period longer than the - time interval between 2 consecutive changes on the Hall inputs. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t IC1Filter; /*!< Specifies the TI1 input filter. - This parameter can be a value of - @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ - - uint32_t CommutationDelay; /*!< Specifies the compare value to be loaded into the Capture Compare Register. - A positive pulse (TRGO event) is generated with a programmable delay every time - a change occurs on the Hall inputs. - This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetCompareCH2().*/ -} LL_TIM_HALLSENSOR_InitTypeDef; - -/** - * @brief BDTR (Break and Dead Time) structure definition - */ -typedef struct -{ - uint32_t OSSRState; /*!< Specifies the Off-State selection used in Run mode. - This parameter can be a value of @ref TIM_LL_EC_OSSR - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetOffStates() - - @note This bit-field cannot be modified as long as LOCK level 2 has been - programmed. */ - - uint32_t OSSIState; /*!< Specifies the Off-State used in Idle state. - This parameter can be a value of @ref TIM_LL_EC_OSSI - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetOffStates() - - @note This bit-field cannot be modified as long as LOCK level 2 has been - programmed. */ - - uint32_t LockLevel; /*!< Specifies the LOCK level parameters. - This parameter can be a value of @ref TIM_LL_EC_LOCKLEVEL - - @note The LOCK bits can be written only once after the reset. Once the TIMx_BDTR - register has been written, their content is frozen until the next reset.*/ - - uint8_t DeadTime; /*!< Specifies the delay time between the switching-off and the - switching-on of the outputs. - This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetDeadTime() - - @note This bit-field can not be modified as long as LOCK level 1, 2 or 3 has been - programmed. */ - - uint16_t BreakState; /*!< Specifies whether the TIM Break input is enabled or not. - This parameter can be a value of @ref TIM_LL_EC_BREAK_ENABLE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_EnableBRK() or @ref LL_TIM_DisableBRK() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t BreakPolarity; /*!< Specifies the TIM Break Input pin polarity. - This parameter can be a value of @ref TIM_LL_EC_BREAK_POLARITY - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t BreakFilter; /*!< Specifies the TIM Break Filter. - This parameter can be a value of @ref TIM_LL_EC_BREAK_FILTER - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#if defined(TIM_BDTR_BKBID) - uint32_t BreakAFMode; /*!< Specifies the alternate function mode of the break input. - This parameter can be a value of @ref TIM_LL_EC_BREAK_AFMODE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_ConfigBRK() - - @note Bidirectional break input is only supported by advanced timers instances. - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#endif /*TIM_BDTR_BKBID */ - uint32_t Break2State; /*!< Specifies whether the TIM Break2 input is enabled or not. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_ENABLE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_EnableBRK2() or @ref LL_TIM_DisableBRK2() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t Break2Polarity; /*!< Specifies the TIM Break2 Input pin polarity. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_POLARITY - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK2() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t Break2Filter; /*!< Specifies the TIM Break2 Filter. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_FILTER - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK2() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#if defined(TIM_BDTR_BKBID) - uint32_t Break2AFMode; /*!< Specifies the alternate function mode of the break2 input. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_AFMODE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_ConfigBRK2() - - @note Bidirectional break input is only supported by advanced timers instances. - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#endif /*TIM_BDTR_BKBID */ - uint32_t AutomaticOutput; /*!< Specifies whether the TIM Automatic Output feature is enabled or not. - This parameter can be a value of @ref TIM_LL_EC_AUTOMATICOUTPUT_ENABLE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_EnableAutomaticOutput() or @ref LL_TIM_DisableAutomaticOutput() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ -} LL_TIM_BDTR_InitTypeDef; - -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/* Exported constants --------------------------------------------------------*/ -/** @defgroup TIM_LL_Exported_Constants TIM Exported Constants - * @{ - */ - -/** @defgroup TIM_LL_EC_GET_FLAG Get Flags Defines - * @brief Flags defines which can be used with LL_TIM_ReadReg function. - * @{ - */ -#define LL_TIM_SR_UIF TIM_SR_UIF /*!< Update interrupt flag */ -#define LL_TIM_SR_CC1IF TIM_SR_CC1IF /*!< Capture/compare 1 interrupt flag */ -#define LL_TIM_SR_CC2IF TIM_SR_CC2IF /*!< Capture/compare 2 interrupt flag */ -#define LL_TIM_SR_CC3IF TIM_SR_CC3IF /*!< Capture/compare 3 interrupt flag */ -#define LL_TIM_SR_CC4IF TIM_SR_CC4IF /*!< Capture/compare 4 interrupt flag */ -#define LL_TIM_SR_CC5IF TIM_SR_CC5IF /*!< Capture/compare 5 interrupt flag */ -#define LL_TIM_SR_CC6IF TIM_SR_CC6IF /*!< Capture/compare 6 interrupt flag */ -#define LL_TIM_SR_COMIF TIM_SR_COMIF /*!< COM interrupt flag */ -#define LL_TIM_SR_TIF TIM_SR_TIF /*!< Trigger interrupt flag */ -#define LL_TIM_SR_BIF TIM_SR_BIF /*!< Break interrupt flag */ -#define LL_TIM_SR_B2IF TIM_SR_B2IF /*!< Second break interrupt flag */ -#define LL_TIM_SR_CC1OF TIM_SR_CC1OF /*!< Capture/Compare 1 overcapture flag */ -#define LL_TIM_SR_CC2OF TIM_SR_CC2OF /*!< Capture/Compare 2 overcapture flag */ -#define LL_TIM_SR_CC3OF TIM_SR_CC3OF /*!< Capture/Compare 3 overcapture flag */ -#define LL_TIM_SR_CC4OF TIM_SR_CC4OF /*!< Capture/Compare 4 overcapture flag */ -#define LL_TIM_SR_SBIF TIM_SR_SBIF /*!< System Break interrupt flag */ -/** - * @} - */ - -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_EC_BREAK_ENABLE Break Enable - * @{ - */ -#define LL_TIM_BREAK_DISABLE 0x00000000U /*!< Break function disabled */ -#define LL_TIM_BREAK_ENABLE TIM_BDTR_BKE /*!< Break function enabled */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_BREAK2_ENABLE Break2 Enable - * @{ - */ -#define LL_TIM_BREAK2_DISABLE 0x00000000U /*!< Break2 function disabled */ -#define LL_TIM_BREAK2_ENABLE TIM_BDTR_BK2E /*!< Break2 function enabled */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_AUTOMATICOUTPUT_ENABLE Automatic output enable - * @{ - */ -#define LL_TIM_AUTOMATICOUTPUT_DISABLE 0x00000000U /*!< MOE can be set only by software */ -#define LL_TIM_AUTOMATICOUTPUT_ENABLE TIM_BDTR_AOE /*!< MOE can be set by software or automatically at the next update event */ -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/** @defgroup TIM_LL_EC_IT IT Defines - * @brief IT defines which can be used with LL_TIM_ReadReg and LL_TIM_WriteReg functions. - * @{ - */ -#define LL_TIM_DIER_UIE TIM_DIER_UIE /*!< Update interrupt enable */ -#define LL_TIM_DIER_CC1IE TIM_DIER_CC1IE /*!< Capture/compare 1 interrupt enable */ -#define LL_TIM_DIER_CC2IE TIM_DIER_CC2IE /*!< Capture/compare 2 interrupt enable */ -#define LL_TIM_DIER_CC3IE TIM_DIER_CC3IE /*!< Capture/compare 3 interrupt enable */ -#define LL_TIM_DIER_CC4IE TIM_DIER_CC4IE /*!< Capture/compare 4 interrupt enable */ -#define LL_TIM_DIER_COMIE TIM_DIER_COMIE /*!< COM interrupt enable */ -#define LL_TIM_DIER_TIE TIM_DIER_TIE /*!< Trigger interrupt enable */ -#define LL_TIM_DIER_BIE TIM_DIER_BIE /*!< Break interrupt enable */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_UPDATESOURCE Update Source - * @{ - */ -#define LL_TIM_UPDATESOURCE_REGULAR 0x00000000U /*!< Counter overflow/underflow, Setting the UG bit or Update generation through the slave mode controller generates an update request */ -#define LL_TIM_UPDATESOURCE_COUNTER TIM_CR1_URS /*!< Only counter overflow/underflow generates an update request */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_ONEPULSEMODE One Pulse Mode - * @{ - */ -#define LL_TIM_ONEPULSEMODE_SINGLE TIM_CR1_OPM /*!< Counter stops counting at the next update event */ -#define LL_TIM_ONEPULSEMODE_REPETITIVE 0x00000000U /*!< Counter is not stopped at update event */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_COUNTERMODE Counter Mode - * @{ - */ -#define LL_TIM_COUNTERMODE_UP 0x00000000U /*!< Counter used as upcounter */ -#define LL_TIM_COUNTERMODE_DOWN TIM_CR1_DIR /*!< Counter used as downcounter */ -#define LL_TIM_COUNTERMODE_CENTER_DOWN TIM_CR1_CMS_0 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting down. */ -#define LL_TIM_COUNTERMODE_CENTER_UP TIM_CR1_CMS_1 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up */ -#define LL_TIM_COUNTERMODE_CENTER_UP_DOWN TIM_CR1_CMS /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up or down. */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CLOCKDIVISION Clock Division - * @{ - */ -#define LL_TIM_CLOCKDIVISION_DIV1 0x00000000U /*!< tDTS=tCK_INT */ -#define LL_TIM_CLOCKDIVISION_DIV2 TIM_CR1_CKD_0 /*!< tDTS=2*tCK_INT */ -#define LL_TIM_CLOCKDIVISION_DIV4 TIM_CR1_CKD_1 /*!< tDTS=4*tCK_INT */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_COUNTERDIRECTION Counter Direction - * @{ - */ -#define LL_TIM_COUNTERDIRECTION_UP 0x00000000U /*!< Timer counter counts up */ -#define LL_TIM_COUNTERDIRECTION_DOWN TIM_CR1_DIR /*!< Timer counter counts down */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CCUPDATESOURCE Capture Compare Update Source - * @{ - */ -#define LL_TIM_CCUPDATESOURCE_COMG_ONLY 0x00000000U /*!< Capture/compare control bits are updated by setting the COMG bit only */ -#define LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI TIM_CR2_CCUS /*!< Capture/compare control bits are updated by setting the COMG bit or when a rising edge occurs on trigger input (TRGI) */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CCDMAREQUEST Capture Compare DMA Request - * @{ - */ -#define LL_TIM_CCDMAREQUEST_CC 0x00000000U /*!< CCx DMA request sent when CCx event occurs */ -#define LL_TIM_CCDMAREQUEST_UPDATE TIM_CR2_CCDS /*!< CCx DMA requests sent when update event occurs */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_LOCKLEVEL Lock Level - * @{ - */ -#define LL_TIM_LOCKLEVEL_OFF 0x00000000U /*!< LOCK OFF - No bit is write protected */ -#define LL_TIM_LOCKLEVEL_1 TIM_BDTR_LOCK_0 /*!< LOCK Level 1 */ -#define LL_TIM_LOCKLEVEL_2 TIM_BDTR_LOCK_1 /*!< LOCK Level 2 */ -#define LL_TIM_LOCKLEVEL_3 TIM_BDTR_LOCK /*!< LOCK Level 3 */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CHANNEL Channel - * @{ - */ -#define LL_TIM_CHANNEL_CH1 TIM_CCER_CC1E /*!< Timer input/output channel 1 */ -#define LL_TIM_CHANNEL_CH1N TIM_CCER_CC1NE /*!< Timer complementary output channel 1 */ -#define LL_TIM_CHANNEL_CH2 TIM_CCER_CC2E /*!< Timer input/output channel 2 */ -#define LL_TIM_CHANNEL_CH2N TIM_CCER_CC2NE /*!< Timer complementary output channel 2 */ -#define LL_TIM_CHANNEL_CH3 TIM_CCER_CC3E /*!< Timer input/output channel 3 */ -#define LL_TIM_CHANNEL_CH3N TIM_CCER_CC3NE /*!< Timer complementary output channel 3 */ -#define LL_TIM_CHANNEL_CH4 TIM_CCER_CC4E /*!< Timer input/output channel 4 */ -#define LL_TIM_CHANNEL_CH5 TIM_CCER_CC5E /*!< Timer output channel 5 */ -#define LL_TIM_CHANNEL_CH6 TIM_CCER_CC6E /*!< Timer output channel 6 */ -/** - * @} - */ - -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_EC_OCSTATE Output Configuration State - * @{ - */ -#define LL_TIM_OCSTATE_DISABLE 0x00000000U /*!< OCx is not active */ -#define LL_TIM_OCSTATE_ENABLE TIM_CCER_CC1E /*!< OCx signal is output on the corresponding output pin */ -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/** Legacy definitions for compatibility purpose -@cond 0 - */ -#define LL_TIM_OCMODE_ASSYMETRIC_PWM1 LL_TIM_OCMODE_ASYMMETRIC_PWM1 -#define LL_TIM_OCMODE_ASSYMETRIC_PWM2 LL_TIM_OCMODE_ASYMMETRIC_PWM2 -/** -@endcond - */ - -/** @defgroup TIM_LL_EC_OCMODE Output Configuration Mode - * @{ - */ -#define LL_TIM_OCMODE_FROZEN 0x00000000U /*!TIMx_CCRy else active.*/ -#define LL_TIM_OCMODE_PWM2 (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0) /*!TIMx_CCRy else inactive*/ -#define LL_TIM_OCMODE_RETRIG_OPM1 TIM_CCMR1_OC1M_3 /*!__REG__, (__VALUE__)) - -/** - * @brief Read a value in TIM register. - * @param __INSTANCE__ TIM Instance - * @param __REG__ Register to be read - * @retval Register value - */ -#define LL_TIM_ReadReg(__INSTANCE__, __REG__) READ_REG((__INSTANCE__)->__REG__) -/** - * @} - */ - -/** - * @brief HELPER macro retrieving the UIFCPY flag from the counter value. - * @note ex: @ref __LL_TIM_GETFLAG_UIFCPY (@ref LL_TIM_GetCounter ()); - * @note Relevant only if UIF flag remapping has been enabled (UIF status bit is copied - * to TIMx_CNT register bit 31) - * @param __CNT__ Counter value - * @retval UIF status bit - */ -#define __LL_TIM_GETFLAG_UIFCPY(__CNT__) \ - (READ_BIT((__CNT__), TIM_CNT_UIFCPY) >> TIM_CNT_UIFCPY_Pos) - -/** - * @brief HELPER macro calculating DTG[0:7] in the TIMx_BDTR register to achieve the requested dead time duration. - * @note ex: @ref __LL_TIM_CALC_DEADTIME (80000000, @ref LL_TIM_GetClockDivision (), 120); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __CKD__ This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - * @param __DT__ deadtime duration (in ns) - * @retval DTG[0:7] - */ -#define __LL_TIM_CALC_DEADTIME(__TIMCLK__, __CKD__, __DT__) \ - ( (((uint64_t)((__DT__)*1000U)) < ((DT_DELAY_1+1U) * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(((uint64_t)((__DT__)*1000U) / TIM_CALC_DTS((__TIMCLK__), (__CKD__))) & DT_DELAY_1) : \ - (((uint64_t)((__DT__)*1000U)) < ((64U + (DT_DELAY_2+1U)) * 2U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(DT_RANGE_2 | ((uint8_t)((uint8_t)((((uint64_t)((__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ - (__CKD__))) >> 1U) - (uint8_t) 64) & DT_DELAY_2)) :\ - (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_3+1U)) * 8U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(DT_RANGE_3 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ - (__CKD__))) >> 3U) - (uint8_t) 32) & DT_DELAY_3)) :\ - (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_4+1U)) * 16U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(DT_RANGE_4 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ - (__CKD__))) >> 4U) - (uint8_t) 32) & DT_DELAY_4)) :\ - 0U) - -/** - * @brief HELPER macro calculating the prescaler value to achieve the required counter clock frequency. - * @note ex: @ref __LL_TIM_CALC_PSC (80000000, 1000000); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __CNTCLK__ counter clock frequency (in Hz) - * @retval Prescaler value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_PSC(__TIMCLK__, __CNTCLK__) \ - (((__TIMCLK__) >= (__CNTCLK__)) ? (uint32_t)((((__TIMCLK__) + (__CNTCLK__)/2U)/(__CNTCLK__)) - 1U) : 0U) - -/** - * @brief HELPER macro calculating the auto-reload value to achieve the required output signal frequency. - * @note ex: @ref __LL_TIM_CALC_ARR (1000000, @ref LL_TIM_GetPrescaler (), 10000); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __PSC__ prescaler - * @param __FREQ__ output signal frequency (in Hz) - * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_ARR(__TIMCLK__, __PSC__, __FREQ__) \ - ((((__TIMCLK__)/((__PSC__) + 1U)) >= (__FREQ__)) ? (((__TIMCLK__)/((__FREQ__) * ((__PSC__) + 1U))) - 1U) : 0U) - -/** - * @brief HELPER macro calculating the compare value required to achieve the required timer output compare - * active/inactive delay. - * @note ex: @ref __LL_TIM_CALC_DELAY (1000000, @ref LL_TIM_GetPrescaler (), 10); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __PSC__ prescaler - * @param __DELAY__ timer output compare active/inactive delay (in us) - * @retval Compare value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_DELAY(__TIMCLK__, __PSC__, __DELAY__) \ - ((uint32_t)(((uint64_t)(__TIMCLK__) * (uint64_t)(__DELAY__)) \ - / ((uint64_t)1000000U * (uint64_t)((__PSC__) + 1U)))) - -/** - * @brief HELPER macro calculating the auto-reload value to achieve the required pulse duration - * (when the timer operates in one pulse mode). - * @note ex: @ref __LL_TIM_CALC_PULSE (1000000, @ref LL_TIM_GetPrescaler (), 10, 20); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __PSC__ prescaler - * @param __DELAY__ timer output compare active/inactive delay (in us) - * @param __PULSE__ pulse duration (in us) - * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_PULSE(__TIMCLK__, __PSC__, __DELAY__, __PULSE__) \ - ((uint32_t)(__LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__PULSE__)) \ - + __LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__DELAY__)))) - -/** - * @brief HELPER macro retrieving the ratio of the input capture prescaler - * @note ex: @ref __LL_TIM_GET_ICPSC_RATIO (@ref LL_TIM_IC_GetPrescaler ()); - * @param __ICPSC__ This parameter can be one of the following values: - * @arg @ref LL_TIM_ICPSC_DIV1 - * @arg @ref LL_TIM_ICPSC_DIV2 - * @arg @ref LL_TIM_ICPSC_DIV4 - * @arg @ref LL_TIM_ICPSC_DIV8 - * @retval Input capture prescaler ratio (1, 2, 4 or 8) - */ -#define __LL_TIM_GET_ICPSC_RATIO(__ICPSC__) \ - ((uint32_t)(0x01U << (((__ICPSC__) >> 16U) >> TIM_CCMR1_IC1PSC_Pos))) - - -/** - * @} - */ - -/* Exported functions --------------------------------------------------------*/ -/** @defgroup TIM_LL_Exported_Functions TIM Exported Functions - * @{ - */ - -/** @defgroup TIM_LL_EF_Time_Base Time Base configuration - * @{ - */ -/** - * @brief Enable timer counter. - * @rmtoll CR1 CEN LL_TIM_EnableCounter - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableCounter(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_CEN); -} - -/** - * @brief Disable timer counter. - * @rmtoll CR1 CEN LL_TIM_DisableCounter - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableCounter(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_CEN); -} - -/** - * @brief Indicates whether the timer counter is enabled. - * @rmtoll CR1 CEN LL_TIM_IsEnabledCounter - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledCounter(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR1, TIM_CR1_CEN) == (TIM_CR1_CEN)) ? 1UL : 0UL); -} - -/** - * @brief Enable update event generation. - * @rmtoll CR1 UDIS LL_TIM_EnableUpdateEvent - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableUpdateEvent(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_UDIS); -} - -/** - * @brief Disable update event generation. - * @rmtoll CR1 UDIS LL_TIM_DisableUpdateEvent - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableUpdateEvent(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_UDIS); -} - -/** - * @brief Indicates whether update event generation is enabled. - * @rmtoll CR1 UDIS LL_TIM_IsEnabledUpdateEvent - * @param TIMx Timer instance - * @retval Inverted state of bit (0 or 1). - */ -static inline uint32_t LL_TIM_IsEnabledUpdateEvent(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR1, TIM_CR1_UDIS) == (uint32_t)RESET) ? 1UL : 0UL); -} - -/** - * @brief Set update event source - * @note Update event source set to LL_TIM_UPDATESOURCE_REGULAR: any of the following events - * generate an update interrupt or DMA request if enabled: - * - Counter overflow/underflow - * - Setting the UG bit - * - Update generation through the slave mode controller - * @note Update event source set to LL_TIM_UPDATESOURCE_COUNTER: only counter - * overflow/underflow generates an update interrupt or DMA request if enabled. - * @rmtoll CR1 URS LL_TIM_SetUpdateSource - * @param TIMx Timer instance - * @param UpdateSource This parameter can be one of the following values: - * @arg @ref LL_TIM_UPDATESOURCE_REGULAR - * @arg @ref LL_TIM_UPDATESOURCE_COUNTER - * @retval None - */ -static inline void LL_TIM_SetUpdateSource(TIM_TypeDef *TIMx, uint32_t UpdateSource) -{ - MODIFY_REG(TIMx->CR1, TIM_CR1_URS, UpdateSource); -} - -/** - * @brief Get actual event update source - * @rmtoll CR1 URS LL_TIM_GetUpdateSource - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_UPDATESOURCE_REGULAR - * @arg @ref LL_TIM_UPDATESOURCE_COUNTER - */ -static inline uint32_t LL_TIM_GetUpdateSource(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_URS)); -} - -/** - * @brief Set one pulse mode (one shot v.s. repetitive). - * @rmtoll CR1 OPM LL_TIM_SetOnePulseMode - * @param TIMx Timer instance - * @param OnePulseMode This parameter can be one of the following values: - * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE - * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE - * @retval None - */ -static inline void LL_TIM_SetOnePulseMode(TIM_TypeDef *TIMx, uint32_t OnePulseMode) -{ - MODIFY_REG(TIMx->CR1, TIM_CR1_OPM, OnePulseMode); -} - -/** - * @brief Get actual one pulse mode. - * @rmtoll CR1 OPM LL_TIM_GetOnePulseMode - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE - * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE - */ -static inline uint32_t LL_TIM_GetOnePulseMode(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_OPM)); -} - -/** - * @brief Set the timer counter counting mode. - * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to - * check whether or not the counter mode selection feature is supported - * by a timer instance. - * @note Switching from Center Aligned counter mode to Edge counter mode (or reverse) - * requires a timer reset to avoid unexpected direction - * due to DIR bit readonly in center aligned mode. - * @rmtoll CR1 DIR LL_TIM_SetCounterMode\n - * CR1 CMS LL_TIM_SetCounterMode - * @param TIMx Timer instance - * @param CounterMode This parameter can be one of the following values: - * @arg @ref LL_TIM_COUNTERMODE_UP - * @arg @ref LL_TIM_COUNTERMODE_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP - * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN - * @retval None - */ -static inline void LL_TIM_SetCounterMode(TIM_TypeDef *TIMx, uint32_t CounterMode) -{ - MODIFY_REG(TIMx->CR1, (TIM_CR1_DIR | TIM_CR1_CMS), CounterMode); -} - -/** - * @brief Get actual counter mode. - * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to - * check whether or not the counter mode selection feature is supported - * by a timer instance. - * @rmtoll CR1 DIR LL_TIM_GetCounterMode\n - * CR1 CMS LL_TIM_GetCounterMode - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_COUNTERMODE_UP - * @arg @ref LL_TIM_COUNTERMODE_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP - * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN - */ -static inline uint32_t LL_TIM_GetCounterMode(const TIM_TypeDef *TIMx) -{ - uint32_t counter_mode; - - counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CMS)); - - if (counter_mode == 0U) - { - counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); - } - - return counter_mode; -} - -/** - * @brief Enable auto-reload (ARR) preload. - * @rmtoll CR1 ARPE LL_TIM_EnableARRPreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableARRPreload(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_ARPE); -} - -/** - * @brief Disable auto-reload (ARR) preload. - * @rmtoll CR1 ARPE LL_TIM_DisableARRPreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableARRPreload(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_ARPE); -} - -/** - * @brief Indicates whether auto-reload (ARR) preload is enabled. - * @rmtoll CR1 ARPE LL_TIM_IsEnabledARRPreload - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledARRPreload(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR1, TIM_CR1_ARPE) == (TIM_CR1_ARPE)) ? 1UL : 0UL); -} - -/** - * @brief Set the division ratio between the timer clock and the sampling clock used by the dead-time generators - * (when supported) and the digital filters. - * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check - * whether or not the clock division feature is supported by the timer - * instance. - * @rmtoll CR1 CKD LL_TIM_SetClockDivision - * @param TIMx Timer instance - * @param ClockDivision This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - * @retval None - */ -static inline void LL_TIM_SetClockDivision(TIM_TypeDef *TIMx, uint32_t ClockDivision) -{ - MODIFY_REG(TIMx->CR1, TIM_CR1_CKD, ClockDivision); -} - -/** - * @brief Get the actual division ratio between the timer clock and the sampling clock used by the dead-time - * generators (when supported) and the digital filters. - * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check - * whether or not the clock division feature is supported by the timer - * instance. - * @rmtoll CR1 CKD LL_TIM_GetClockDivision - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - */ -static inline uint32_t LL_TIM_GetClockDivision(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CKD)); -} - -/** - * @brief Set the counter value. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @rmtoll CNT CNT LL_TIM_SetCounter - * @param TIMx Timer instance - * @param Counter Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) - * @retval None - */ -static inline void LL_TIM_SetCounter(TIM_TypeDef *TIMx, uint32_t Counter) -{ - WRITE_REG(TIMx->CNT, Counter); -} - -/** - * @brief Get the counter value. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @rmtoll CNT CNT LL_TIM_GetCounter - * @param TIMx Timer instance - * @retval Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) - */ -static inline uint32_t LL_TIM_GetCounter(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CNT)); -} - -/** - * @brief Get the current direction of the counter - * @rmtoll CR1 DIR LL_TIM_GetDirection - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_COUNTERDIRECTION_UP - * @arg @ref LL_TIM_COUNTERDIRECTION_DOWN - */ -static inline uint32_t LL_TIM_GetDirection(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); -} - -/** - * @brief Set the prescaler value. - * @note The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1). - * @note The prescaler can be changed on the fly as this control register is buffered. The new - * prescaler ratio is taken into account at the next update event. - * @note Helper macro @ref __LL_TIM_CALC_PSC can be used to calculate the Prescaler parameter - * @rmtoll PSC PSC LL_TIM_SetPrescaler - * @param TIMx Timer instance - * @param Prescaler between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Prescaler) -{ - WRITE_REG(TIMx->PSC, Prescaler); -} - -/** - * @brief Get the prescaler value. - * @rmtoll PSC PSC LL_TIM_GetPrescaler - * @param TIMx Timer instance - * @retval Prescaler value between Min_Data=0 and Max_Data=65535 - */ -static inline uint32_t LL_TIM_GetPrescaler(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->PSC)); -} - -/** - * @brief Set the auto-reload value. - * @note The counter is blocked while the auto-reload value is null. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Helper macro @ref __LL_TIM_CALC_ARR can be used to calculate the AutoReload parameter - * @rmtoll ARR ARR LL_TIM_SetAutoReload - * @param TIMx Timer instance - * @param AutoReload between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_SetAutoReload(TIM_TypeDef *TIMx, uint32_t AutoReload) -{ - WRITE_REG(TIMx->ARR, AutoReload); -} - -/** - * @brief Get the auto-reload value. - * @rmtoll ARR ARR LL_TIM_GetAutoReload - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @param TIMx Timer instance - * @retval Auto-reload value - */ -static inline uint32_t LL_TIM_GetAutoReload(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->ARR)); -} - -/** - * @brief Set the repetition counter value. - * @note For advanced timer instances RepetitionCounter can be up to 65535. - * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a repetition counter. - * @rmtoll RCR REP LL_TIM_SetRepetitionCounter - * @param TIMx Timer instance - * @param RepetitionCounter between Min_Data=0 and Max_Data=255 or 65535 for advanced timer. - * @retval None - */ -static inline void LL_TIM_SetRepetitionCounter(TIM_TypeDef *TIMx, uint32_t RepetitionCounter) -{ - WRITE_REG(TIMx->RCR, RepetitionCounter); -} - -/** - * @brief Get the repetition counter value. - * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a repetition counter. - * @rmtoll RCR REP LL_TIM_GetRepetitionCounter - * @param TIMx Timer instance - * @retval Repetition counter value - */ -static inline uint32_t LL_TIM_GetRepetitionCounter(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->RCR)); -} - -/** - * @brief Force a continuous copy of the update interrupt flag (UIF) into the timer counter register (bit 31). - * @note This allows both the counter value and a potential roll-over condition signalled by the UIFCPY flag to be read - * in an atomic way. - * @rmtoll CR1 UIFREMAP LL_TIM_EnableUIFRemap - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableUIFRemap(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); -} - -/** - * @brief Disable update interrupt flag (UIF) remapping. - * @rmtoll CR1 UIFREMAP LL_TIM_DisableUIFRemap - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableUIFRemap(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); -} - -/** - * @brief Indicate whether update interrupt flag (UIF) copy is set. - * @param Counter Counter value - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveUIFCPY(const uint32_t Counter) -{ - return (((Counter & TIM_CNT_UIFCPY) == (TIM_CNT_UIFCPY)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Capture_Compare Capture Compare configuration - * @{ - */ -/** - * @brief Enable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. - * @note CCxE, CCxNE and OCxM bits are preloaded, after having been written, - * they are updated only when a commutation event (COM) occurs. - * @note Only on channels that have a complementary output. - * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check - * whether or not a timer instance is able to generate a commutation event. - * @rmtoll CR2 CCPC LL_TIM_CC_EnablePreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_CC_EnablePreload(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR2, TIM_CR2_CCPC); -} - -/** - * @brief Disable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. - * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check - * whether or not a timer instance is able to generate a commutation event. - * @rmtoll CR2 CCPC LL_TIM_CC_DisablePreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_CC_DisablePreload(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR2, TIM_CR2_CCPC); -} - -/** - * @brief Indicates whether the capture/compare control bits (CCxE, CCxNE and OCxM) preload is enabled. - * @rmtoll CR2 CCPC LL_TIM_CC_IsEnabledPreload - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_CC_IsEnabledPreload(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR2, TIM_CR2_CCPC) == (TIM_CR2_CCPC)) ? 1UL : 0UL); -} - -/** - * @brief Set the updated source of the capture/compare control bits (CCxE, CCxNE and OCxM). - * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check - * whether or not a timer instance is able to generate a commutation event. - * @rmtoll CR2 CCUS LL_TIM_CC_SetUpdate - * @param TIMx Timer instance - * @param CCUpdateSource This parameter can be one of the following values: - * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_ONLY - * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI - * @retval None - */ -static inline void LL_TIM_CC_SetUpdate(TIM_TypeDef *TIMx, uint32_t CCUpdateSource) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_CCUS, CCUpdateSource); -} - -/** - * @brief Set the trigger of the capture/compare DMA request. - * @rmtoll CR2 CCDS LL_TIM_CC_SetDMAReqTrigger - * @param TIMx Timer instance - * @param DMAReqTrigger This parameter can be one of the following values: - * @arg @ref LL_TIM_CCDMAREQUEST_CC - * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE - * @retval None - */ -static inline void LL_TIM_CC_SetDMAReqTrigger(TIM_TypeDef *TIMx, uint32_t DMAReqTrigger) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_CCDS, DMAReqTrigger); -} - -/** - * @brief Get actual trigger of the capture/compare DMA request. - * @rmtoll CR2 CCDS LL_TIM_CC_GetDMAReqTrigger - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_CCDMAREQUEST_CC - * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE - */ -static inline uint32_t LL_TIM_CC_GetDMAReqTrigger(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR2, TIM_CR2_CCDS)); -} - -/** - * @brief Set the lock level to freeze the - * configuration of several capture/compare parameters. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * the lock mechanism is supported by a timer instance. - * @rmtoll BDTR LOCK LL_TIM_CC_SetLockLevel - * @param TIMx Timer instance - * @param LockLevel This parameter can be one of the following values: - * @arg @ref LL_TIM_LOCKLEVEL_OFF - * @arg @ref LL_TIM_LOCKLEVEL_1 - * @arg @ref LL_TIM_LOCKLEVEL_2 - * @arg @ref LL_TIM_LOCKLEVEL_3 - * @retval None - */ -static inline void LL_TIM_CC_SetLockLevel(TIM_TypeDef *TIMx, uint32_t LockLevel) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_LOCK, LockLevel); -} - -/** - * @brief Enable capture/compare channels. - * @rmtoll CCER CC1E LL_TIM_CC_EnableChannel\n - * CCER CC1NE LL_TIM_CC_EnableChannel\n - * CCER CC2E LL_TIM_CC_EnableChannel\n - * CCER CC2NE LL_TIM_CC_EnableChannel\n - * CCER CC3E LL_TIM_CC_EnableChannel\n - * CCER CC3NE LL_TIM_CC_EnableChannel\n - * CCER CC4E LL_TIM_CC_EnableChannel\n - * CCER CC5E LL_TIM_CC_EnableChannel\n - * CCER CC6E LL_TIM_CC_EnableChannel - * @param TIMx Timer instance - * @param Channels This parameter can be a combination of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_CC_EnableChannel(TIM_TypeDef *TIMx, uint32_t Channels) -{ - SET_BIT(TIMx->CCER, Channels); -} - -/** - * @brief Disable capture/compare channels. - * @rmtoll CCER CC1E LL_TIM_CC_DisableChannel\n - * CCER CC1NE LL_TIM_CC_DisableChannel\n - * CCER CC2E LL_TIM_CC_DisableChannel\n - * CCER CC2NE LL_TIM_CC_DisableChannel\n - * CCER CC3E LL_TIM_CC_DisableChannel\n - * CCER CC3NE LL_TIM_CC_DisableChannel\n - * CCER CC4E LL_TIM_CC_DisableChannel\n - * CCER CC5E LL_TIM_CC_DisableChannel\n - * CCER CC6E LL_TIM_CC_DisableChannel - * @param TIMx Timer instance - * @param Channels This parameter can be a combination of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_CC_DisableChannel(TIM_TypeDef *TIMx, uint32_t Channels) -{ - CLEAR_BIT(TIMx->CCER, Channels); -} - -/** - * @brief Indicate whether channel(s) is(are) enabled. - * @rmtoll CCER CC1E LL_TIM_CC_IsEnabledChannel\n - * CCER CC1NE LL_TIM_CC_IsEnabledChannel\n - * CCER CC2E LL_TIM_CC_IsEnabledChannel\n - * CCER CC2NE LL_TIM_CC_IsEnabledChannel\n - * CCER CC3E LL_TIM_CC_IsEnabledChannel\n - * CCER CC3NE LL_TIM_CC_IsEnabledChannel\n - * CCER CC4E LL_TIM_CC_IsEnabledChannel\n - * CCER CC5E LL_TIM_CC_IsEnabledChannel\n - * CCER CC6E LL_TIM_CC_IsEnabledChannel - * @param TIMx Timer instance - * @param Channels This parameter can be a combination of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_CC_IsEnabledChannel(const TIM_TypeDef *TIMx, uint32_t Channels) -{ - return ((READ_BIT(TIMx->CCER, Channels) == (Channels)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Output_Channel Output channel configuration - * @{ - */ -/** - * @brief Configure an output channel. - * @rmtoll CCMR1 CC1S LL_TIM_OC_ConfigOutput\n - * CCMR1 CC2S LL_TIM_OC_ConfigOutput\n - * CCMR2 CC3S LL_TIM_OC_ConfigOutput\n - * CCMR2 CC4S LL_TIM_OC_ConfigOutput\n - * CCMR3 CC5S LL_TIM_OC_ConfigOutput\n - * CCMR3 CC6S LL_TIM_OC_ConfigOutput\n - * CCER CC1P LL_TIM_OC_ConfigOutput\n - * CCER CC2P LL_TIM_OC_ConfigOutput\n - * CCER CC3P LL_TIM_OC_ConfigOutput\n - * CCER CC4P LL_TIM_OC_ConfigOutput\n - * CCER CC5P LL_TIM_OC_ConfigOutput\n - * CCER CC6P LL_TIM_OC_ConfigOutput\n - * CR2 OIS1 LL_TIM_OC_ConfigOutput\n - * CR2 OIS2 LL_TIM_OC_ConfigOutput\n - * CR2 OIS3 LL_TIM_OC_ConfigOutput\n - * CR2 OIS4 LL_TIM_OC_ConfigOutput\n - * CR2 OIS5 LL_TIM_OC_ConfigOutput\n - * CR2 OIS6 LL_TIM_OC_ConfigOutput - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param Configuration This parameter must be a combination of all the following values: - * @arg @ref LL_TIM_OCPOLARITY_HIGH or @ref LL_TIM_OCPOLARITY_LOW - * @arg @ref LL_TIM_OCIDLESTATE_LOW or @ref LL_TIM_OCIDLESTATE_HIGH - * @retval None - */ -static inline void LL_TIM_OC_ConfigOutput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_CC1S << SHIFT_TAB_OCxx[iChannel])); - MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), - (Configuration & TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]); - MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), - (Configuration & TIM_CR2_OIS1) << SHIFT_TAB_OISx[iChannel]); -} - -/** - * @brief Define the behavior of the output reference signal OCxREF from which - * OCx and OCxN (when relevant) are derived. - * @rmtoll CCMR1 OC1M LL_TIM_OC_SetMode\n - * CCMR1 OC2M LL_TIM_OC_SetMode\n - * CCMR2 OC3M LL_TIM_OC_SetMode\n - * CCMR2 OC4M LL_TIM_OC_SetMode\n - * CCMR3 OC5M LL_TIM_OC_SetMode\n - * CCMR3 OC6M LL_TIM_OC_SetMode - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param Mode This parameter can be one of the following values: - * @arg @ref LL_TIM_OCMODE_FROZEN - * @arg @ref LL_TIM_OCMODE_ACTIVE - * @arg @ref LL_TIM_OCMODE_INACTIVE - * @arg @ref LL_TIM_OCMODE_TOGGLE - * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE - * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE - * @arg @ref LL_TIM_OCMODE_PWM1 - * @arg @ref LL_TIM_OCMODE_PWM2 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 - * @retval None - */ -static inline void LL_TIM_OC_SetMode(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Mode) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel]), Mode << SHIFT_TAB_OCxx[iChannel]); -} - -/** - * @brief Get the output compare mode of an output channel. - * @rmtoll CCMR1 OC1M LL_TIM_OC_GetMode\n - * CCMR1 OC2M LL_TIM_OC_GetMode\n - * CCMR2 OC3M LL_TIM_OC_GetMode\n - * CCMR2 OC4M LL_TIM_OC_GetMode\n - * CCMR3 OC5M LL_TIM_OC_GetMode\n - * CCMR3 OC6M LL_TIM_OC_GetMode - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_OCMODE_FROZEN - * @arg @ref LL_TIM_OCMODE_ACTIVE - * @arg @ref LL_TIM_OCMODE_INACTIVE - * @arg @ref LL_TIM_OCMODE_TOGGLE - * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE - * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE - * @arg @ref LL_TIM_OCMODE_PWM1 - * @arg @ref LL_TIM_OCMODE_PWM2 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 - */ -static inline uint32_t LL_TIM_OC_GetMode(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return (READ_BIT(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel])) >> SHIFT_TAB_OCxx[iChannel]); -} - -/** - * @brief Set the polarity of an output channel. - * @rmtoll CCER CC1P LL_TIM_OC_SetPolarity\n - * CCER CC1NP LL_TIM_OC_SetPolarity\n - * CCER CC2P LL_TIM_OC_SetPolarity\n - * CCER CC2NP LL_TIM_OC_SetPolarity\n - * CCER CC3P LL_TIM_OC_SetPolarity\n - * CCER CC3NP LL_TIM_OC_SetPolarity\n - * CCER CC4P LL_TIM_OC_SetPolarity\n - * CCER CC5P LL_TIM_OC_SetPolarity\n - * CCER CC6P LL_TIM_OC_SetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_OCPOLARITY_HIGH - * @arg @ref LL_TIM_OCPOLARITY_LOW - * @retval None - */ -static inline void LL_TIM_OC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Polarity) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), Polarity << SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Get the polarity of an output channel. - * @rmtoll CCER CC1P LL_TIM_OC_GetPolarity\n - * CCER CC1NP LL_TIM_OC_GetPolarity\n - * CCER CC2P LL_TIM_OC_GetPolarity\n - * CCER CC2NP LL_TIM_OC_GetPolarity\n - * CCER CC3P LL_TIM_OC_GetPolarity\n - * CCER CC3NP LL_TIM_OC_GetPolarity\n - * CCER CC4P LL_TIM_OC_GetPolarity\n - * CCER CC5P LL_TIM_OC_GetPolarity\n - * CCER CC6P LL_TIM_OC_GetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_OCPOLARITY_HIGH - * @arg @ref LL_TIM_OCPOLARITY_LOW - */ -static inline uint32_t LL_TIM_OC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - return (READ_BIT(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel])) >> SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Set the IDLE state of an output channel - * @note This function is significant only for the timer instances - * supporting the break feature. Macro IS_TIM_BREAK_INSTANCE(TIMx) - * can be used to check whether or not a timer instance provides - * a break input. - * @rmtoll CR2 OIS1 LL_TIM_OC_SetIdleState\n - * CR2 OIS2N LL_TIM_OC_SetIdleState\n - * CR2 OIS2 LL_TIM_OC_SetIdleState\n - * CR2 OIS2N LL_TIM_OC_SetIdleState\n - * CR2 OIS3 LL_TIM_OC_SetIdleState\n - * CR2 OIS3N LL_TIM_OC_SetIdleState\n - * CR2 OIS4 LL_TIM_OC_SetIdleState\n - * CR2 OIS5 LL_TIM_OC_SetIdleState\n - * CR2 OIS6 LL_TIM_OC_SetIdleState - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param IdleState This parameter can be one of the following values: - * @arg @ref LL_TIM_OCIDLESTATE_LOW - * @arg @ref LL_TIM_OCIDLESTATE_HIGH - * @retval None - */ -static inline void LL_TIM_OC_SetIdleState(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t IdleState) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), IdleState << SHIFT_TAB_OISx[iChannel]); -} - -/** - * @brief Get the IDLE state of an output channel - * @rmtoll CR2 OIS1 LL_TIM_OC_GetIdleState\n - * CR2 OIS2N LL_TIM_OC_GetIdleState\n - * CR2 OIS2 LL_TIM_OC_GetIdleState\n - * CR2 OIS2N LL_TIM_OC_GetIdleState\n - * CR2 OIS3 LL_TIM_OC_GetIdleState\n - * CR2 OIS3N LL_TIM_OC_GetIdleState\n - * CR2 OIS4 LL_TIM_OC_GetIdleState\n - * CR2 OIS5 LL_TIM_OC_GetIdleState\n - * CR2 OIS6 LL_TIM_OC_GetIdleState - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_OCIDLESTATE_LOW - * @arg @ref LL_TIM_OCIDLESTATE_HIGH - */ -static inline uint32_t LL_TIM_OC_GetIdleState(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - return (READ_BIT(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel])) >> SHIFT_TAB_OISx[iChannel]); -} - -/** - * @brief Enable fast mode for the output channel. - * @note Acts only if the channel is configured in PWM1 or PWM2 mode. - * @rmtoll CCMR1 OC1FE LL_TIM_OC_EnableFast\n - * CCMR1 OC2FE LL_TIM_OC_EnableFast\n - * CCMR2 OC3FE LL_TIM_OC_EnableFast\n - * CCMR2 OC4FE LL_TIM_OC_EnableFast\n - * CCMR3 OC5FE LL_TIM_OC_EnableFast\n - * CCMR3 OC6FE LL_TIM_OC_EnableFast - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_EnableFast(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - SET_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); - -} - -/** - * @brief Disable fast mode for the output channel. - * @rmtoll CCMR1 OC1FE LL_TIM_OC_DisableFast\n - * CCMR1 OC2FE LL_TIM_OC_DisableFast\n - * CCMR2 OC3FE LL_TIM_OC_DisableFast\n - * CCMR2 OC4FE LL_TIM_OC_DisableFast\n - * CCMR3 OC5FE LL_TIM_OC_DisableFast\n - * CCMR3 OC6FE LL_TIM_OC_DisableFast - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_DisableFast(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); - -} - -/** - * @brief Indicates whether fast mode is enabled for the output channel. - * @rmtoll CCMR1 OC1FE LL_TIM_OC_IsEnabledFast\n - * CCMR1 OC2FE LL_TIM_OC_IsEnabledFast\n - * CCMR2 OC3FE LL_TIM_OC_IsEnabledFast\n - * CCMR2 OC4FE LL_TIM_OC_IsEnabledFast\n - * CCMR3 OC5FE LL_TIM_OC_IsEnabledFast\n - * CCMR3 OC6FE LL_TIM_OC_IsEnabledFast - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_OC_IsEnabledFast(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - uint32_t bitfield = TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel]; - return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); -} - -/** - * @brief Enable compare register (TIMx_CCRx) preload for the output channel. - * @rmtoll CCMR1 OC1PE LL_TIM_OC_EnablePreload\n - * CCMR1 OC2PE LL_TIM_OC_EnablePreload\n - * CCMR2 OC3PE LL_TIM_OC_EnablePreload\n - * CCMR2 OC4PE LL_TIM_OC_EnablePreload\n - * CCMR3 OC5PE LL_TIM_OC_EnablePreload\n - * CCMR3 OC6PE LL_TIM_OC_EnablePreload - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_EnablePreload(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - SET_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Disable compare register (TIMx_CCRx) preload for the output channel. - * @rmtoll CCMR1 OC1PE LL_TIM_OC_DisablePreload\n - * CCMR1 OC2PE LL_TIM_OC_DisablePreload\n - * CCMR2 OC3PE LL_TIM_OC_DisablePreload\n - * CCMR2 OC4PE LL_TIM_OC_DisablePreload\n - * CCMR3 OC5PE LL_TIM_OC_DisablePreload\n - * CCMR3 OC6PE LL_TIM_OC_DisablePreload - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_DisablePreload(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Indicates whether compare register (TIMx_CCRx) preload is enabled for the output channel. - * @rmtoll CCMR1 OC1PE LL_TIM_OC_IsEnabledPreload\n - * CCMR1 OC2PE LL_TIM_OC_IsEnabledPreload\n - * CCMR2 OC3PE LL_TIM_OC_IsEnabledPreload\n - * CCMR2 OC4PE LL_TIM_OC_IsEnabledPreload\n - * CCMR3 OC5PE LL_TIM_OC_IsEnabledPreload\n - * CCMR3 OC6PE LL_TIM_OC_IsEnabledPreload - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_OC_IsEnabledPreload(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - uint32_t bitfield = TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel]; - return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); -} - -/** - * @brief Enable clearing the output channel on an external event. - * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. - * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether - * or not a timer instance can clear the OCxREF signal on an external event. - * @rmtoll CCMR1 OC1CE LL_TIM_OC_EnableClear\n - * CCMR1 OC2CE LL_TIM_OC_EnableClear\n - * CCMR2 OC3CE LL_TIM_OC_EnableClear\n - * CCMR2 OC4CE LL_TIM_OC_EnableClear\n - * CCMR3 OC5CE LL_TIM_OC_EnableClear\n - * CCMR3 OC6CE LL_TIM_OC_EnableClear - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_EnableClear(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - SET_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Disable clearing the output channel on an external event. - * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether - * or not a timer instance can clear the OCxREF signal on an external event. - * @rmtoll CCMR1 OC1CE LL_TIM_OC_DisableClear\n - * CCMR1 OC2CE LL_TIM_OC_DisableClear\n - * CCMR2 OC3CE LL_TIM_OC_DisableClear\n - * CCMR2 OC4CE LL_TIM_OC_DisableClear\n - * CCMR3 OC5CE LL_TIM_OC_DisableClear\n - * CCMR3 OC6CE LL_TIM_OC_DisableClear - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_DisableClear(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Indicates clearing the output channel on an external event is enabled for the output channel. - * @note This function enables clearing the output channel on an external event. - * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. - * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether - * or not a timer instance can clear the OCxREF signal on an external event. - * @rmtoll CCMR1 OC1CE LL_TIM_OC_IsEnabledClear\n - * CCMR1 OC2CE LL_TIM_OC_IsEnabledClear\n - * CCMR2 OC3CE LL_TIM_OC_IsEnabledClear\n - * CCMR2 OC4CE LL_TIM_OC_IsEnabledClear\n - * CCMR3 OC5CE LL_TIM_OC_IsEnabledClear\n - * CCMR3 OC6CE LL_TIM_OC_IsEnabledClear - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_OC_IsEnabledClear(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - uint32_t bitfield = TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel]; - return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); -} - -/** - * @brief Set the dead-time delay (delay inserted between the rising edge of the OCxREF signal and the rising edge of - * the Ocx and OCxN signals). - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * dead-time insertion feature is supported by a timer instance. - * @note Helper macro @ref __LL_TIM_CALC_DEADTIME can be used to calculate the DeadTime parameter - * @rmtoll BDTR DTG LL_TIM_OC_SetDeadTime - * @param TIMx Timer instance - * @param DeadTime between Min_Data=0 and Max_Data=255 - * @retval None - */ -static inline void LL_TIM_OC_SetDeadTime(TIM_TypeDef *TIMx, uint32_t DeadTime) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_DTG, DeadTime); -} - -/** - * @brief Set compare value for output channel 1 (TIMx_CCR1). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not - * output channel 1 is supported by a timer instance. - * @rmtoll CCR1 CCR1 LL_TIM_OC_SetCompareCH1 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH1(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR1, CompareValue); -} - -/** - * @brief Set compare value for output channel 2 (TIMx_CCR2). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not - * output channel 2 is supported by a timer instance. - * @rmtoll CCR2 CCR2 LL_TIM_OC_SetCompareCH2 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH2(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR2, CompareValue); -} - -/** - * @brief Set compare value for output channel 3 (TIMx_CCR3). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not - * output channel is supported by a timer instance. - * @rmtoll CCR3 CCR3 LL_TIM_OC_SetCompareCH3 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH3(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR3, CompareValue); -} - -/** - * @brief Set compare value for output channel 4 (TIMx_CCR4). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not - * output channel 4 is supported by a timer instance. - * @rmtoll CCR4 CCR4 LL_TIM_OC_SetCompareCH4 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH4(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR4, CompareValue); -} - -/** - * @brief Set compare value for output channel 5 (TIMx_CCR5). - * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not - * output channel 5 is supported by a timer instance. - * @rmtoll CCR5 CCR5 LL_TIM_OC_SetCompareCH5 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH5(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - MODIFY_REG(TIMx->CCR5, TIM_CCR5_CCR5, CompareValue); -} - -/** - * @brief Set compare value for output channel 6 (TIMx_CCR6). - * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not - * output channel 6 is supported by a timer instance. - * @rmtoll CCR6 CCR6 LL_TIM_OC_SetCompareCH6 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH6(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR6, CompareValue); -} - -/** - * @brief Get compare value (TIMx_CCR1) set for output channel 1. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not - * output channel 1 is supported by a timer instance. - * @rmtoll CCR1 CCR1 LL_TIM_OC_GetCompareCH1 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH1(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR1)); -} - -/** - * @brief Get compare value (TIMx_CCR2) set for output channel 2. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not - * output channel 2 is supported by a timer instance. - * @rmtoll CCR2 CCR2 LL_TIM_OC_GetCompareCH2 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH2(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR2)); -} - -/** - * @brief Get compare value (TIMx_CCR3) set for output channel 3. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not - * output channel 3 is supported by a timer instance. - * @rmtoll CCR3 CCR3 LL_TIM_OC_GetCompareCH3 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH3(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR3)); -} - -/** - * @brief Get compare value (TIMx_CCR4) set for output channel 4. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not - * output channel 4 is supported by a timer instance. - * @rmtoll CCR4 CCR4 LL_TIM_OC_GetCompareCH4 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH4(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR4)); -} - -/** - * @brief Get compare value (TIMx_CCR5) set for output channel 5. - * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not - * output channel 5 is supported by a timer instance. - * @rmtoll CCR5 CCR5 LL_TIM_OC_GetCompareCH5 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH5(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CCR5, TIM_CCR5_CCR5)); -} - -/** - * @brief Get compare value (TIMx_CCR6) set for output channel 6. - * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not - * output channel 6 is supported by a timer instance. - * @rmtoll CCR6 CCR6 LL_TIM_OC_GetCompareCH6 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH6(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR6)); -} - -/** - * @brief Select on which reference signal the OC5REF is combined to. - * @note Macro IS_TIM_COMBINED3PHASEPWM_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports the combined 3-phase PWM mode. - * @rmtoll CCR5 GC5C3 LL_TIM_SetCH5CombinedChannels\n - * CCR5 GC5C2 LL_TIM_SetCH5CombinedChannels\n - * CCR5 GC5C1 LL_TIM_SetCH5CombinedChannels - * @param TIMx Timer instance - * @param GroupCH5 This parameter can be a combination of the following values: - * @arg @ref LL_TIM_GROUPCH5_NONE - * @arg @ref LL_TIM_GROUPCH5_OC1REFC - * @arg @ref LL_TIM_GROUPCH5_OC2REFC - * @arg @ref LL_TIM_GROUPCH5_OC3REFC - * @retval None - */ -static inline void LL_TIM_SetCH5CombinedChannels(TIM_TypeDef *TIMx, uint32_t GroupCH5) -{ - MODIFY_REG(TIMx->CCR5, (TIM_CCR5_GC5C3 | TIM_CCR5_GC5C2 | TIM_CCR5_GC5C1), GroupCH5); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Input_Channel Input channel configuration - * @{ - */ -/** - * @brief Configure input channel. - * @rmtoll CCMR1 CC1S LL_TIM_IC_Config\n - * CCMR1 IC1PSC LL_TIM_IC_Config\n - * CCMR1 IC1F LL_TIM_IC_Config\n - * CCMR1 CC2S LL_TIM_IC_Config\n - * CCMR1 IC2PSC LL_TIM_IC_Config\n - * CCMR1 IC2F LL_TIM_IC_Config\n - * CCMR2 CC3S LL_TIM_IC_Config\n - * CCMR2 IC3PSC LL_TIM_IC_Config\n - * CCMR2 IC3F LL_TIM_IC_Config\n - * CCMR2 CC4S LL_TIM_IC_Config\n - * CCMR2 IC4PSC LL_TIM_IC_Config\n - * CCMR2 IC4F LL_TIM_IC_Config\n - * CCER CC1P LL_TIM_IC_Config\n - * CCER CC1NP LL_TIM_IC_Config\n - * CCER CC2P LL_TIM_IC_Config\n - * CCER CC2NP LL_TIM_IC_Config\n - * CCER CC3P LL_TIM_IC_Config\n - * CCER CC3NP LL_TIM_IC_Config\n - * CCER CC4P LL_TIM_IC_Config\n - * CCER CC4NP LL_TIM_IC_Config - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param Configuration This parameter must be a combination of all the following values: - * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI or @ref LL_TIM_ACTIVEINPUT_INDIRECTTI or @ref LL_TIM_ACTIVEINPUT_TRC - * @arg @ref LL_TIM_ICPSC_DIV1 or ... or @ref LL_TIM_ICPSC_DIV8 - * @arg @ref LL_TIM_IC_FILTER_FDIV1 or ... or @ref LL_TIM_IC_FILTER_FDIV32_N8 - * @arg @ref LL_TIM_IC_POLARITY_RISING or @ref LL_TIM_IC_POLARITY_FALLING or @ref LL_TIM_IC_POLARITY_BOTHEDGE - * @retval None - */ -static inline void LL_TIM_IC_Config(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), - ((Configuration >> 16U) & (TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S)) \ - << SHIFT_TAB_ICxx[iChannel]); - MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), - (Configuration & (TIM_CCER_CC1NP | TIM_CCER_CC1P)) << SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Set the active input. - * @rmtoll CCMR1 CC1S LL_TIM_IC_SetActiveInput\n - * CCMR1 CC2S LL_TIM_IC_SetActiveInput\n - * CCMR2 CC3S LL_TIM_IC_SetActiveInput\n - * CCMR2 CC4S LL_TIM_IC_SetActiveInput - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICActiveInput This parameter can be one of the following values: - * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_TRC - * @retval None - */ -static inline void LL_TIM_IC_SetActiveInput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICActiveInput) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), (ICActiveInput >> 16U) << SHIFT_TAB_ICxx[iChannel]); -} - -/** - * @brief Get the current active input. - * @rmtoll CCMR1 CC1S LL_TIM_IC_GetActiveInput\n - * CCMR1 CC2S LL_TIM_IC_GetActiveInput\n - * CCMR2 CC3S LL_TIM_IC_GetActiveInput\n - * CCMR2 CC4S LL_TIM_IC_GetActiveInput - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_TRC - */ -static inline uint32_t LL_TIM_IC_GetActiveInput(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return ((READ_BIT(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); -} - -/** - * @brief Set the prescaler of input channel. - * @rmtoll CCMR1 IC1PSC LL_TIM_IC_SetPrescaler\n - * CCMR1 IC2PSC LL_TIM_IC_SetPrescaler\n - * CCMR2 IC3PSC LL_TIM_IC_SetPrescaler\n - * CCMR2 IC4PSC LL_TIM_IC_SetPrescaler - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICPrescaler This parameter can be one of the following values: - * @arg @ref LL_TIM_ICPSC_DIV1 - * @arg @ref LL_TIM_ICPSC_DIV2 - * @arg @ref LL_TIM_ICPSC_DIV4 - * @arg @ref LL_TIM_ICPSC_DIV8 - * @retval None - */ -static inline void LL_TIM_IC_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPrescaler) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel]), (ICPrescaler >> 16U) << SHIFT_TAB_ICxx[iChannel]); -} - -/** - * @brief Get the current prescaler value acting on an input channel. - * @rmtoll CCMR1 IC1PSC LL_TIM_IC_GetPrescaler\n - * CCMR1 IC2PSC LL_TIM_IC_GetPrescaler\n - * CCMR2 IC3PSC LL_TIM_IC_GetPrescaler\n - * CCMR2 IC4PSC LL_TIM_IC_GetPrescaler - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_ICPSC_DIV1 - * @arg @ref LL_TIM_ICPSC_DIV2 - * @arg @ref LL_TIM_ICPSC_DIV4 - * @arg @ref LL_TIM_ICPSC_DIV8 - */ -static inline uint32_t LL_TIM_IC_GetPrescaler(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); -} - -/** - * @brief Set the input filter duration. - * @rmtoll CCMR1 IC1F LL_TIM_IC_SetFilter\n - * CCMR1 IC2F LL_TIM_IC_SetFilter\n - * CCMR2 IC3F LL_TIM_IC_SetFilter\n - * CCMR2 IC4F LL_TIM_IC_SetFilter - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_IC_FILTER_FDIV1 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_IC_SetFilter(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICFilter) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel]), (ICFilter >> 16U) << SHIFT_TAB_ICxx[iChannel]); -} - -/** - * @brief Get the input filter duration. - * @rmtoll CCMR1 IC1F LL_TIM_IC_GetFilter\n - * CCMR1 IC2F LL_TIM_IC_GetFilter\n - * CCMR2 IC3F LL_TIM_IC_GetFilter\n - * CCMR2 IC4F LL_TIM_IC_GetFilter - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_IC_FILTER_FDIV1 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 - */ -static inline uint32_t LL_TIM_IC_GetFilter(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); -} - -/** - * @brief Set the input channel polarity. - * @rmtoll CCER CC1P LL_TIM_IC_SetPolarity\n - * CCER CC1NP LL_TIM_IC_SetPolarity\n - * CCER CC2P LL_TIM_IC_SetPolarity\n - * CCER CC2NP LL_TIM_IC_SetPolarity\n - * CCER CC3P LL_TIM_IC_SetPolarity\n - * CCER CC3NP LL_TIM_IC_SetPolarity\n - * CCER CC4P LL_TIM_IC_SetPolarity\n - * CCER CC4NP LL_TIM_IC_SetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_IC_POLARITY_RISING - * @arg @ref LL_TIM_IC_POLARITY_FALLING - * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE - * @retval None - */ -static inline void LL_TIM_IC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPolarity) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), - ICPolarity << SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Get the current input channel polarity. - * @rmtoll CCER CC1P LL_TIM_IC_GetPolarity\n - * CCER CC1NP LL_TIM_IC_GetPolarity\n - * CCER CC2P LL_TIM_IC_GetPolarity\n - * CCER CC2NP LL_TIM_IC_GetPolarity\n - * CCER CC3P LL_TIM_IC_GetPolarity\n - * CCER CC3NP LL_TIM_IC_GetPolarity\n - * CCER CC4P LL_TIM_IC_GetPolarity\n - * CCER CC4NP LL_TIM_IC_GetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_IC_POLARITY_RISING - * @arg @ref LL_TIM_IC_POLARITY_FALLING - * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE - */ -static inline uint32_t LL_TIM_IC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - return (READ_BIT(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel])) >> - SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Connect the TIMx_CH1, CH2 and CH3 pins to the TI1 input (XOR combination). - * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an XOR input. - * @rmtoll CR2 TI1S LL_TIM_IC_EnableXORCombination - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_IC_EnableXORCombination(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR2, TIM_CR2_TI1S); -} - -/** - * @brief Disconnect the TIMx_CH1, CH2 and CH3 pins from the TI1 input. - * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an XOR input. - * @rmtoll CR2 TI1S LL_TIM_IC_DisableXORCombination - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_IC_DisableXORCombination(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR2, TIM_CR2_TI1S); -} - -/** - * @brief Indicates whether the TIMx_CH1, CH2 and CH3 pins are connectected to the TI1 input. - * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an XOR input. - * @rmtoll CR2 TI1S LL_TIM_IC_IsEnabledXORCombination - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IC_IsEnabledXORCombination(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR2, TIM_CR2_TI1S) == (TIM_CR2_TI1S)) ? 1UL : 0UL); -} - -/** - * @brief Get captured value for input channel 1. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not - * input channel 1 is supported by a timer instance. - * @rmtoll CCR1 CCR1 LL_TIM_IC_GetCaptureCH1 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH1(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR1)); -} - -/** - * @brief Get captured value for input channel 2. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not - * input channel 2 is supported by a timer instance. - * @rmtoll CCR2 CCR2 LL_TIM_IC_GetCaptureCH2 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH2(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR2)); -} - -/** - * @brief Get captured value for input channel 3. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not - * input channel 3 is supported by a timer instance. - * @rmtoll CCR3 CCR3 LL_TIM_IC_GetCaptureCH3 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH3(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR3)); -} - -/** - * @brief Get captured value for input channel 4. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not - * input channel 4 is supported by a timer instance. - * @rmtoll CCR4 CCR4 LL_TIM_IC_GetCaptureCH4 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH4(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR4)); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Clock_Selection Counter clock selection - * @{ - */ -/** - * @brief Enable external clock mode 2. - * @note When external clock mode 2 is enabled the counter is clocked by any active edge on the ETRF signal. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR ECE LL_TIM_EnableExternalClock - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableExternalClock(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->SMCR, TIM_SMCR_ECE); -} - -/** - * @brief Disable external clock mode 2. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR ECE LL_TIM_DisableExternalClock - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableExternalClock(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->SMCR, TIM_SMCR_ECE); -} - -/** - * @brief Indicate whether external clock mode 2 is enabled. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR ECE LL_TIM_IsEnabledExternalClock - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledExternalClock(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SMCR, TIM_SMCR_ECE) == (TIM_SMCR_ECE)) ? 1UL : 0UL); -} - -/** - * @brief Set the clock source of the counter clock. - * @note when selected clock source is external clock mode 1, the timer input - * the external clock is applied is selected by calling the @ref LL_TIM_SetTriggerInput() - * function. This timer input must be configured by calling - * the @ref LL_TIM_IC_Config() function. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE1_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode1. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR SMS LL_TIM_SetClockSource\n - * SMCR ECE LL_TIM_SetClockSource - * @param TIMx Timer instance - * @param ClockSource This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKSOURCE_INTERNAL - * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE1 - * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE2 - * @retval None - */ -static inline void LL_TIM_SetClockSource(TIM_TypeDef *TIMx, uint32_t ClockSource) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS | TIM_SMCR_ECE, ClockSource); -} - -/** - * @brief Set the encoder interface mode. - * @note Macro IS_TIM_ENCODER_INTERFACE_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports the encoder mode. - * @rmtoll SMCR SMS LL_TIM_SetEncoderMode - * @param TIMx Timer instance - * @param EncoderMode This parameter can be one of the following values: - * @arg @ref LL_TIM_ENCODERMODE_X2_TI1 - * @arg @ref LL_TIM_ENCODERMODE_X2_TI2 - * @arg @ref LL_TIM_ENCODERMODE_X4_TI12 - * @retval None - */ -static inline void LL_TIM_SetEncoderMode(TIM_TypeDef *TIMx, uint32_t EncoderMode) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, EncoderMode); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Timer_Synchronization Timer synchronisation configuration - * @{ - */ -/** - * @brief Set the trigger output (TRGO) used for timer synchronization . - * @note Macro IS_TIM_MASTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance can operate as a master timer. - * @rmtoll CR2 MMS LL_TIM_SetTriggerOutput - * @param TIMx Timer instance - * @param TimerSynchronization This parameter can be one of the following values: - * @arg @ref LL_TIM_TRGO_RESET - * @arg @ref LL_TIM_TRGO_ENABLE - * @arg @ref LL_TIM_TRGO_UPDATE - * @arg @ref LL_TIM_TRGO_CC1IF - * @arg @ref LL_TIM_TRGO_OC1REF - * @arg @ref LL_TIM_TRGO_OC2REF - * @arg @ref LL_TIM_TRGO_OC3REF - * @arg @ref LL_TIM_TRGO_OC4REF - * @retval None - */ -static inline void LL_TIM_SetTriggerOutput(TIM_TypeDef *TIMx, uint32_t TimerSynchronization) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_MMS, TimerSynchronization); -} - -/** - * @brief Set the trigger output 2 (TRGO2) used for ADC synchronization . - * @note Macro IS_TIM_TRGO2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance can be used for ADC synchronization. - * @rmtoll CR2 MMS2 LL_TIM_SetTriggerOutput2 - * @param TIMx Timer Instance - * @param ADCSynchronization This parameter can be one of the following values: - * @arg @ref LL_TIM_TRGO2_RESET - * @arg @ref LL_TIM_TRGO2_ENABLE - * @arg @ref LL_TIM_TRGO2_UPDATE - * @arg @ref LL_TIM_TRGO2_CC1F - * @arg @ref LL_TIM_TRGO2_OC1 - * @arg @ref LL_TIM_TRGO2_OC2 - * @arg @ref LL_TIM_TRGO2_OC3 - * @arg @ref LL_TIM_TRGO2_OC4 - * @arg @ref LL_TIM_TRGO2_OC5 - * @arg @ref LL_TIM_TRGO2_OC6 - * @arg @ref LL_TIM_TRGO2_OC4_RISINGFALLING - * @arg @ref LL_TIM_TRGO2_OC6_RISINGFALLING - * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_RISING - * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_FALLING - * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_RISING - * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_FALLING - * @retval None - */ -static inline void LL_TIM_SetTriggerOutput2(TIM_TypeDef *TIMx, uint32_t ADCSynchronization) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_MMS2, ADCSynchronization); -} - -/** - * @brief Set the synchronization mode of a slave timer. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR SMS LL_TIM_SetSlaveMode - * @param TIMx Timer instance - * @param SlaveMode This parameter can be one of the following values: - * @arg @ref LL_TIM_SLAVEMODE_DISABLED - * @arg @ref LL_TIM_SLAVEMODE_RESET - * @arg @ref LL_TIM_SLAVEMODE_GATED - * @arg @ref LL_TIM_SLAVEMODE_TRIGGER - * @arg @ref LL_TIM_SLAVEMODE_COMBINED_RESETTRIGGER - * @retval None - */ -static inline void LL_TIM_SetSlaveMode(TIM_TypeDef *TIMx, uint32_t SlaveMode) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, SlaveMode); -} - -/** - * @brief Set the selects the trigger input to be used to synchronize the counter. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR TS LL_TIM_SetTriggerInput - * @param TIMx Timer instance - * @param TriggerInput This parameter can be one of the following values: - * @arg @ref LL_TIM_TS_ITR0 - * @arg @ref LL_TIM_TS_ITR1 - * @arg @ref LL_TIM_TS_ITR2 - * @arg @ref LL_TIM_TS_ITR3 - * @arg @ref LL_TIM_TS_ITR4 - * @arg @ref LL_TIM_TS_ITR5 - * @arg @ref LL_TIM_TS_ITR6 - * @arg @ref LL_TIM_TS_ITR7 - * @arg @ref LL_TIM_TS_ITR8 (*) - * @arg @ref LL_TIM_TS_ITR9 (*) - * @arg @ref LL_TIM_TS_ITR10 (*) - * @arg @ref LL_TIM_TS_ITR11 (*) - * @arg @ref LL_TIM_TS_ITR12 (*) - * @arg @ref LL_TIM_TS_ITR13 (*) - * @arg @ref LL_TIM_TS_TI1F_ED - * @arg @ref LL_TIM_TS_TI1FP1 - * @arg @ref LL_TIM_TS_TI2FP2 - * @arg @ref LL_TIM_TS_ETRF - * - * (*) Value not defined in all devices. - * @retval None - */ -static inline void LL_TIM_SetTriggerInput(TIM_TypeDef *TIMx, uint32_t TriggerInput) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_TS, TriggerInput); -} - -/** - * @brief Enable the Master/Slave mode. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR MSM LL_TIM_EnableMasterSlaveMode - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableMasterSlaveMode(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->SMCR, TIM_SMCR_MSM); -} - -/** - * @brief Disable the Master/Slave mode. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR MSM LL_TIM_DisableMasterSlaveMode - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableMasterSlaveMode(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->SMCR, TIM_SMCR_MSM); -} - -/** - * @brief Indicates whether the Master/Slave mode is enabled. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR MSM LL_TIM_IsEnabledMasterSlaveMode - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledMasterSlaveMode(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SMCR, TIM_SMCR_MSM) == (TIM_SMCR_MSM)) ? 1UL : 0UL); -} - -/** - * @brief Configure the external trigger (ETR) input. - * @note Macro IS_TIM_ETR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an external trigger input. - * @rmtoll SMCR ETP LL_TIM_ConfigETR\n - * SMCR ETPS LL_TIM_ConfigETR\n - * SMCR ETF LL_TIM_ConfigETR - * @param TIMx Timer instance - * @param ETRPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_ETR_POLARITY_NONINVERTED - * @arg @ref LL_TIM_ETR_POLARITY_INVERTED - * @param ETRPrescaler This parameter can be one of the following values: - * @arg @ref LL_TIM_ETR_PRESCALER_DIV1 - * @arg @ref LL_TIM_ETR_PRESCALER_DIV2 - * @arg @ref LL_TIM_ETR_PRESCALER_DIV4 - * @arg @ref LL_TIM_ETR_PRESCALER_DIV8 - * @param ETRFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_ETR_FILTER_FDIV1 - * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_ConfigETR(TIM_TypeDef *TIMx, uint32_t ETRPolarity, uint32_t ETRPrescaler, - uint32_t ETRFilter) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_ETP | TIM_SMCR_ETPS | TIM_SMCR_ETF, ETRPolarity | ETRPrescaler | ETRFilter); -} - -/** - * @brief Select the external trigger (ETR) input source. - * @note Macro IS_TIM_ETRSEL_INSTANCE(TIMx) can be used to check whether or - * not a timer instance supports ETR source selection. - * @rmtoll AF1 ETRSEL LL_TIM_SetETRSource - * @param TIMx Timer instance - * @param ETRSource This parameter can be one of the following values: - * For TIM1, the parameter is one of the following values: - * @arg LL_TIM_TIM1_ETRSOURCE_GPIO: TIM1_ETR is connected to GPIO - * @arg LL_TIM_TIM1_ETRSOURCE_COMP1: TIM1_ETR is connected to COMP1 output - * @arg LL_TIM_TIM1_ETRSOURCE_COMP2: TIM1_ETR is connected to COMP2 output - * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD1: TIM1_ETR is connected to ADC1 AWD1 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD2: TIM1_ETR is connected to ADC1 AWD2 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD3: TIM1_ETR is connected to ADC1 AWD3 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD1: TIM1_ETR is connected to ADC3 AWD1 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD2: TIM1_ETR is connected to ADC3 AWD2 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD3: TIM1_ETR is connected to ADC3 AWD3 - * - * For TIM2, the parameter is one of the following values: - * @arg LL_TIM_TIM2_ETRSOURCE_GPIO: TIM2_ETR is connected to GPIO - * @arg LL_TIM_TIM2_ETRSOURCE_COMP1: TIM2_ETR is connected to COMP1 output - * @arg LL_TIM_TIM2_ETRSOURCE_COMP2: TIM2_ETR is connected to COMP2 output - * @arg LL_TIM_TIM2_ETRSOURCE_LSE: TIM2_ETR is connected to LSE - * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSA: TIM2_ETR is connected to SAI1 FS_A - * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSB: TIM2_ETR is connected to SAI1 FS_B - * - * For TIM3, the parameter is one of the following values: - * @arg LL_TIM_TIM3_ETRSOURCE_GPIO: TIM3_ETR is connected to GPIO - * @arg LL_TIM_TIM3_ETRSOURCE_COMP1: TIM3_ETR is connected to COMP1 output - * - * For TIM5, the parameter is one of the following values: - * @arg LL_TIM_TIM5_ETRSOURCE_GPIO: TIM5_ETR is connected to GPIO - * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSA: TIM5_ETR is connected to SAI2 FS_A (*) - * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSB: TIM5_ETR is connected to SAI2 FS_B (*) - * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSA: TIM5_ETR is connected to SAI2 FS_A (*) - * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSB: TIM5_ETR is connected to SAI2 FS_B (*) - * - * For TIM8, the parameter is one of the following values: - * @arg LL_TIM_TIM8_ETRSOURCE_GPIO: TIM8_ETR is connected to GPIO - * @arg LL_TIM_TIM8_ETRSOURCE_COMP1: TIM8_ETR is connected to COMP1 output - * @arg LL_TIM_TIM8_ETRSOURCE_COMP2: TIM8_ETR is connected to COMP2 output - * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD1: TIM8_ETR is connected to ADC2 AWD1 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD2: TIM8_ETR is connected to ADC2 AWD2 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD3: TIM8_ETR is connected to ADC2 AWD3 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD1: TIM8_ETR is connected to ADC3 AWD1 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD2: TIM8_ETR is connected to ADC3 AWD2 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD3: TIM8_ETR is connected to ADC3 AWD3 - * - * For TIM23, the parameter is one of the following values: (*) - * @arg LL_TIM_TIM23_ETRSOURCE_GPIO TIM23_ETR is connected to GPIO - * @arg LL_TIM_TIM23_ETRSOURCE_COMP1 TIM23_ETR is connected to COMP1 output - * @arg LL_TIM_TIM23_ETRSOURCE_COMP2 TIM23_ETR is connected to COMP2 output - * - * For TIM24, the parameter is one of the following values: (*) - * @arg LL_TIM_TIM24_ETRSOURCE_GPIO TIM24_ETR is connected to GPIO - * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSA TIM24_ETR is connected to SAI4 FS_A - * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSB TIM24_ETR is connected to SAI4 FS_B - * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSA TIM24_ETR is connected to SAI1 FS_A - * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSB TIM24_ETR is connected to SAI1 FS_B - * - * (*) Value not defined in all devices. - * @retval None - */ -static inline void LL_TIM_SetETRSource(TIM_TypeDef *TIMx, uint32_t ETRSource) -{ - MODIFY_REG(TIMx->AF1, TIMx_AF1_ETRSEL, ETRSource); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Break_Function Break function configuration - * @{ - */ -/** - * @brief Enable the break function. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR BKE LL_TIM_EnableBRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableBRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BKE); -} - -/** - * @brief Disable the break function. - * @rmtoll BDTR BKE LL_TIM_DisableBRK - * @param TIMx Timer instance - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @retval None - */ -static inline void LL_TIM_DisableBRK(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BKE); -} - -#if defined(TIM_BDTR_BKBID) -/** - * @brief Configure the break input. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @note Bidirectional mode is only supported by advanced timer instances. - * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not - * a timer instance is an advanced-control timer. - * @note In bidirectional mode (BKBID bit set), the Break input is configured both - * in input mode and in open drain output mode. Any active Break event will - * assert a low logic level on the Break input to indicate an internal break - * event to external devices. - * @note When bidirectional mode isn't supported, BreakAFMode must be set to - * LL_TIM_BREAK_AFMODE_INPUT. - * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n - * BDTR BKF LL_TIM_ConfigBRK\n - * BDTR BKBID LL_TIM_ConfigBRK - * @param TIMx Timer instance - * @param BreakPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_POLARITY_LOW - * @arg @ref LL_TIM_BREAK_POLARITY_HIGH - * @param BreakFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 - * @param BreakAFMode This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_AFMODE_INPUT - * @arg @ref LL_TIM_BREAK_AFMODE_BIDIRECTIONAL - * @retval None - */ -static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, uint32_t BreakFilter, - uint32_t BreakAFMode) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF | TIM_BDTR_BKBID, BreakPolarity | BreakFilter | BreakAFMode); -} - -#else -/** - * @brief Configure the break input. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n - * BDTR BKF LL_TIM_ConfigBRK - * @param TIMx Timer instance - * @param BreakPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_POLARITY_LOW - * @arg @ref LL_TIM_BREAK_POLARITY_HIGH - * @param BreakFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, - uint32_t BreakFilter) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF, BreakPolarity | BreakFilter); -} - -#endif /* TIM_BDTR_BKBID */ -#if defined(TIM_BDTR_BKBID) -/** - * @brief Disarm the break input (when it operates in bidirectional mode). - * @note The break input can be disarmed only when it is configured in - * bidirectional mode and when when MOE is reset. - * @note Purpose is to be able to have the input voltage back to high-state, - * whatever the time constant on the output . - * @rmtoll BDTR BKDSRM LL_TIM_DisarmBRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisarmBRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BKDSRM); -} - -#endif /*TIM_BDTR_BKBID */ -/** - * @brief Enable the break 2 function. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @rmtoll BDTR BK2E LL_TIM_EnableBRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableBRK2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BK2E); -} - -/** - * @brief Disable the break 2 function. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @rmtoll BDTR BK2E LL_TIM_DisableBRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableBRK2(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BK2E); -} - -#if defined(TIM_BDTR_BKBID) -/** - * @brief Configure the break 2 input. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @note Bidirectional mode is only supported by advanced timer instances. - * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not - * a timer instance is an advanced-control timer. - * @note In bidirectional mode (BK2BID bit set), the Break 2 input is configured both - * in input mode and in open drain output mode. Any active Break event will - * assert a low logic level on the Break 2 input to indicate an internal break - * event to external devices. - * @note When bidirectional mode isn't supported, Break2AFMode must be set to - * LL_TIM_BREAK2_AFMODE_INPUT. - * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n - * BDTR BK2F LL_TIM_ConfigBRK2\n - * BDTR BK2BID LL_TIM_ConfigBRK2 - * @param TIMx Timer instance - * @param Break2Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_POLARITY_LOW - * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH - * @param Break2Filter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 - * @param Break2AFMode This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_AFMODE_INPUT - * @arg @ref LL_TIM_BREAK2_AFMODE_BIDIRECTIONAL - * @retval None - */ -static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter, - uint32_t Break2AFMode) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F | TIM_BDTR_BK2BID, Break2Polarity | Break2Filter | Break2AFMode); -} - -#else -/** - * @brief Configure the break 2 input. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n - * BDTR BK2F LL_TIM_ConfigBRK2 - * @param TIMx Timer instance - * @param Break2Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_POLARITY_LOW - * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH - * @param Break2Filter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F, Break2Polarity | Break2Filter); -} - -#endif /*TIM_BDTR_BKBID */ -#if defined(TIM_BDTR_BKBID) -/** - * @brief Disarm the break 2 input (when it operates in bidirectional mode). - * @note The break 2 input can be disarmed only when it is configured in - * bidirectional mode and when when MOE is reset. - * @note Purpose is to be able to have the input voltage back to high-state, - * whatever the time constant on the output. - * @rmtoll BDTR BK2DSRM LL_TIM_DisarmBRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisarmBRK2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BK2DSRM); -} - -#endif /*TIM_BDTR_BKBID */ -/** - * @brief Select the outputs off state (enabled v.s. disabled) in Idle and Run modes. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR OSSI LL_TIM_SetOffStates\n - * BDTR OSSR LL_TIM_SetOffStates - * @param TIMx Timer instance - * @param OffStateIdle This parameter can be one of the following values: - * @arg @ref LL_TIM_OSSI_DISABLE - * @arg @ref LL_TIM_OSSI_ENABLE - * @param OffStateRun This parameter can be one of the following values: - * @arg @ref LL_TIM_OSSR_DISABLE - * @arg @ref LL_TIM_OSSR_ENABLE - * @retval None - */ -static inline void LL_TIM_SetOffStates(TIM_TypeDef *TIMx, uint32_t OffStateIdle, uint32_t OffStateRun) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_OSSI | TIM_BDTR_OSSR, OffStateIdle | OffStateRun); -} - -/** - * @brief Enable automatic output (MOE can be set by software or automatically when a break input is active). - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR AOE LL_TIM_EnableAutomaticOutput - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableAutomaticOutput(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_AOE); -} - -/** - * @brief Disable automatic output (MOE can be set only by software). - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR AOE LL_TIM_DisableAutomaticOutput - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableAutomaticOutput(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_AOE); -} - -/** - * @brief Indicate whether automatic output is enabled. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR AOE LL_TIM_IsEnabledAutomaticOutput - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledAutomaticOutput(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->BDTR, TIM_BDTR_AOE) == (TIM_BDTR_AOE)) ? 1UL : 0UL); -} - -/** - * @brief Enable the outputs (set the MOE bit in TIMx_BDTR register). - * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by - * software and is reset in case of break or break2 event - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR MOE LL_TIM_EnableAllOutputs - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableAllOutputs(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_MOE); -} - -/** - * @brief Disable the outputs (reset the MOE bit in TIMx_BDTR register). - * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by - * software and is reset in case of break or break2 event. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR MOE LL_TIM_DisableAllOutputs - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableAllOutputs(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_MOE); -} - -/** - * @brief Indicates whether outputs are enabled. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR MOE LL_TIM_IsEnabledAllOutputs - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledAllOutputs(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->BDTR, TIM_BDTR_MOE) == (TIM_BDTR_MOE)) ? 1UL : 0UL); -} - -#if defined(TIM_BREAK_INPUT_SUPPORT) -/** - * @brief Enable the signals connected to the designated timer break input. - * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether - * or not a timer instance allows for break input selection. - * @rmtoll AF1 BKINE LL_TIM_EnableBreakInputSource\n - * AF1 BKCMP1E LL_TIM_EnableBreakInputSource\n - * AF1 BKCMP2E LL_TIM_EnableBreakInputSource\n - * AF1 BKDF1BK0E LL_TIM_EnableBreakInputSource\n - * AF2 BK2INE LL_TIM_EnableBreakInputSource\n - * AF2 BK2CMP1E LL_TIM_EnableBreakInputSource\n - * AF2 BK2CMP2E LL_TIM_EnableBreakInputSource\n - * AF2 BK2DF1BK1E LL_TIM_EnableBreakInputSource - * @param TIMx Timer instance - * @param BreakInput This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_INPUT_BKIN - * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 - * @param Source This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_SOURCE_BKIN - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 - * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK - * @retval None - */ -static inline void LL_TIM_EnableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) -{ - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); - SET_BIT(*pReg, Source); -} - -/** - * @brief Disable the signals connected to the designated timer break input. - * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether - * or not a timer instance allows for break input selection. - * @rmtoll AF1 BKINE LL_TIM_DisableBreakInputSource\n - * AF1 BKCMP1E LL_TIM_DisableBreakInputSource\n - * AF1 BKCMP2E LL_TIM_DisableBreakInputSource\n - * AF1 BKDF1BK0E LL_TIM_DisableBreakInputSource\n - * AF2 BK2INE LL_TIM_DisableBreakInputSource\n - * AF2 BK2CMP1E LL_TIM_DisableBreakInputSource\n - * AF2 BK2CMP2E LL_TIM_DisableBreakInputSource\n - * AF2 BK2DF1BK1E LL_TIM_DisableBreakInputSource - * @param TIMx Timer instance - * @param BreakInput This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_INPUT_BKIN - * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 - * @param Source This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_SOURCE_BKIN - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 - * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK - * @retval None - */ -static inline void LL_TIM_DisableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) -{ - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); - CLEAR_BIT(*pReg, Source); -} - -/** - * @brief Set the polarity of the break signal for the timer break input. - * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether - * or not a timer instance allows for break input selection. - * @rmtoll AF1 BKINP LL_TIM_SetBreakInputSourcePolarity\n - * AF1 BKCMP1P LL_TIM_SetBreakInputSourcePolarity\n - * AF1 BKCMP2P LL_TIM_SetBreakInputSourcePolarity\n - * AF2 BK2INP LL_TIM_SetBreakInputSourcePolarity\n - * AF2 BK2CMP1P LL_TIM_SetBreakInputSourcePolarity\n - * AF2 BK2CMP2P LL_TIM_SetBreakInputSourcePolarity - * @param TIMx Timer instance - * @param BreakInput This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_INPUT_BKIN - * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 - * @param Source This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_SOURCE_BKIN - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 - * @param Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_POLARITY_LOW - * @arg @ref LL_TIM_BKIN_POLARITY_HIGH - * @retval None - */ -static inline void LL_TIM_SetBreakInputSourcePolarity(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source, - uint32_t Polarity) -{ - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); - MODIFY_REG(*pReg, (TIMx_AF1_BKINP << TIM_POSITION_BRK_SOURCE), (Polarity << TIM_POSITION_BRK_SOURCE)); -} -#endif /* TIM_BREAK_INPUT_SUPPORT */ -/** - * @} - */ - -/** @defgroup TIM_LL_EF_DMA_Burst_Mode DMA burst mode configuration - * @{ - */ -/** - * @brief Configures the timer DMA burst feature. - * @note Macro IS_TIM_DMABURST_INSTANCE(TIMx) can be used to check whether or - * not a timer instance supports the DMA burst mode. - * @rmtoll DCR DBL LL_TIM_ConfigDMABurst\n - * DCR DBA LL_TIM_ConfigDMABurst - * @param TIMx Timer instance - * @param DMABurstBaseAddress This parameter can be one of the following values: - * @arg @ref LL_TIM_DMABURST_BASEADDR_CR1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CR2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_SMCR - * @arg @ref LL_TIM_DMABURST_BASEADDR_DIER - * @arg @ref LL_TIM_DMABURST_BASEADDR_SR - * @arg @ref LL_TIM_DMABURST_BASEADDR_EGR - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCER - * @arg @ref LL_TIM_DMABURST_BASEADDR_CNT - * @arg @ref LL_TIM_DMABURST_BASEADDR_PSC - * @arg @ref LL_TIM_DMABURST_BASEADDR_ARR - * @arg @ref LL_TIM_DMABURST_BASEADDR_RCR - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR3 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR4 - * @arg @ref LL_TIM_DMABURST_BASEADDR_BDTR - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR3 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR5 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR6 - * @arg @ref LL_TIM_DMABURST_BASEADDR_AF1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_AF2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_TISEL - * - * @param DMABurstLength This parameter can be one of the following values: - * @arg @ref LL_TIM_DMABURST_LENGTH_1TRANSFER - * @arg @ref LL_TIM_DMABURST_LENGTH_2TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_3TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_4TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_5TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_6TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_7TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_8TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_9TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_10TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_11TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_12TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_13TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_14TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_15TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_16TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_17TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_18TRANSFERS - * @retval None - */ -static inline void LL_TIM_ConfigDMABurst(TIM_TypeDef *TIMx, uint32_t DMABurstBaseAddress, uint32_t DMABurstLength) -{ - MODIFY_REG(TIMx->DCR, (TIM_DCR_DBL | TIM_DCR_DBA), (DMABurstBaseAddress | DMABurstLength)); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Timer_Inputs_Remapping Timer input remapping - * @{ - */ -/** - * @brief Remap TIM inputs (input channel, internal/external triggers). - * @note Macro IS_TIM_REMAP_INSTANCE(TIMx) can be used to check whether or not - * a some timer inputs can be remapped. - * TIM1: one of the following values: - * @arg LL_TIM_TIM1_TI1_RMP_GPIO: TIM1 TI1 is connected to GPIO - * @arg LL_TIM_TIM1_TI1_RMP_COMP1: TIM1 TI1 is connected to COMP1 output - * - * TIM2: one of the following values: - * @arg LL_TIM_TIM2_TI4_RMP_GPIO: TIM2 TI4 is connected to GPIO - * @arg LL_TIM_TIM2_TI4_RMP_COMP1: TIM2 TI4 is connected to COMP1 output - * @arg LL_TIM_TIM2_TI4_RMP_COMP2: TIM2 TI4 is connected to COMP2 output - * @arg LL_TIM_TIM2_TI4_RMP_COMP1_COMP2: TIM2 TI4 is connected to logical OR between COMP1 and COMP2 output - * - * TIM3: one of the following values: - * @arg LL_TIM_TIM3_TI1_RMP_GPIO: TIM3 TI1 is connected to GPIO - * @arg LL_TIM_TIM3_TI1_RMP_COMP1: TIM3 TI1 is connected to COMP1 output - * @arg LL_TIM_TIM3_TI1_RMP_COMP2: TIM3 TI1 is connected to COMP2 output - * @arg LL_TIM_TIM3_TI1_RMP_COMP1_COMP2: TIM3 TI1 is connected to logical OR between COMP1 and COMP2 output - * - * TIM5: one of the following values: - * @arg LL_TIM_TIM5_TI1_RMP_GPIO: TIM5 TI1 is connected to GPIO - * @arg LL_TIM_TIM5_TI1_RMP_CAN_TMP: TIM5 TI1 is connected to CAN TMP - * @arg LL_TIM_TIM5_TI1_RMP_CAN_RTP: TIM5 TI1 is connected to CAN RTP - * - * TIM8: one of the following values: - * @arg LL_TIM_TIM8_TI1_RMP_GPIO: TIM8 TI1 is connected to GPIO - * @arg LL_TIM_TIM8_TI1_RMP_COMP2: TIM8 TI1 is connected to COMP2 output - * - * TIM12: one of the following values: (*) - * @arg LL_TIM_TIM12_TI1_RMP_GPIO: TIM12 TI1 is connected to GPIO - * @arg LL_TIM_TIM12_TI1_RMP_SPDIF_FS: TIM12 TI1 is connected to SPDIF FS - * - * TIM15: one of the following values: - * @arg LL_TIM_TIM15_TI1_RMP_GPIO: TIM15 TI1 is connected to GPIO - * @arg LL_TIM_TIM15_TI1_RMP_TIM2: TIM15 TI1 is connected to TIM2 CH1 - * @arg LL_TIM_TIM15_TI1_RMP_TIM3: TIM15 TI1 is connected to TIM3 CH1 - * @arg LL_TIM_TIM15_TI1_RMP_TIM4: TIM15 TI1 is connected to TIM4 CH1 - * @arg LL_TIM_TIM15_TI1_RMP_LSE: TIM15 TI1 is connected to LSE - * @arg LL_TIM_TIM15_TI1_RMP_CSI: TIM15 TI1 is connected to CSI - * @arg LL_TIM_TIM15_TI1_RMP_MCO2: TIM15 TI1 is connected to MCO2 - * @arg LL_TIM_TIM15_TI2_RMP_GPIO: TIM15 TI2 is connected to GPIO - * @arg LL_TIM_TIM15_TI2_RMP_TIM2: TIM15 TI2 is connected to TIM2 CH2 - * @arg LL_TIM_TIM15_TI2_RMP_TIM3: TIM15 TI2 is connected to TIM3 CH2 - * @arg LL_TIM_TIM15_TI2_RMP_TIM4: TIM15 TI2 is connected to TIM4 CH2 - * - * TIM16: one of the following values: - * @arg LL_TIM_TIM16_TI1_RMP_GPIO: TIM16 TI1 is connected to GPIO - * @arg LL_TIM_TIM16_TI1_RMP_LSI: TIM16 TI1 is connected to LSI - * @arg LL_TIM_TIM16_TI1_RMP_LSE: TIM16 TI1 is connected to LSE - * @arg LL_TIM_TIM16_TI1_RMP_RTC: TIM16 TI1 is connected to RTC wakeup interrupt - * - * TIM17: one of the following values: - * @arg LL_TIM_TIM17_TI1_RMP_GPIO: TIM17 TI1 is connected to GPIO - * @arg LL_TIM_TIM17_TI1_RMP_SPDIF_FS: TIM17 TI1 is connected to SPDIF FS (*) - * @arg LL_TIM_TIM17_TI1_RMP_HSE_1MHZ: TIM17 TI1 is connected to HSE 1MHz - * @arg LL_TIM_TIM17_TI1_RMP_MCO1: TIM17 TI1 is connected to MCO1 - * - * TIM23: one of the following values: (*) - * @arg LL_TIM_TIM23_TI4_RMP_GPIO TIM23_TI4 is connected to GPIO - * @arg LL_TIM_TIM23_TI4_RMP_COMP1 TIM23_TI4 is connected to COMP1 output - * @arg LL_TIM_TIM23_TI4_RMP_COMP2 TIM23_TI4 is connected to COMP2 output - * @arg LL_TIM_TIM23_TI4_RMP_COMP1_COMP2 TIM23_TI4 is connected to COMP2 output - * - * TIM24: one of the following values: (*) - * @arg LL_TIM_TIM24_TI1_RMP_GPIO TIM24_TI1 is connected to GPIO - * @arg LL_TIM_TIM24_TI1_RMP_CAN_TMP TIM24_TI1 is connected to CAN_TMP - * @arg LL_TIM_TIM24_TI1_RMP_CAN_RTP TIM24_TI1 is connected to CAN_RTP - * @arg LL_TIM_TIM24_TI1_RMP_CAN_SOC TIM24_TI1 is connected to CAN_SOC - * - * (*) Value not defined in all devices. \n - * @retval None - */ -static inline void LL_TIM_SetRemap(TIM_TypeDef *TIMx, uint32_t Remap) -{ - MODIFY_REG(TIMx->TISEL, (TIM_TISEL_TI1SEL | TIM_TISEL_TI2SEL | TIM_TISEL_TI3SEL | TIM_TISEL_TI4SEL), Remap); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_FLAG_Management FLAG-Management - * @{ - */ -/** - * @brief Clear the update interrupt flag (UIF). - * @rmtoll SR UIF LL_TIM_ClearFlag_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_UPDATE(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_UIF)); -} - -/** - * @brief Indicate whether update interrupt flag (UIF) is set (update interrupt is pending). - * @rmtoll SR UIF LL_TIM_IsActiveFlag_UPDATE - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_UPDATE(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_UIF) == (TIM_SR_UIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 1 interrupt flag (CC1F). - * @rmtoll SR CC1IF LL_TIM_ClearFlag_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC1(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC1IF)); -} - -/** - * @brief Indicate whether Capture/Compare 1 interrupt flag (CC1F) is set (Capture/Compare 1 interrupt is pending). - * @rmtoll SR CC1IF LL_TIM_IsActiveFlag_CC1 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC1(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC1IF) == (TIM_SR_CC1IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 2 interrupt flag (CC2F). - * @rmtoll SR CC2IF LL_TIM_ClearFlag_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC2(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC2IF)); -} - -/** - * @brief Indicate whether Capture/Compare 2 interrupt flag (CC2F) is set (Capture/Compare 2 interrupt is pending). - * @rmtoll SR CC2IF LL_TIM_IsActiveFlag_CC2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC2IF) == (TIM_SR_CC2IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 3 interrupt flag (CC3F). - * @rmtoll SR CC3IF LL_TIM_ClearFlag_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC3(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC3IF)); -} - -/** - * @brief Indicate whether Capture/Compare 3 interrupt flag (CC3F) is set (Capture/Compare 3 interrupt is pending). - * @rmtoll SR CC3IF LL_TIM_IsActiveFlag_CC3 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC3(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC3IF) == (TIM_SR_CC3IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 4 interrupt flag (CC4F). - * @rmtoll SR CC4IF LL_TIM_ClearFlag_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC4(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC4IF)); -} - -/** - * @brief Indicate whether Capture/Compare 4 interrupt flag (CC4F) is set (Capture/Compare 4 interrupt is pending). - * @rmtoll SR CC4IF LL_TIM_IsActiveFlag_CC4 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC4(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC4IF) == (TIM_SR_CC4IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 5 interrupt flag (CC5F). - * @rmtoll SR CC5IF LL_TIM_ClearFlag_CC5 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC5(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC5IF)); -} - -/** - * @brief Indicate whether Capture/Compare 5 interrupt flag (CC5F) is set (Capture/Compare 5 interrupt is pending). - * @rmtoll SR CC5IF LL_TIM_IsActiveFlag_CC5 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC5(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC5IF) == (TIM_SR_CC5IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 6 interrupt flag (CC6F). - * @rmtoll SR CC6IF LL_TIM_ClearFlag_CC6 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC6(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC6IF)); -} - -/** - * @brief Indicate whether Capture/Compare 6 interrupt flag (CC6F) is set (Capture/Compare 6 interrupt is pending). - * @rmtoll SR CC6IF LL_TIM_IsActiveFlag_CC6 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC6(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC6IF) == (TIM_SR_CC6IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the commutation interrupt flag (COMIF). - * @rmtoll SR COMIF LL_TIM_ClearFlag_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_COM(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_COMIF)); -} - -/** - * @brief Indicate whether commutation interrupt flag (COMIF) is set (commutation interrupt is pending). - * @rmtoll SR COMIF LL_TIM_IsActiveFlag_COM - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_COM(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_COMIF) == (TIM_SR_COMIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the trigger interrupt flag (TIF). - * @rmtoll SR TIF LL_TIM_ClearFlag_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_TRIG(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_TIF)); -} - -/** - * @brief Indicate whether trigger interrupt flag (TIF) is set (trigger interrupt is pending). - * @rmtoll SR TIF LL_TIM_IsActiveFlag_TRIG - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_TRIG(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_TIF) == (TIM_SR_TIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the break interrupt flag (BIF). - * @rmtoll SR BIF LL_TIM_ClearFlag_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_BRK(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_BIF)); -} - -/** - * @brief Indicate whether break interrupt flag (BIF) is set (break interrupt is pending). - * @rmtoll SR BIF LL_TIM_IsActiveFlag_BRK - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_BRK(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_BIF) == (TIM_SR_BIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the break 2 interrupt flag (B2IF). - * @rmtoll SR B2IF LL_TIM_ClearFlag_BRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_BRK2(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_B2IF)); -} - -/** - * @brief Indicate whether break 2 interrupt flag (B2IF) is set (break 2 interrupt is pending). - * @rmtoll SR B2IF LL_TIM_IsActiveFlag_BRK2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_BRK2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_B2IF) == (TIM_SR_B2IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 1 over-capture interrupt flag (CC1OF). - * @rmtoll SR CC1OF LL_TIM_ClearFlag_CC1OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC1OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC1OF)); -} - -/** - * @brief Indicate whether Capture/Compare 1 over-capture interrupt flag (CC1OF) is set - * (Capture/Compare 1 interrupt is pending). - * @rmtoll SR CC1OF LL_TIM_IsActiveFlag_CC1OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC1OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC1OF) == (TIM_SR_CC1OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 2 over-capture interrupt flag (CC2OF). - * @rmtoll SR CC2OF LL_TIM_ClearFlag_CC2OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC2OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC2OF)); -} - -/** - * @brief Indicate whether Capture/Compare 2 over-capture interrupt flag (CC2OF) is set - * (Capture/Compare 2 over-capture interrupt is pending). - * @rmtoll SR CC2OF LL_TIM_IsActiveFlag_CC2OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC2OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC2OF) == (TIM_SR_CC2OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 3 over-capture interrupt flag (CC3OF). - * @rmtoll SR CC3OF LL_TIM_ClearFlag_CC3OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC3OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC3OF)); -} - -/** - * @brief Indicate whether Capture/Compare 3 over-capture interrupt flag (CC3OF) is set - * (Capture/Compare 3 over-capture interrupt is pending). - * @rmtoll SR CC3OF LL_TIM_IsActiveFlag_CC3OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC3OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC3OF) == (TIM_SR_CC3OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 4 over-capture interrupt flag (CC4OF). - * @rmtoll SR CC4OF LL_TIM_ClearFlag_CC4OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC4OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC4OF)); -} - -/** - * @brief Indicate whether Capture/Compare 4 over-capture interrupt flag (CC4OF) is set - * (Capture/Compare 4 over-capture interrupt is pending). - * @rmtoll SR CC4OF LL_TIM_IsActiveFlag_CC4OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC4OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC4OF) == (TIM_SR_CC4OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the system break interrupt flag (SBIF). - * @rmtoll SR SBIF LL_TIM_ClearFlag_SYSBRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_SYSBRK(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_SBIF)); -} - -/** - * @brief Indicate whether system break interrupt flag (SBIF) is set (system break interrupt is pending). - * @rmtoll SR SBIF LL_TIM_IsActiveFlag_SYSBRK - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_SYSBRK(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_SBIF) == (TIM_SR_SBIF)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_IT_Management IT-Management - * @{ - */ -/** - * @brief Enable update interrupt (UIE). - * @rmtoll DIER UIE LL_TIM_EnableIT_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_UPDATE(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_UIE); -} - -/** - * @brief Disable update interrupt (UIE). - * @rmtoll DIER UIE LL_TIM_DisableIT_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_UPDATE(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_UIE); -} - -/** - * @brief Indicates whether the update interrupt (UIE) is enabled. - * @rmtoll DIER UIE LL_TIM_IsEnabledIT_UPDATE - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_UPDATE(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_UIE) == (TIM_DIER_UIE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 1 interrupt (CC1IE). - * @rmtoll DIER CC1IE LL_TIM_EnableIT_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC1(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC1IE); -} - -/** - * @brief Disable capture/compare 1 interrupt (CC1IE). - * @rmtoll DIER CC1IE LL_TIM_DisableIT_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC1(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1IE); -} - -/** - * @brief Indicates whether the capture/compare 1 interrupt (CC1IE) is enabled. - * @rmtoll DIER CC1IE LL_TIM_IsEnabledIT_CC1 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC1(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1IE) == (TIM_DIER_CC1IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 2 interrupt (CC2IE). - * @rmtoll DIER CC2IE LL_TIM_EnableIT_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC2IE); -} - -/** - * @brief Disable capture/compare 2 interrupt (CC2IE). - * @rmtoll DIER CC2IE LL_TIM_DisableIT_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC2(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2IE); -} - -/** - * @brief Indicates whether the capture/compare 2 interrupt (CC2IE) is enabled. - * @rmtoll DIER CC2IE LL_TIM_IsEnabledIT_CC2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2IE) == (TIM_DIER_CC2IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 3 interrupt (CC3IE). - * @rmtoll DIER CC3IE LL_TIM_EnableIT_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC3(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC3IE); -} - -/** - * @brief Disable capture/compare 3 interrupt (CC3IE). - * @rmtoll DIER CC3IE LL_TIM_DisableIT_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC3(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3IE); -} - -/** - * @brief Indicates whether the capture/compare 3 interrupt (CC3IE) is enabled. - * @rmtoll DIER CC3IE LL_TIM_IsEnabledIT_CC3 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC3(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3IE) == (TIM_DIER_CC3IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 4 interrupt (CC4IE). - * @rmtoll DIER CC4IE LL_TIM_EnableIT_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC4(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC4IE); -} - -/** - * @brief Disable capture/compare 4 interrupt (CC4IE). - * @rmtoll DIER CC4IE LL_TIM_DisableIT_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC4(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4IE); -} - -/** - * @brief Indicates whether the capture/compare 4 interrupt (CC4IE) is enabled. - * @rmtoll DIER CC4IE LL_TIM_IsEnabledIT_CC4 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC4(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4IE) == (TIM_DIER_CC4IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable commutation interrupt (COMIE). - * @rmtoll DIER COMIE LL_TIM_EnableIT_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_COM(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_COMIE); -} - -/** - * @brief Disable commutation interrupt (COMIE). - * @rmtoll DIER COMIE LL_TIM_DisableIT_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_COM(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_COMIE); -} - -/** - * @brief Indicates whether the commutation interrupt (COMIE) is enabled. - * @rmtoll DIER COMIE LL_TIM_IsEnabledIT_COM - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_COM(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_COMIE) == (TIM_DIER_COMIE)) ? 1UL : 0UL); -} - -/** - * @brief Enable trigger interrupt (TIE). - * @rmtoll DIER TIE LL_TIM_EnableIT_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_TRIG(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_TIE); -} - -/** - * @brief Disable trigger interrupt (TIE). - * @rmtoll DIER TIE LL_TIM_DisableIT_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_TRIG(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_TIE); -} - -/** - * @brief Indicates whether the trigger interrupt (TIE) is enabled. - * @rmtoll DIER TIE LL_TIM_IsEnabledIT_TRIG - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_TRIG(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_TIE) == (TIM_DIER_TIE)) ? 1UL : 0UL); -} - -/** - * @brief Enable break interrupt (BIE). - * @rmtoll DIER BIE LL_TIM_EnableIT_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_BRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_BIE); -} - -/** - * @brief Disable break interrupt (BIE). - * @rmtoll DIER BIE LL_TIM_DisableIT_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_BRK(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_BIE); -} - -/** - * @brief Indicates whether the break interrupt (BIE) is enabled. - * @rmtoll DIER BIE LL_TIM_IsEnabledIT_BRK - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_BRK(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_BIE) == (TIM_DIER_BIE)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_DMA_Management DMA Management - * @{ - */ -/** - * @brief Enable update DMA request (UDE). - * @rmtoll DIER UDE LL_TIM_EnableDMAReq_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_UPDATE(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_UDE); -} - -/** - * @brief Disable update DMA request (UDE). - * @rmtoll DIER UDE LL_TIM_DisableDMAReq_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_UPDATE(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_UDE); -} - -/** - * @brief Indicates whether the update DMA request (UDE) is enabled. - * @rmtoll DIER UDE LL_TIM_IsEnabledDMAReq_UPDATE - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_UPDATE(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_UDE) == (TIM_DIER_UDE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 1 DMA request (CC1DE). - * @rmtoll DIER CC1DE LL_TIM_EnableDMAReq_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC1(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC1DE); -} - -/** - * @brief Disable capture/compare 1 DMA request (CC1DE). - * @rmtoll DIER CC1DE LL_TIM_DisableDMAReq_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC1(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1DE); -} - -/** - * @brief Indicates whether the capture/compare 1 DMA request (CC1DE) is enabled. - * @rmtoll DIER CC1DE LL_TIM_IsEnabledDMAReq_CC1 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC1(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1DE) == (TIM_DIER_CC1DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 2 DMA request (CC2DE). - * @rmtoll DIER CC2DE LL_TIM_EnableDMAReq_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC2DE); -} - -/** - * @brief Disable capture/compare 2 DMA request (CC2DE). - * @rmtoll DIER CC2DE LL_TIM_DisableDMAReq_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC2(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2DE); -} - -/** - * @brief Indicates whether the capture/compare 2 DMA request (CC2DE) is enabled. - * @rmtoll DIER CC2DE LL_TIM_IsEnabledDMAReq_CC2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2DE) == (TIM_DIER_CC2DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 3 DMA request (CC3DE). - * @rmtoll DIER CC3DE LL_TIM_EnableDMAReq_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC3(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC3DE); -} - -/** - * @brief Disable capture/compare 3 DMA request (CC3DE). - * @rmtoll DIER CC3DE LL_TIM_DisableDMAReq_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC3(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3DE); -} - -/** - * @brief Indicates whether the capture/compare 3 DMA request (CC3DE) is enabled. - * @rmtoll DIER CC3DE LL_TIM_IsEnabledDMAReq_CC3 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC3(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3DE) == (TIM_DIER_CC3DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 4 DMA request (CC4DE). - * @rmtoll DIER CC4DE LL_TIM_EnableDMAReq_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC4(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC4DE); -} - -/** - * @brief Disable capture/compare 4 DMA request (CC4DE). - * @rmtoll DIER CC4DE LL_TIM_DisableDMAReq_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC4(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4DE); -} - -/** - * @brief Indicates whether the capture/compare 4 DMA request (CC4DE) is enabled. - * @rmtoll DIER CC4DE LL_TIM_IsEnabledDMAReq_CC4 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC4(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4DE) == (TIM_DIER_CC4DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable commutation DMA request (COMDE). - * @rmtoll DIER COMDE LL_TIM_EnableDMAReq_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_COM(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_COMDE); -} - -/** - * @brief Disable commutation DMA request (COMDE). - * @rmtoll DIER COMDE LL_TIM_DisableDMAReq_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_COM(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_COMDE); -} - -/** - * @brief Indicates whether the commutation DMA request (COMDE) is enabled. - * @rmtoll DIER COMDE LL_TIM_IsEnabledDMAReq_COM - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_COM(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_COMDE) == (TIM_DIER_COMDE)) ? 1UL : 0UL); -} - -/** - * @brief Enable trigger interrupt (TDE). - * @rmtoll DIER TDE LL_TIM_EnableDMAReq_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_TRIG(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_TDE); -} - -/** - * @brief Disable trigger interrupt (TDE). - * @rmtoll DIER TDE LL_TIM_DisableDMAReq_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_TRIG(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_TDE); -} - -/** - * @brief Indicates whether the trigger interrupt (TDE) is enabled. - * @rmtoll DIER TDE LL_TIM_IsEnabledDMAReq_TRIG - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_TRIG(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_TDE) == (TIM_DIER_TDE)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_EVENT_Management EVENT-Management - * @{ - */ -/** - * @brief Generate an update event. - * @rmtoll EGR UG LL_TIM_GenerateEvent_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_UPDATE(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_UG); -} - -/** - * @brief Generate Capture/Compare 1 event. - * @rmtoll EGR CC1G LL_TIM_GenerateEvent_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC1(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC1G); -} - -/** - * @brief Generate Capture/Compare 2 event. - * @rmtoll EGR CC2G LL_TIM_GenerateEvent_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC2G); -} - -/** - * @brief Generate Capture/Compare 3 event. - * @rmtoll EGR CC3G LL_TIM_GenerateEvent_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC3(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC3G); -} - -/** - * @brief Generate Capture/Compare 4 event. - * @rmtoll EGR CC4G LL_TIM_GenerateEvent_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC4(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC4G); -} - -/** - * @brief Generate commutation event. - * @rmtoll EGR COMG LL_TIM_GenerateEvent_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_COM(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_COMG); -} - -/** - * @brief Generate trigger event. - * @rmtoll EGR TG LL_TIM_GenerateEvent_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_TRIG(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_TG); -} - -/** - * @brief Generate break event. - * @rmtoll EGR BG LL_TIM_GenerateEvent_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_BRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_BG); -} - -/** - * @brief Generate break 2 event. - * @rmtoll EGR B2G LL_TIM_GenerateEvent_BRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_BRK2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_B2G); -} - -/** - * @} - */ - -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_EF_Init Initialisation and deinitialisation functions - * @{ - */ - -ErrorStatus LL_TIM_DeInit(const TIM_TypeDef *TIMx); -void LL_TIM_StructInit(LL_TIM_InitTypeDef *TIM_InitStruct); -ErrorStatus LL_TIM_Init(TIM_TypeDef *TIMx, const LL_TIM_InitTypeDef *TIM_InitStruct); -void LL_TIM_OC_StructInit(LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); -ErrorStatus LL_TIM_OC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); -void LL_TIM_IC_StructInit(LL_TIM_IC_InitTypeDef *TIM_ICInitStruct); -ErrorStatus LL_TIM_IC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_IC_InitTypeDef *TIM_IC_InitStruct); -void LL_TIM_ENCODER_StructInit(LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); -ErrorStatus LL_TIM_ENCODER_Init(TIM_TypeDef *TIMx, const LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); -void LL_TIM_HALLSENSOR_StructInit(LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); -ErrorStatus LL_TIM_HALLSENSOR_Init(TIM_TypeDef *TIMx, const LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); -void LL_TIM_BDTR_StructInit(LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); -ErrorStatus LL_TIM_BDTR_Init(TIM_TypeDef *TIMx, const LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/** - * @} - */ - -/** - * @} - */ - -#endif /* TIM1 || TIM2 || TIM3 || TIM4 || TIM5 || TIM6 || TIM7 || TIM8 || TIM12 || TIM13 ||TIM14 || TIM15 || TIM16 || TIM17 || TIM23 || TIM24 */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32H7xx_LL_TIM_H */ diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 2132cfb78..c2b56e106 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -27,8 +27,7 @@ class TimerRegister : public RegisterBase { static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); -class TIM_TypeDef{ -public: +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/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index f363cee7f..6d5850340 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -2,6 +2,15 @@ #define STM32H723xx_WRAPPER_H #include + +#define STM32H723xx + +#if defined(__GNUC__) || defined(__GNUG__) +# define __STATIC_INLINE static inline +#else +# error :) +#endif + #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permissions */ #else @@ -12,8 +21,7 @@ #define __RBIT __RBIT__CMSIS #define TIM_TypeDef TIM_TypeDef__CMSIS -// don't do anything in "core_cm7.h" -#define __CORE_CM7_H_GENERIC +// only do __CORE_CM7_H_GENERIC in "core_cm7.h" #define __CORE_CM7_H_DEPENDANT #include "stm32h723xx.h" @@ -21,7 +29,6 @@ #undef TIM_TypeDef #undef RCC - extern RCC_TypeDef *RCC; #endif // STM32H723xx_WRAPPER_H From e8a90e6fa69440a09cdb976671e6e9522ee2db87 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:34:30 +0100 Subject: [PATCH 100/281] fix ci/cd and add the other submodule to be automatically added --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb2cfe6e..57955f586 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ endif() if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) execute_process( - COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx + COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx Drivers/STM32H7xx_HAL_Driver WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 ) endif() @@ -38,6 +38,11 @@ endif() if(NOT CMAKE_CROSSCOMPILING) message(STATUS "Compiling for simulator") add_subdirectory(Tests) +else() + execute_process( + COMMAND git submodule update --init --depth 1 Drivers/BSP/Components/lan8742 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 + ) endif() # ============================ From cab07f976f3dc96e412980a43e8658de70a2d31f Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:36:44 +0100 Subject: [PATCH 101/281] fix: actually add stm32h7xx_ll_tim_wrapper.h --- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h new file mode 100644 index 000000000..6d82146f0 --- /dev/null +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -0,0 +1,17 @@ +#ifndef STM32H7xx_LL_TIM_WRAPPER_H +#define STM32H7xx_LL_TIM_WRAPPER_H + +#include + +#include "MockedDrivers/stm32h723xx_wrapper.h" + +#include "stm32h7xx.h" + +#include "MockedDrivers/mocked_ll_tim.hpp" +#define uint32_t size_t +#include "stm32h7xx_ll_tim.h" +#undef uint32_t + +#include "MockedDrivers/compiler_specific.hpp" + +#endif // STM32H7xx_LL_TIM_WRAPPER_H From 86d300821b6a27f9b331cc1f58045bb6ac962dbf Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:54:29 +0100 Subject: [PATCH 102/281] try to fix ci/cd warning --- Inc/MockedDrivers/common.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 76326dc42..83fb6f217 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -15,6 +15,7 @@ #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) +#if 0 #ifdef SET_BIT # undef SET_BIT #endif @@ -43,3 +44,4 @@ #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) +#endif From 8856395789d8fda939bb829951b99815f7816cad Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:58:03 +0100 Subject: [PATCH 103/281] try fix warnings again --- Inc/MockedDrivers/common.hpp | 2 -- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 83fb6f217..76326dc42 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -15,7 +15,6 @@ #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) -#if 0 #ifdef SET_BIT # undef SET_BIT #endif @@ -44,4 +43,3 @@ #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) -#endif diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index 6d82146f0..cf9b0d15e 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -12,6 +12,6 @@ #include "stm32h7xx_ll_tim.h" #undef uint32_t -#include "MockedDrivers/compiler_specific.hpp" +#include "MockedDrivers/common.hpp" #endif // STM32H7xx_LL_TIM_WRAPPER_H From e8b7d8d40b95ac14b84f4ce3ef50a384145b60dc Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 16:20:55 +0100 Subject: [PATCH 104/281] fix: add ignore Woverflow to stm32h7xx_ll_tim --- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index cf9b0d15e..fc918244c 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -8,9 +8,16 @@ #include "stm32h7xx.h" #include "MockedDrivers/mocked_ll_tim.hpp" + +// -Woverflow does not do much in stm32h7xx_ll_tim.h +// the only places where it's used in are in WRITE_REG(reg, ~(bit)) +// where they should use CLEAR_BIT(reg, bit) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverflow" #define uint32_t size_t #include "stm32h7xx_ll_tim.h" #undef uint32_t +#pragma GCC diagnostic pop #include "MockedDrivers/common.hpp" From 8506d927b7cbbe9b26d50c3c211b50cce2a0fa9c Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 19 Dec 2025 11:27:37 +0100 Subject: [PATCH 105/281] fix: remove need to ignore Woverflow warnings --- Inc/MockedDrivers/common.hpp | 9 ++++++--- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 6 ------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 76326dc42..def8838ec 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -28,18 +28,21 @@ # undef MODIFY_REG #endif +// this is needed because later I will do a #define uint32_t size_t +typedef uint32_t u32; + #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT))) +#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT))) #define READ_BIT(REG, BIT) ((REG) & (BIT)) #define CLEAR_REG(REG) ((REG) = (0x0)) -#define WRITE_REG(REG, VAL) ((REG) = static_cast(VAL)) +#define WRITE_REG(REG, VAL) ((REG) = static_cast(VAL)) #define READ_REG(REG) ((REG)) -#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(u32)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index fc918244c..904f5bb5f 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -9,15 +9,9 @@ #include "MockedDrivers/mocked_ll_tim.hpp" -// -Woverflow does not do much in stm32h7xx_ll_tim.h -// the only places where it's used in are in WRITE_REG(reg, ~(bit)) -// where they should use CLEAR_BIT(reg, bit) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverflow" #define uint32_t size_t #include "stm32h7xx_ll_tim.h" #undef uint32_t -#pragma GCC diagnostic pop #include "MockedDrivers/common.hpp" From 9313709ab3bee6d8b35a3fb11540f819bf67aa03 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 19 Dec 2025 14:40:31 +0100 Subject: [PATCH 106/281] fix: Remove tim_register_definitions.hpp We're already including them in stm32h723xx_wrapper --- Inc/MockedDrivers/mocked_ll_tim.hpp | 2 +- .../tim_register_definitions.hpp | 914 ------------------ 2 files changed, 1 insertion(+), 915 deletions(-) delete mode 100644 Inc/MockedDrivers/tim_register_definitions.hpp diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index c2b56e106..eb5a8b3bf 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,9 +1,9 @@ #pragma once #include #include "MockedDrivers/stm32h723xx_wrapper.h" +#include "stm32h7xx.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" -#include "MockedDrivers/tim_register_definitions.hpp" #include "MockedDrivers/Register.hpp" #include enum class TimReg { diff --git a/Inc/MockedDrivers/tim_register_definitions.hpp b/Inc/MockedDrivers/tim_register_definitions.hpp deleted file mode 100644 index 1788be399..000000000 --- a/Inc/MockedDrivers/tim_register_definitions.hpp +++ /dev/null @@ -1,914 +0,0 @@ -#pragma once -/******************************************************************************/ -/* */ -/* TIM */ -/* */ -/******************************************************************************/ -#define TIM_BREAK_INPUT_SUPPORT /*! Date: Sat, 27 Dec 2025 13:31:57 +0100 Subject: [PATCH 107/281] Initial TimerDomain commit, lots of work to do... --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 622 +++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 Inc/HALAL/Models/TimerDomain/TimerDomain.hpp diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp new file mode 100644 index 000000000..ba76d8c84 --- /dev/null +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -0,0 +1,622 @@ +/* + * New TimerPeripheral.hpp + * + * Created on: 3 dic. 2025 + * Author: victor + */ + +#pragma once + +#include "stm32h7xx_hal_tim.h" + +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim3; +extern TIM_HandleTypeDef htim4; +extern TIM_HandleTypeDef htim6; +extern TIM_HandleTypeDef htim7; +extern TIM_HandleTypeDef htim8; +extern TIM_HandleTypeDef htim12; +extern TIM_HandleTypeDef htim13; +extern TIM_HandleTypeDef htim14; +extern TIM_HandleTypeDef htim15; +extern TIM_HandleTypeDef htim16; +extern TIM_HandleTypeDef htim17; +extern TIM_HandleTypeDef htim23; +extern TIM_HandleTypeDef htim24; + +/* Tim1 & Tim8 are advanced-control timers + * their ARR & prescaler are 16bit + * they have up to 6 independent channels for: + * - input capture (not channel 5 or 6) + * - output capture + * - PWM generation + * - One-pulse mode output + */ + +/* Timers {TIM2, TIM5, TIM23, TIM24} are the only 32-bit counter resolution timers, the rest are 16-bit */ +/* Timers 2, 3, 4, 5, 23, 24 are general-purpose timers + * Timers 12, 13, 14 are also general-purpose timers (but separate in the ref manual) + * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) + */ + +/* Tim6 & Tim7 are basic timers */ + +/* basic timer features: + - 16-bit ARR upcounter + - 16-bit PSC + - Synchronization circuit to trigger the DAC + - Interrupt/DMA generation on the update event +*/ + +/* advanced timer features: + - 16-bit ARR up/down counter + - 16-bit PSC + - Up to 6 independent channels for: + · Input capture (all channels but 5 and 6) + · Output compare + · PWM generation (Edge and Center aligned mode) + · One-pulse mode output + - Complementary outputs with programmable dead-time + - Synchronization circuit to control the timer with + external signals and to interconnect several timers together. + - Repetition counter to update the timer registers only after + a given number of cycles of the counter. + - 2 break inputs to put the timer’s output signals in a safe user selectable configuration. + - Interrupt/DMA generation on the following events: + · Update: counter overflow/underflow, counter initialization (by software or internal/external trigger) + · Trigger event (counter start, stop, initialization or count by internal/external trigger) + · Input capture + · Output compare + - Supports incremental (quadrature) encoder and Hall-sensor circuitry for positioning purposes + - Trigger input for external clock or cycle-by-cycle current management +*/ +class TimerDomain { + static constexpr std::array create_idxmap() { + std::array result{}; + + // invalid timers that don't exist + result[0] = -1; + result[9] = -1; result[10] = -1; result[11] = -1; + result[18] = -1; result[19] = -1; result[20] = -1; result[21] = -1; result[22] = -1; + + // general-purpose timers + result[2] = 0; result[3] = 1; result[4] = 2; + result[5] = 3; result[23] = 4; result[24] = 5; + + // more general-purpose timers + result[12] = 6; result[13] = 7; result[14] = 8; + + // more general-purpose timers + result[15] = 9; result[16] = 10; result[17] = 11; + + // basic timers + result[6] = 12; result[7] = 13; + + // advanced control timers + result[1] = 14; result[8] = 15; + + return result; + } + + static constexpr std::array idxmap = create_idxmap(); + + static const TIM_HandleTypeDef *hal_handles[16] = { + // general purpose timers + &htim2, &htim3, &htim4, &htim5, &htim23, &htim24, + &htim12, &htim13, &htim14, + &htim15, &htim16, &htim17, + + // basic timers + &htim6, &htim7, + + // advanced control timers + &htim1, &htim8 + }; + + static const TIM_TypeDef *cmsis_timers[16] = { + // general purpose timers + TIM2, TIM3, TIM4, TIM5, TIM23, TIM24, + TIM12, TIM13, TIM14, + TIM15, TIM16, TIM17, + + // basic timers + TIM6, TIM7, + + // advanced control timers + TIM1, TIM8 + }; + + static inline void rcc_enable_timer(TIM_TypeDef *tim) { + switch(tim) { + case TIM2: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM2EN); break; + case TIM3: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM3EN); break; + case TIM4: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM4EN); break; + case TIM5: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM5EN); break; + case TIM6: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM6EN); break; + case TIM7: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM7EN); break; + case TIM12: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM12EN); break; + case TIM13: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM13EN); break; + case TIM14: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM14EN); break; + + case TIM24: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM24EN); break; + case TIM23: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM23EN); break; + + case TIM17: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM17EN); break; + case TIM16: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM16EN); break; + case TIM15: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM15EN); break; + case TIM8: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM8EN); break; + case TIM1: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM1EN); break; + } + } + + static consteval bool check_timer(Config *cfg, const Entry req, uint16_t timer_idx, int reqidx) { + if(req.period == 0) { + ErrorInRequestN("Error: In request reqidx: period must be greater than 0 (>0)", reqidx); + return false; + } + + uint8_t reqint = static_cast(req.request); + if(!(reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24)) { + if(req.period > 0xFFFF) { + ErrorInRequestN("Error: In request reqidx: Timers other than {TIM2, TIM5, TIM23, TIM24} have a maximum period of 0xFFFF (they are uint16_t)", reqidx); + return false; + } + } + + if(!(reqint == 1 || reqint == 8 || + reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || + reqint == 3 || reqint == 4)) + { + if(req.counting_mode != CountingMode::UP) { + ErrorInRequestN("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting", reqidx); + return false; + } + } + + if(timer_idx == 12 || timer_idx == 13) { + // basic timers + cfg->kind = TimerDomain::Kind::Basic; + } else if(timer_idx == 14 || timer_idx == 15) { + // advanced timers + cfg->kind = TimerDomain::Kind::Advanced; + } else { + if(timer_idx >= 0 && timer_idx <= 5) { + // general purpose timers 1 + } else if(timer_idx >= 6 && timer_idx <= 8) { + // general purpose timers 2 + } else if(timer_idx >= 9 && timer_idx <= 11) { + // general purpose timers 3 + } else { + ErrorInRequestN("Unknown timer idx in reqidx", reqidx); + } + + cfg->kind = TimerDomain::Kind::GeneralPurpose; + } + } + + /* to show the error with an index */ + static consteval ErrorInRequestN(char *str, int n) + { + switch(n) { + case 0: compile_error(str); + case 1: compile_error(str); + case 2: compile_error(str); + case 3: compile_error(str); + case 4: compile_error(str); + case 5: compile_error(str); + case 6: compile_error(str); + case 7: compile_error(str); + case 8: compile_error(str); + case 9: compile_error(str); + case 10: compile_error(str); + case 11: compile_error(str); + case 12: compile_error(str); + case 13: compile_error(str); + case 14: compile_error(str); + case 15: compile_error(str); + } + } + + enum Kind : uint8_t { + Basic, + GeneralPurpose, + Advanced, + }; + +public: + enum CountingMode : uint8_t { + UP = 0, + DOWN = 1, + /* center-aligned = counter counts up and down alternatively */ + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting down */ + CENTER_ALIGNED_INTERRUPT_DOWN = 2, + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting up */ + CENTER_ALIGNED_INTERRUPT_UP = 3, + /* both up and down */ + CENTER_ALIGNED_INTERRUPT_BOTH = 4, + }; + + enum PWM_MODE : uint8_t { + NORMAL = 0, + PHASED = 1, + CENTER_ALIGNED = 2, + }; + + struct PWMData { + uint32_t channel; + PWM_MODE mode; + }; + + /* The number corresponds with the timer nº */ + enum TimerRequest : uint8_t { + Advanced1 = 1, + Advanced2 = 8, + + AnyGeneralPurpose = 0xFF, + GeneralPurpose1 = 2, + GeneralPurpose2 = 3, + GeneralPurpose3 = 4, + GeneralPurpose4 = 5, + GeneralPurpose5 = 23, + GeneralPurpose6 = 24, + + GeneralPurpose7 = 12, + GeneralPurpose8 = 13, + GeneralPurpose9 = 14, + + GeneralPurpose10 = 15, + GeneralPurpose11 = 16, + GeneralPurpose12 = 17, + + Basic1 = 6, + Basic2 = 7, + }; + + struct Entry { + string name; + TimerRequest request; + ST_LIB::GPIODomain::Pin *pin; + TimerDomain::CountingMode counting_mode; + uint16_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + + struct Device { + using domain = TimerDomain; + Entry e; + + consteval Device(string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, + ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, + uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, + uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) : + e(name, request, pin, counting_mode, prescaler, period, deadtime, polarity, negated_polarity) {} + + template + consteval void inscribe(Ctx &ctx) const { + ctx.template add(e); + } + }; + + // There are 16 timers + static constexpr std::size_t max_instances = 16; + + struct Config { + char name[8]; /* "Timerxx\0" */ + TimerDomain::Kind kind; + uint16_t timer_idx; + ST_LIB::GPIODomain::Pin *asociated_pin; + TimerDomain::CountingMode counting_mode; + uint32_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + + template + static consteval std::array build(span requests) { + array cfgs{}; + uint16_t cfg_idx = 0; + bool usedTimer[25] = {0}; + + if(requests.size() > max_instances) { + throw "too many Timer requests, there are only 16 timers"; + } + + int remaining_requests[max_instances] = {}; + std::size_t count_remaining_requests = requsts.size(); + for(int i = 0; i < requests.size(); i++) remaining_requests[i] = i; + + for(int i = 0; i < requests.size(); i++) { + if(requests[i].request != TimerRequest::AnyGeneralPurpose && + (requests[i].request < 1 || requests[i].request > 24 || + (requests[i].request > 17 && requests[i].request < 23))) + { + ErrorInRequestN("Invalid TimerRequest value for timer i", i); + } + } + + // First find any that have requested a specific timer + for(std::size_t i = 0; i < N; i++) { + uint8_t reqint = static_cast(requests[i].request); + if(reqint != static_cast(TimerRequest::AnyGeneralPurpose)) { + if(usedTimer[reqint]) { + ErrorInRequestN("Error: Timer already used. Error in request i", i); + } + + Config cfg; + if(requests[i].name[0] == '\0') { + // "Timer" + tostring(reqint) + cfg.name[0] = 'T'; + cfg.name[1] = 'i'; + cfg.name[2] = 'm'; + cfg.name[3] = 'e'; + cfg.name[4] = 'r'; + cfg.name[5] = (reqint/10) + '0'; + cfg.name[6] = (reqint%10) + '0'; + } else { + if(requests[i].name.length() >= sizeof(cfg.name)) { + ErrorInRequestN("Error: Timer name too large, max = 7 (sizeof cfg.name - 1). In request i", i); + } + for(int si = 0; si < requests[i].name.length(); si++) { + cfg.name[si] = requests[i].name[si]; + } + cfg.name[requests[i].name.length()] = '\0'; + } + cfg.timer_idx = TimerDomain.idxmap[reqint]; + cfg.prescaler = requests[i].prescaler; + cfg.period = requests[i].period; + cfg.deadtime = requests[i].deadtime; + cfg.polarity = requests[i].polarity; + cfg.negated_polarity = requests[i].negated_polarity; + + cfgs[cfg_idx++] = cfg; + + // unordered remove + count_remaining_requests--; + remaining_requests[i] = remaining_requests[count_remaining_requests]; + } + } + + // Now do AnyGeneralPurpose + for(int i = 0; i < count_remaining_requests; i++) { + const Entry &e = requests[remaining_requests[i]]; + if(e.request == AnyGeneralPurpose) { + // TODO: Find first general purpose timer that isn't used + } + } + + return cfgs; + } + + // Runtime object + struct Instance { + template friend struct TimerWrapper; + + inline void counter_enable() { + SET_BIT(tim->CR1, TIM_CR1_CEN); + } + inline void counter_disable() { + CLEAR_BIT(tim->CR1, TIM_CR1_CEN); + } + + inline void clear_update_interrupt_flag() { + CLEAR_BIT(tim->SR, TIM_SR_UIF); + } + + /* Enabled by default */ + inline void enable_update_interrupt() { + CLEAR_BIT(tim->CR1, TIM_CR1_UDIS); + } + inline void disable_update_interrupt() { + SET_BIT(tim->CR1, TIM_CR1_UDIS); + } + + /* interrupt gets called only once, counter needs to be reenabled */ + inline void set_one_pulse_mode() { + SET_BIT(tim->CR1, TIM_CR1_OPM); + } + inline void multi_interrupt() { + CLEAR_BIT(tim->CR1, TIM_CR1_OPM); + } + + inline TIM_HandleTypeDef *get_hal_handle() { + return hal_tim; + } + inline TIM_TypeDef *get_cmsis_handle() { + return tim; + } + + template + inline void configure(void (*callback)()) { + if constexpr (psc != 0) { + tim->PSC = psc; + } + this.callback = callback; + this.counter_enable(); + } + + // leftover from old TimerPeripheral, maybe this was useful? + inline uint32_t get_prescaler() { + return tim->PSC; + } + inline uint32_t get_period() { + return tim->ARR; + } + }; + + template + struct TimerWrapper { + TIM_TypeDef *tim; + TIM_HandleTypeDef *hal_tim; + char name[8]; + const TimerDomain::Kind kind; + uint16_t timer_idx; + void (*callback)(TimerDomain::Instance); + + // NOTE: Need counter_enable() here for configure(), kept counter_disable() for consistency + if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { + // advanced specific functions + } + + if constexpr (dev.e.request != TimerRequest::Basic1 && dev.e.request != TimerRequest::Basic2) { + // general purpose and advanced functions + } + + /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ + template + inline void set_mode(void) { + constexpr uint8_t reqint = static_cast(dev.e.request); + if constexpr (!(reqint == 1 || reqint == 8 || + reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || + reqint == 3 || reqint == 4)) + { + compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + return; + } + + if constexpr (mode == CounterMode::UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == CounterMode::DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } + } + }; + + 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 Config &e = cfgs[i]; + + 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; + handle->Init.Period = e.period; + handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + handle->Init.RepetitionCounter = 0; + + TIM_TypeDef *tim = &cmsis_timers[e.timer_idx]; + tim->PSC = e.prescaler; + tim->ARR = e.period; + + if constexpr (e.counting_mode == CounterMode::UP) { + CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (e.counting_mode == CounterMode::DOWN) { + SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } + + rcc_enable_timer(tim); + + // InputCapture stuff should be dome somewhere else.. + // PWM stuff should be done somewhere else.. + + instances[i] = Instance{ + .tim = &cmsis_timers[e.timer_idx], + .hal_tim = handle, + .name = {e.name[0], e.name[1], e.name[2], e.name[3], e.name[4], e.name[5], e.name[6], e.name[7]}, + .kind = e.kind, + .timer_idx = e.timer_idx, + }; + } + } + } + + // Leftover from last iteration of the design of NewTimerPeripheral, will cleanup soon +private: + enum TIM_CAPABILITIES { + Basic_Start = 0, + Basic_End = 1, + + General_Start = 2, + General_End = 13, + + Advanced_Start = 14, + Advanced_End = 15, + + Count_Cap = 16, + }; + + // This should use __builtin_ffs() - 1 to get the index of the next + static uint32_t free_bmp = 0xFFFF'FFFF; + + static void (*callbacks)()[16]; +}; + + +/* 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); + } +*/ \ No newline at end of file From 4c86596ef2ec5958a00784160e42c75a03757cdb Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 13:32:50 +0100 Subject: [PATCH 108/281] Change name to TimerDomain.hpp in comment --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ba76d8c84..ce0c7086d 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -1,5 +1,5 @@ /* - * New TimerPeripheral.hpp + * TimerDomain.hpp * * Created on: 3 dic. 2025 * Author: victor From a4ca0df8449017e593d5fbd91e76d7029078cb42 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:12:55 +0100 Subject: [PATCH 109/281] feat: Implement getting AnyGeneralPurpose timer with priorities --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 112 +++++++++++++------ 1 file changed, 77 insertions(+), 35 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ce0c7086d..d18bb05ca 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -9,6 +9,9 @@ #include "stm32h7xx_hal_tim.h" +// NOTE: only works for static arrays +#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) + extern TIM_HandleTypeDef htim1; extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; @@ -150,7 +153,8 @@ class TimerDomain { } } - static consteval bool check_timer(Config *cfg, const Entry req, uint16_t timer_idx, int reqidx) { + // Do any compile time checks needed for the timers... + static consteval bool check_timer(Config *cfg, const Entry req, int reqidx) { if(req.period == 0) { ErrorInRequestN("Error: In request reqidx: period must be greater than 0 (>0)", reqidx); return false; @@ -174,18 +178,18 @@ class TimerDomain { } } - if(timer_idx == 12 || timer_idx == 13) { + if(req.request == Basic1 || req.request == Basic2) { // basic timers cfg->kind = TimerDomain::Kind::Basic; - } else if(timer_idx == 14 || timer_idx == 15) { + } else if(req.request == Advanced1 || req.request == Advanced2) { // advanced timers cfg->kind = TimerDomain::Kind::Advanced; } else { - if(timer_idx >= 0 && timer_idx <= 5) { + if(cfg->timer_idx >= 0 && cfg->timer_idx <= 5) { // general purpose timers 1 - } else if(timer_idx >= 6 && timer_idx <= 8) { + } else if(cfg->timer_idx >= 6 && cfg->timer_idx <= 8) { // general purpose timers 2 - } else if(timer_idx >= 9 && timer_idx <= 11) { + } else if(cfg->timer_idx >= 9 && cfg->timer_idx <= 11) { // general purpose timers 3 } else { ErrorInRequestN("Unknown timer idx in reqidx", reqidx); @@ -218,6 +222,38 @@ class TimerDomain { } } + Config DoTimer(const Entry request, uint8_t reqint, int reqidx, const char *name_too_long_msg) { + Config cfg; + if(request.name.length() == 0) { + // "Timer" + tostring(reqint) + cfg.name[0] = 'T'; + cfg.name[1] = 'i'; + cfg.name[2] = 'm'; + cfg.name[3] = 'e'; + cfg.name[4] = 'r'; + cfg.name[5] = (reqint/10) + '0'; + cfg.name[6] = (reqint%10) + '0'; + cfg.name[7] = '\0'; + } else { + if(request.name.length() >= sizeof(cfg.name)) { + ErrorInRequestN(name_too_long_msg, reqidx); + } + for(int si = 0; si < request.name.length(); si++) { + cfg.name[si] = request.name[si]; + } + cfg.name[request.name.length()] = '\0'; + } + cfg.timer_idx = TimerDomain.idxmap[reqint]; + cfg.prescaler = request.prescaler; + cfg.period = request.period; + cfg.deadtime = request.deadtime; + cfg.polarity = request.polarity; + cfg.negated_polarity = request.negated_polarity; + + check_timer(&cfg, request, i); + return cfg; + } + enum Kind : uint8_t { Basic, GeneralPurpose, @@ -349,46 +385,52 @@ class TimerDomain { if(usedTimer[reqint]) { ErrorInRequestN("Error: Timer already used. Error in request i", i); } + usedTimer[reqint] = true; - Config cfg; - if(requests[i].name[0] == '\0') { - // "Timer" + tostring(reqint) - cfg.name[0] = 'T'; - cfg.name[1] = 'i'; - cfg.name[2] = 'm'; - cfg.name[3] = 'e'; - cfg.name[4] = 'r'; - cfg.name[5] = (reqint/10) + '0'; - cfg.name[6] = (reqint%10) + '0'; - } else { - if(requests[i].name.length() >= sizeof(cfg.name)) { - ErrorInRequestN("Error: Timer name too large, max = 7 (sizeof cfg.name - 1). In request i", i); - } - for(int si = 0; si < requests[i].name.length(); si++) { - cfg.name[si] = requests[i].name[si]; - } - cfg.name[requests[i].name.length()] = '\0'; - } - cfg.timer_idx = TimerDomain.idxmap[reqint]; - cfg.prescaler = requests[i].prescaler; - cfg.period = requests[i].period; - cfg.deadtime = requests[i].deadtime; - cfg.polarity = requests[i].polarity; - cfg.negated_polarity = requests[i].negated_polarity; - + Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; - // unordered remove + // unordered remove (remaining requests is ) count_remaining_requests--; remaining_requests[i] = remaining_requests[count_remaining_requests]; } } - // Now do AnyGeneralPurpose + // 32 bit timers, very important for scheduler + uint8_t bits32_timers[] = {2, 5, 23, 24}; + // can use any CountingMode (32 bit timers can also but they are higher priority) + uint8_t up_down_updown_timers[] = {3, 4}; + // 16 bit timers + uint8_t bits16_timers[] = {12, 13, 14, 15, 16, 17}; + uint8_t remaining_timers[15] = {0}; + uint8_t count_remaining_timers = 0; + + for(int i = 0; i < ARRAY_LENGTH(bits16_timers); i++) { + if(!used_timers[bits16_timers[i]]) + remaining_timers[count_remaining_timers++] = bits16_timers[i]; + } + + for(int i = 0; i < ARRAY_LENGTH(up_down_updown_timers); i++) { + if(!used_timers[up_down_updown_timers[i]]) + remaining_timers[count_remaining_timers++] = up_down_updown_timers[i]; + } + + for(int i = 0; i < ARRAY_LENGTH(bits32_timers); i++) { + if(!used_timers[bits32_timers[i]]) + remaining_timers[count_remaining_timers++] = bits32_timers[i]; + } + + if(count_remaining_requests > count_remaining_timers) { + compile_error("This should not happen"); + } + for(int i = 0; i < count_remaining_requests; i++) { const Entry &e = requests[remaining_requests[i]]; if(e.request == AnyGeneralPurpose) { - // TODO: Find first general purpose timer that isn't used + uint8_t reqint = remaining_timers[i]; + // NOTE: I don't want to do an ordered remove so this has the real index + Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 (sizeof cfg.name - 1)"); + cfgs[cfg_idx++] = cfg; } } From 12c7aad43966a421ad5512220eea9af2d1eaca79 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:16:30 +0100 Subject: [PATCH 110/281] Make prettier --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index d18bb05ca..494982445 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -29,23 +29,22 @@ extern TIM_HandleTypeDef htim23; extern TIM_HandleTypeDef htim24; /* Tim1 & Tim8 are advanced-control timers - * their ARR & prescaler are 16bit - * they have up to 6 independent channels for: - * - input capture (not channel 5 or 6) - * - output capture - * - PWM generation - * - One-pulse mode output - */ + * their ARR & prescaler are 16bit + * they have up to 6 independent channels for: + * - input capture (not channel 5 or 6) + * - output capture + * - PWM generation + * - One-pulse mode output + */ /* Timers {TIM2, TIM5, TIM23, TIM24} are the only 32-bit counter resolution timers, the rest are 16-bit */ /* Timers 2, 3, 4, 5, 23, 24 are general-purpose timers - * Timers 12, 13, 14 are also general-purpose timers (but separate in the ref manual) - * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) - */ + * Timers 12, 13, 14 are also general-purpose timers (but separate in the ref manual) + * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) + */ -/* Tim6 & Tim7 are basic timers */ -/* basic timer features: +/* Tim6 & Tim7 are basic timers. Features: - 16-bit ARR upcounter - 16-bit PSC - Synchronization circuit to trigger the DAC @@ -485,7 +484,7 @@ class TimerDomain { } // leftover from old TimerPeripheral, maybe this was useful? - inline uint32_t get_prescaler() { + inline uint16_t get_prescaler() { return tim->PSC; } inline uint32_t get_period() { From 4a5ee25efe66e0a2c67966a0a4ace8e76dd902af Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:17:26 +0100 Subject: [PATCH 111/281] Remove leftovers --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 494982445..9b73e31a2 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -586,26 +586,6 @@ class TimerDomain { } } } - - // Leftover from last iteration of the design of NewTimerPeripheral, will cleanup soon -private: - enum TIM_CAPABILITIES { - Basic_Start = 0, - Basic_End = 1, - - General_Start = 2, - General_End = 13, - - Advanced_Start = 14, - Advanced_End = 15, - - Count_Cap = 16, - }; - - // This should use __builtin_ffs() - 1 to get the index of the next - static uint32_t free_bmp = 0xFFFF'FFFF; - - static void (*callbacks)()[16]; }; From 3c14d8fa3aad66dfd1c5c526516a7c16e4b56021 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:18:24 +0100 Subject: [PATCH 112/281] Remove outdated comment --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 9b73e31a2..51528d8b2 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -501,7 +501,6 @@ class TimerDomain { uint16_t timer_idx; void (*callback)(TimerDomain::Instance); - // NOTE: Need counter_enable() here for configure(), kept counter_disable() for consistency if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { // advanced specific functions } From fee4058a2e8b4568b0db844883ae42e90773bb45 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:19:12 +0100 Subject: [PATCH 113/281] fix: Finish the comment :) --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 51528d8b2..1adf0b6db 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -389,7 +389,7 @@ class TimerDomain { Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; - // unordered remove (remaining requests is ) + // unordered remove (remaining requests is not used here so these are ordered) count_remaining_requests--; remaining_requests[i] = remaining_requests[count_remaining_requests]; } From 6e36b748bf9b09c528041f0777813417796a558a Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 17:46:37 +0100 Subject: [PATCH 114/281] Clean up error messages, add comment --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 1adf0b6db..fcbd4d1ae 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -311,7 +311,7 @@ class TimerDomain { }; struct Entry { - string name; + string name; /* max length = 7 */ TimerRequest request; ST_LIB::GPIODomain::Pin *pin; TimerDomain::CountingMode counting_mode; @@ -386,7 +386,7 @@ class TimerDomain { } usedTimer[reqint] = true; - Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 (sizeof cfg.name - 1)"); + Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -428,7 +428,7 @@ class TimerDomain { if(e.request == AnyGeneralPurpose) { uint8_t reqint = remaining_timers[i]; // NOTE: I don't want to do an ordered remove so this has the real index - Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 (sizeof cfg.name - 1)"); + Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; } } From 930db1def4cde36bbef70889c600fa71c9407c5b Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 18:22:45 +0100 Subject: [PATCH 115/281] temp: setup to try to compile template_project --- Inc/HALAL/HALAL.hpp | 5 ++-- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 5 ++++ Inc/ST-LIB.hpp | 9 ++++++- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 28 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 Src/HALAL/Models/TimerDomain/TimerDomain.cpp diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index bc896cce3..72ce03845 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -20,7 +20,8 @@ #include "HALAL/Services/PWM/PhasedPWM/PhasedPWM.hpp" #include "HALAL/Services/PWM/DualPhasedPWM/DualPhasedPWM.hpp" -#include "HALAL/Services/Time/Time.hpp" +//#include "HALAL/Services/Time/Time.hpp" +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" #include "HALAL/Services/Time/Scheduler.hpp" #include "HALAL/Services/Time/RTC.hpp" @@ -40,7 +41,7 @@ #include "HALAL/Services/InfoWarning/InfoWarning.hpp" #include "HALAL/Services/Watchdog/Watchdog.hpp" -#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" +//#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" #include "HALAL/Models/BoardID/BoardID.hpp" #include "HALAL/Models/Concepts/Concepts.hpp" diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index fcbd4d1ae..a4f1e96f0 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -509,6 +509,10 @@ class TimerDomain { // general purpose and advanced functions } + template + void set_mode(); + +#if 0 /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ template inline void set_mode(void) { @@ -535,6 +539,7 @@ class TimerDomain { MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); } } +#endif }; template struct Init { diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 32fb54814..07c14d1a4 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -70,7 +70,8 @@ template struct BuildCtx { } }; -using DomainsCtx = BuildCtx; template struct Board { @@ -88,12 +89,14 @@ template struct Board { static consteval auto build() { 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(); // ... struct ConfigBundle { std::array gpio_cfgs; + std::array tim_cfgs; std::array dout_cfgs; std::array din_cfgs; // ... @@ -102,6 +105,8 @@ template struct Board { return ConfigBundle{ .gpio_cfgs = GPIODomain::template build(ctx.template span()), + .tim_cfgs = + TimerDomain::template build(ctx.template span()), .dout_cfgs = DigitalOutputDomain::template build( ctx.template span()), .din_cfgs = DigitalInputDomain::template build( @@ -114,11 +119,13 @@ template struct Board { static void init() { 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(); // ... 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, diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp new file mode 100644 index 000000000..b79e2834f --- /dev/null +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -0,0 +1,28 @@ +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" + +template +TimerDomain::TimerWrapper::set_mode() { + constexpr uint8_t reqint = static_cast(dev.e.request); + if constexpr (!(reqint == 1 || reqint == 8 || + reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || + reqint == 3 || reqint == 4)) + { + compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + return; + } + + if constexpr (mode == CounterMode::UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == CounterMode::DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } +} + From 4b7aa2e949d8db1ed95cd54328fa1873ff7c7b27 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 20:31:24 +0100 Subject: [PATCH 116/281] Try to get TimerDomain to compile --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 434 ++++++++++--------- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 27 +- 2 files changed, 226 insertions(+), 235 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index a4f1e96f0..03022efbc 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -9,6 +9,10 @@ #include "stm32h7xx_hal_tim.h" +#include +#include +#include + // NOTE: only works for static arrays #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) @@ -16,6 +20,7 @@ extern TIM_HandleTypeDef htim1; extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; extern TIM_HandleTypeDef htim4; +extern TIM_HandleTypeDef htim5; extern TIM_HandleTypeDef htim6; extern TIM_HandleTypeDef htim7; extern TIM_HandleTypeDef htim8; @@ -73,37 +78,112 @@ extern TIM_HandleTypeDef htim24; - Supports incremental (quadrature) encoder and Hall-sensor circuitry for positioning purposes - Trigger input for external clock or cycle-by-cycle current management */ -class TimerDomain { - static constexpr std::array create_idxmap() { - std::array result{}; - - // invalid timers that don't exist - result[0] = -1; - result[9] = -1; result[10] = -1; result[11] = -1; - result[18] = -1; result[19] = -1; result[20] = -1; result[21] = -1; result[22] = -1; - - // general-purpose timers - result[2] = 0; result[3] = 1; result[4] = 2; - result[5] = 3; result[23] = 4; result[24] = 5; +constexpr std::array create_idxmap() { + std::array result{}; + + // invalid timers that don't exist + result[0] = -1; + result[9] = -1; result[10] = -1; result[11] = -1; + result[18] = -1; result[19] = -1; result[20] = -1; result[21] = -1; result[22] = -1; + + // general-purpose timers + result[2] = 0; result[3] = 1; result[4] = 2; + result[5] = 3; result[23] = 4; result[24] = 5; + + // more general-purpose timers + result[12] = 6; result[13] = 7; result[14] = 8; + + // more general-purpose timers + result[15] = 9; result[16] = 10; result[17] = 11; + + // basic timers + result[6] = 12; result[7] = 13; + + // advanced control timers + result[1] = 14; result[8] = 15; + + return result; +} + +struct TimerDomain { + // There are 16 timers + static constexpr std::size_t max_instances = 16; - // more general-purpose timers - result[12] = 6; result[13] = 7; result[14] = 8; + /* The number corresponds with the timer nº */ + enum TimerRequest : uint8_t { + Advanced1 = 1, + Advanced2 = 8, - // more general-purpose timers - result[15] = 9; result[16] = 10; result[17] = 11; + AnyGeneralPurpose = 0xFF, + GeneralPurpose1 = 2, + GeneralPurpose2 = 3, + GeneralPurpose3 = 4, + GeneralPurpose4 = 5, + GeneralPurpose5 = 23, + GeneralPurpose6 = 24, - // basic timers - result[6] = 12; result[7] = 13; + GeneralPurpose7 = 12, + GeneralPurpose8 = 13, + GeneralPurpose9 = 14, - // advanced control timers - result[1] = 14; result[8] = 15; - - return result; - } + GeneralPurpose10 = 15, + GeneralPurpose11 = 16, + GeneralPurpose12 = 17, + + Basic1 = 6, + Basic2 = 7, + }; + + enum CountingMode : uint8_t { + UP = 0, + DOWN = 1, + /* center-aligned = counter counts up and down alternatively */ + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting down */ + CENTER_ALIGNED_INTERRUPT_DOWN = 2, + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting up */ + CENTER_ALIGNED_INTERRUPT_UP = 3, + /* both up and down */ + CENTER_ALIGNED_INTERRUPT_BOTH = 4, + }; + enum Kind : uint8_t { + Basic, + GeneralPurpose, + Advanced, + }; + + struct Entry { + std::string name; /* max length = 7 */ + TimerRequest request; + ST_LIB::GPIODomain::Pin *pin; + TimerDomain::CountingMode counting_mode; + uint16_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + + struct Config { + char name[8]; /* "Timerxx\0" */ + TimerDomain::Kind kind; + uint16_t timer_idx; + ST_LIB::GPIODomain::Pin *asociated_pin; + TimerDomain::CountingMode counting_mode; + uint32_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + +private: + static void I_Need_To_Compile_TimerDomain_CPP(void); static constexpr std::array idxmap = create_idxmap(); - static const TIM_HandleTypeDef *hal_handles[16] = { + static constexpr TIM_HandleTypeDef *hal_handles[16] = { // general purpose timers &htim2, &htim3, &htim4, &htim5, &htim23, &htim24, &htim12, &htim13, &htim14, @@ -116,7 +196,7 @@ class TimerDomain { &htim1, &htim8 }; - static const TIM_TypeDef *cmsis_timers[16] = { + static constexpr TIM_TypeDef *cmsis_timers[16] = { // general purpose timers TIM2, TIM3, TIM4, TIM5, TIM23, TIM24, TIM12, TIM13, TIM14, @@ -129,29 +209,61 @@ class TimerDomain { TIM1, TIM8 }; - static inline void rcc_enable_timer(TIM_TypeDef *tim) { - switch(tim) { - case TIM2: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM2EN); break; - case TIM3: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM3EN); break; - case TIM4: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM4EN); break; - case TIM5: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM5EN); break; - case TIM6: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM6EN); break; - case TIM7: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM7EN); break; - case TIM12: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM12EN); break; - case TIM13: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM13EN); break; - case TIM14: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM14EN); break; - - case TIM24: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM24EN); break; - case TIM23: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM23EN); break; - - case TIM17: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM17EN); break; - case TIM16: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM16EN); break; - case TIM15: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM15EN); break; - case TIM8: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM8EN); break; - case TIM1: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM1EN); break; + /* to show the error with an index */ + static consteval void ErrorInRequestN(const char *str, int n) + { + switch(n) { + case 0: ST_LIB::compile_error(str); + case 1: ST_LIB::compile_error(str); + case 2: ST_LIB::compile_error(str); + case 3: ST_LIB::compile_error(str); + case 4: ST_LIB::compile_error(str); + case 5: ST_LIB::compile_error(str); + case 6: ST_LIB::compile_error(str); + case 7: ST_LIB::compile_error(str); + case 8: ST_LIB::compile_error(str); + case 9: ST_LIB::compile_error(str); + case 10: ST_LIB::compile_error(str); + case 11: ST_LIB::compile_error(str); + case 12: ST_LIB::compile_error(str); + case 13: ST_LIB::compile_error(str); + case 14: ST_LIB::compile_error(str); + case 15: ST_LIB::compile_error(str); } } + static inline void rcc_enable_timer(TIM_TypeDef *tim) { +#define TimerXList \ + X(TIM2, APB1LENR) \ + X(TIM3, APB1LENR) \ + X(TIM4, APB1LENR) \ + X(TIM5, APB1LENR) \ + X(TIM6, APB1LENR) \ + X(TIM7, APB1LENR) \ + X(TIM12, APB1LENR) \ + X(TIM13, APB1LENR) \ + X(TIM14, APB1LENR) \ + \ + X(TIM23, APB1HENR) \ + X(TIM24, APB1HENR) \ + \ + X(TIM1, APB2ENR) \ + X(TIM8, APB2ENR) \ + X(TIM15, APB2ENR) \ + X(TIM16, APB2ENR) \ + X(TIM17, APB2ENR) +#define X(t, b) \ + else if(tim == t) { SET_BIT(RCC->b, RCC_##b##_##t##EN); } + + if(false) {} + TimerXList + else { + ErrorHandler("Invalid timer given to rcc_enable_timer"); + } + +#undef X + } + // Do any compile time checks needed for the timers... static consteval bool check_timer(Config *cfg, const Entry req, int reqidx) { if(req.period == 0) { @@ -198,82 +310,38 @@ class TimerDomain { } } - /* to show the error with an index */ - static consteval ErrorInRequestN(char *str, int n) - { - switch(n) { - case 0: compile_error(str); - case 1: compile_error(str); - case 2: compile_error(str); - case 3: compile_error(str); - case 4: compile_error(str); - case 5: compile_error(str); - case 6: compile_error(str); - case 7: compile_error(str); - case 8: compile_error(str); - case 9: compile_error(str); - case 10: compile_error(str); - case 11: compile_error(str); - case 12: compile_error(str); - case 13: compile_error(str); - case 14: compile_error(str); - case 15: compile_error(str); - } - } - - Config DoTimer(const Entry request, uint8_t reqint, int reqidx, const char *name_too_long_msg) { - Config cfg; - if(request.name.length() == 0) { - // "Timer" + tostring(reqint) - cfg.name[0] = 'T'; - cfg.name[1] = 'i'; - cfg.name[2] = 'm'; - cfg.name[3] = 'e'; - cfg.name[4] = 'r'; - cfg.name[5] = (reqint/10) + '0'; - cfg.name[6] = (reqint%10) + '0'; - cfg.name[7] = '\0'; - } else { - if(request.name.length() >= sizeof(cfg.name)) { - ErrorInRequestN(name_too_long_msg, reqidx); - } - for(int si = 0; si < request.name.length(); si++) { - cfg.name[si] = request.name[si]; - } - cfg.name[request.name.length()] = '\0'; - } - cfg.timer_idx = TimerDomain.idxmap[reqint]; - cfg.prescaler = request.prescaler; - cfg.period = request.period; - cfg.deadtime = request.deadtime; - cfg.polarity = request.polarity; - cfg.negated_polarity = request.negated_polarity; - - check_timer(&cfg, request, i); - return cfg; - } - - enum Kind : uint8_t { - Basic, - GeneralPurpose, - Advanced, - }; + #define DoTimer(request, reqint, reqidx, name_too_long_msg) do{ \ + Config cfg; \ + if((request).name.length() == 0) { \ + /* "Timer" + tostring(reqint) */ \ + cfg.name[0] = 'T'; \ + cfg.name[1] = 'i'; \ + cfg.name[2] = 'm'; \ + cfg.name[3] = 'e'; \ + cfg.name[4] = 'r'; \ + cfg.name[5] = (reqint/10) + '0'; \ + cfg.name[6] = (reqint%10) + '0'; \ + cfg.name[7] = '\0'; \ + } else { \ + if((request).name.length() >= sizeof(cfg.name)) { \ + ErrorInRequestN(name_too_long_msg, reqidx); \ + } \ + for(std::size_t si = 0; si < (request).name.length(); si++) { \ + cfg.name[si] = (request).name[si]; \ + } \ + cfg.name[(request).name.length()] = '\0'; \ + } \ + cfg.timer_idx = TimerDomain::idxmap[reqint]; \ + cfg.prescaler = (request).prescaler; \ + cfg.period = (request).period; \ + cfg.deadtime = (request).deadtime; \ + cfg.polarity = (request).polarity; \ + cfg.negated_polarity = (request).negated_polarity; \ + \ + check_timer(&cfg, request, i); \ + } while(0) public: - enum CountingMode : uint8_t { - UP = 0, - DOWN = 1, - /* center-aligned = counter counts up and down alternatively */ - /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are - set only when the counter is counting down */ - CENTER_ALIGNED_INTERRUPT_DOWN = 2, - /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are - set only when the counter is counting up */ - CENTER_ALIGNED_INTERRUPT_UP = 3, - /* both up and down */ - CENTER_ALIGNED_INTERRUPT_BOTH = 4, - }; - enum PWM_MODE : uint8_t { NORMAL = 0, PHASED = 1, @@ -285,48 +353,11 @@ class TimerDomain { PWM_MODE mode; }; - /* The number corresponds with the timer nº */ - enum TimerRequest : uint8_t { - Advanced1 = 1, - Advanced2 = 8, - - AnyGeneralPurpose = 0xFF, - GeneralPurpose1 = 2, - GeneralPurpose2 = 3, - GeneralPurpose3 = 4, - GeneralPurpose4 = 5, - GeneralPurpose5 = 23, - GeneralPurpose6 = 24, - - GeneralPurpose7 = 12, - GeneralPurpose8 = 13, - GeneralPurpose9 = 14, - - GeneralPurpose10 = 15, - GeneralPurpose11 = 16, - GeneralPurpose12 = 17, - - Basic1 = 6, - Basic2 = 7, - }; - - struct Entry { - string name; /* max length = 7 */ - TimerRequest request; - ST_LIB::GPIODomain::Pin *pin; - TimerDomain::CountingMode counting_mode; - uint16_t prescaler; - uint32_t period; - uint32_t deadtime; - uint32_t polarity; - uint32_t negated_polarity; - }; - struct Device { using domain = TimerDomain; Entry e; - consteval Device(string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, + consteval Device(std::string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) : @@ -338,34 +369,18 @@ class TimerDomain { } }; - // There are 16 timers - static constexpr std::size_t max_instances = 16; - - struct Config { - char name[8]; /* "Timerxx\0" */ - TimerDomain::Kind kind; - uint16_t timer_idx; - ST_LIB::GPIODomain::Pin *asociated_pin; - TimerDomain::CountingMode counting_mode; - uint32_t prescaler; - uint32_t period; - uint32_t deadtime; - uint32_t polarity; - uint32_t negated_polarity; - }; - template - static consteval std::array build(span requests) { - array cfgs{}; + static consteval std::array build(std::span requests) { + std::array cfgs{}; uint16_t cfg_idx = 0; - bool usedTimer[25] = {0}; + bool used_timers[25] = {0}; if(requests.size() > max_instances) { throw "too many Timer requests, there are only 16 timers"; } int remaining_requests[max_instances] = {}; - std::size_t count_remaining_requests = requsts.size(); + std::size_t count_remaining_requests = requests.size(); for(int i = 0; i < requests.size(); i++) remaining_requests[i] = i; for(int i = 0; i < requests.size(); i++) { @@ -381,12 +396,13 @@ class TimerDomain { for(std::size_t i = 0; i < N; i++) { uint8_t reqint = static_cast(requests[i].request); if(reqint != static_cast(TimerRequest::AnyGeneralPurpose)) { - if(usedTimer[reqint]) { + if(used_timers[reqint]) { ErrorInRequestN("Error: Timer already used. Error in request i", i); } - usedTimer[reqint] = true; + used_timers[reqint] = true; - Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); + Config cfg; + DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -420,7 +436,7 @@ class TimerDomain { } if(count_remaining_requests > count_remaining_timers) { - compile_error("This should not happen"); + ST_LIB::compile_error("This should not happen"); } for(int i = 0; i < count_remaining_requests; i++) { @@ -428,7 +444,8 @@ class TimerDomain { if(e.request == AnyGeneralPurpose) { uint8_t reqint = remaining_timers[i]; // NOTE: I don't want to do an ordered remove so this has the real index - Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); + Config cfg; + DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; } } @@ -439,6 +456,16 @@ class TimerDomain { // Runtime object struct Instance { template friend struct TimerWrapper; + }; + + template + struct TimerWrapper { + TIM_TypeDef *tim; + TIM_HandleTypeDef *hal_tim; + char name[8]; + const TimerDomain::Kind kind; + uint16_t timer_idx; + void (*callback)(TimerDomain::Instance); inline void counter_enable() { SET_BIT(tim->CR1, TIM_CR1_CEN); @@ -490,17 +517,8 @@ class TimerDomain { inline uint32_t get_period() { return tim->ARR; } - }; - - template - struct TimerWrapper { - TIM_TypeDef *tim; - TIM_HandleTypeDef *hal_tim; - char name[8]; - const TimerDomain::Kind kind; - uint16_t timer_idx; - void (*callback)(TimerDomain::Instance); +#if 0 if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { // advanced specific functions } @@ -508,38 +526,34 @@ class TimerDomain { if constexpr (dev.e.request != TimerRequest::Basic1 && dev.e.request != TimerRequest::Basic2) { // general purpose and advanced functions } +#endif - template - void set_mode(); - -#if 0 /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ - template + template inline void set_mode(void) { constexpr uint8_t reqint = static_cast(dev.e.request); if constexpr (!(reqint == 1 || reqint == 8 || reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || reqint == 3 || reqint == 4)) { - compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + ST_LIB::compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); return; } - if constexpr (mode == CounterMode::UP) { + if constexpr (mode == CountingMode::UP) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == CounterMode::DOWN) { + } else if constexpr (mode == CountingMode::DOWN) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); } } -#endif }; template struct Init { @@ -563,15 +577,15 @@ class TimerDomain { tim->PSC = e.prescaler; tim->ARR = e.period; - if constexpr (e.counting_mode == CounterMode::UP) { + if(e.counting_mode == CountingMode::UP) { CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (e.counting_mode == CounterMode::DOWN) { + } else if(e.counting_mode == CountingMode::DOWN) { SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + } 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)); } @@ -589,7 +603,7 @@ class TimerDomain { }; } } - } + }; }; diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index b79e2834f..c23c50df2 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -1,28 +1,5 @@ #include "HALAL/Models/TimerDomain/TimerDomain.hpp" -template -TimerDomain::TimerWrapper::set_mode() { - constexpr uint8_t reqint = static_cast(dev.e.request); - if constexpr (!(reqint == 1 || reqint == 8 || - reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || - reqint == 3 || reqint == 4)) - { - compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); - return; - } - - if constexpr (mode == CounterMode::UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); - CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == CounterMode::DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); - SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); - } +void TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { + // Need to compile this file so I keep this symbol here } - From bfd2f4a4052246831fdf4b7b902cfef082428b9b Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 09:43:31 +0100 Subject: [PATCH 117/281] Add initial implementation of scheduler --- Inc/HALAL/Services/Time/Scheduler.hpp | 96 ++++++++ Src/HALAL/Services/Time/Scheduler.cpp | 309 ++++++++++++++++++++++++++ 2 files changed, 405 insertions(+) create mode 100644 Inc/HALAL/Services/Time/Scheduler.hpp create mode 100644 Src/HALAL/Services/Time/Scheduler.cpp diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp new file mode 100644 index 000000000..e300094cf --- /dev/null +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -0,0 +1,96 @@ +/* + * Scheduler.hpp + * + * Created on: 17 nov. 2025 + * Author: Victor (coauthor Stephan) + */ +#pragma once + +#include "stm32h7xx_ll_tim.h" + +#include +#include +#include + +/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto + * Cambiar el SCHEDULER_TIMER_IDX si es mejor usar otro timer que no sea TIM2 + */ +#ifndef SCHEDULER_TIMER_IDX +# define SCHEDULER_TIMER_IDX 2 +#endif + +#define glue_(a,b) a ## b +#define glue(a,b) glue_(a,b) +#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) + +// Used to reserve a TimerPeripheral +#include "stm32h7xx_hal_tim.h" +#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) +extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; + +struct Scheduler { + using callback_t = void (*)(); + static constexpr uint32_t INVALID_ID = 0xFFu; + + static void start(); + static void update(); + static inline uint64_t get_global_tick(); + + static inline uint8_t register_task(uint32_t period_us, callback_t func) { + if(period_us == 0) [[unlikely]] period_us = 1; + return register_task(period_us, func, true); + } + static bool unregister_task(uint8_t id); + + static inline uint8_t set_timeout(uint32_t microseconds, callback_t func) { + if(microseconds == 0) [[unlikely]] microseconds = 1; + return register_task(microseconds, func, false); + } + static inline void cancel_timeout(uint8_t id) { unregister_task(id); } + + // static void global_timer_callback(); + + // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise + static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + static void on_timer_update(); + +private: + struct Task { + uint64_t next_fire_us{0}; + callback_t callback{}; + uint32_t period_us{0}; + bool repeating{false}; + }; + + static constexpr std::size_t kMaxTasks = 16; + static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); + static constexpr uint32_t kBaseClockHz = 1'000'000u; + + static std::array tasks_; + static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); + static uint64_t sorted_task_ids_; + + static std::size_t active_task_count_; + static uint32_t ready_bitmap_; + static uint32_t used_bitmap_; + static uint64_t global_tick_us_; + static uint64_t long_wait_remaining_us_; + static uint64_t current_interval_us_; + + static inline uint8_t allocate_slot(); + static inline void release_slot(uint8_t id); + static void insert_sorted(uint8_t id); + static void remove_sorted(uint8_t id); + static void schedule_next_interval(); + static inline void configure_timer_for_interval(uint64_t microseconds); + static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); + + // helpers + static inline uint8_t get_at(std::size_t logical); + static inline void set_at(std::size_t logical, uint8_t id); + static inline void pop_front(); + static inline uint8_t front_id(); + + static inline void global_timer_disable(); + static inline void global_timer_enable(); +}; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp new file mode 100644 index 000000000..0e1faf054 --- /dev/null +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -0,0 +1,309 @@ +/* + * Scheduler.hpp + * + * Created on: 17 nov. 2025 + * Author: Victor (coauthor Stephan) + */ +#include "HALAL/Services/Time/Scheduler.hpp" + +// This is needed to register a TimerPeripheral +#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" + +#include +#include + +/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ +#define SCHEDULER_RCC_TIMER_ENABLE glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) +#define SCHEDULER_GLOBAL_TIMER_IRQn glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) +#define SCHEDULER_GLOBAL_TIMER_CALLBACK() extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) +#define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) + +/* bit field insert + * (internally) mask = ((1UL << width) - 1) << pos + * dest = (dest & ~mask) | (source & mask) + * With the condition that pos and width are immediate values + * ref: https://developer.arm.com/documentation/dui0646/c/The-Cortex-M7-Instruction-Set/Bit-field-instructions/BFC-and-BFI + */ +#define BFI(dest, source, pos, width) \ + __asm__( \ + "bfi %0, %1, %2, %3" \ + : "+r" (dest) \ + : "r" (source), "i" (pos), "i" (width) \ + ) + +namespace { +constexpr uint64_t kMaxIntervalUs = + static_cast(std::numeric_limits::max()) + 1ULL; +} + +std::array Scheduler::tasks_{}; +uint64_t Scheduler::sorted_task_ids_ = 0; +std::size_t Scheduler::active_task_count_{0}; + +uint32_t Scheduler::ready_bitmap_{0}; +uint32_t Scheduler::used_bitmap_{0}; +uint64_t Scheduler::global_tick_us_{0}; +uint64_t Scheduler::long_wait_remaining_us_{0}; +uint64_t Scheduler::current_interval_us_{0}; + +inline uint8_t Scheduler::get_at(std::size_t idx) { + uint32_t shift = idx*4; + return (sorted_task_ids_ & (0x0F << shift)) >> shift; +} +inline void Scheduler::set_at(std::size_t idx, uint8_t id) { + uint32_t shift = idx*4; + uint64_t clearmask = ~(0xFF << shift); + Scheduler::sorted_task_ids_ = (sorted_task_ids_ & clearmask) | (id << shift); + // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though +} +inline uint8_t Scheduler::front_id() { + return Scheduler::get_at(0); +} +inline void Scheduler::pop_front() { + // O(1) remove of logical index 0 + Scheduler::active_task_count_--; + Scheduler::sorted_task_ids_ <<= 4; +} + +// ---------------------------- + +inline void Scheduler::global_timer_disable() { + LL_TIM_DisableCounter(Scheduler_global_timer); + //Scheduler_global_timer->CR1 &= ~TIM_CR1_CEN; +} +inline void Scheduler::global_timer_enable() { + LL_TIM_EnableCounter(Scheduler_global_timer); + //Scheduler_global_timer->CR1 |= TIM_CR1_CEN; +} + +// ---------------------------- + +void Scheduler::start() { + static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); + + const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; + static_assert(prescaler < 0xFFFF'FFFF, "Prescaler is 16 bit, so it must be in that range"); + + // Register a TimerPeripheral so it's not used anywhere else + // hopefully we can move to something better than TimerPeripheral + TimerPeripheral::InitData init_data(TimerPeripheral::BASE); + TimerPeripheral perif_reserve(&SCHEDULER_HAL_TIM, std::move(init_data), (std::string)"timer2"); + + RCC->APB1LENR |= SCHEDULER_RCC_TIMER_ENABLE; + Scheduler_global_timer->PSC = (uint16_t)prescaler; + Scheduler_global_timer->ARR = 0; + Scheduler_global_timer->DIER |= LL_TIM_DIER_UIE; + Scheduler_global_timer->CR1 = LL_TIM_CLOCKDIVISION_DIV1 | (Scheduler_global_timer->CR1 & ~TIM_CR1_CKD); + // I think this should be cleared at startup. TODO: Look it up in ref manual + // LL_TIM_DisableExternalClock(Scheduler_global_timer); + // |-> does this: Scheduler_global_timer->SMCR &= ~TIM_SMCR_ECE; /* Disable external clock */ + + active_task_count_ = 0; + Scheduler_global_timer->CNT = 0; /* Clear counter value */ + + NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); + Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ + // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() + // Scheduler::global_timer_enable(); + + Scheduler::schedule_next_interval(); +} + +SCHEDULER_GLOBAL_TIMER_CALLBACK() { + Scheduler_global_timer->SR &= ~TIM_SR_UIF; + Scheduler::on_timer_update(); +} + +void Scheduler::update() { + while(ready_bitmap_ != 0u) { + uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); + ready_bitmap_ &= ~(1u << bit_index); // Clear the bit + Task& task = tasks_[bit_index]; + task.callback(); + if (!task.repeating) [[unlikely]] { + release_slot(static_cast(bit_index)); + } + } +} + +inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } + +// void Scheduler::global_timer_callback() { on_timer_update(); } + +inline uint8_t Scheduler::allocate_slot() { + int idx = __builtin_clz(Scheduler::ready_bitmap_); + if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] + return static_cast(Scheduler::INVALID_ID); + return static_cast(idx); +} + +inline void Scheduler::release_slot(uint8_t id) { + // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert + if(id >= kMaxTasks) return; + tasks_[id] = Task{}; + uint32_t clearmask = ~(1u << id); + ready_bitmap_ &= clearmask; + used_bitmap_ &= clearmask; +} + +void Scheduler::insert_sorted(uint8_t id) { + Task& task = tasks_[id]; + + // binary search on logical range [0, active_task_count_) + std::size_t left = 0; + std::size_t right = active_task_count_; + while (left < right) { + std::size_t mid = left + ((right - left) / 2); + const Task& mid_task = tasks_[Scheduler::get_at(mid)]; + if (mid_task.next_fire_us <= task.next_fire_us) { + left = mid + 1; + } else { + right = mid; + } + } + const std::size_t pos = left; + + uint32_t lo = (uint32_t)sorted_task_ids_; + uint32_t hi = (uint32_t)(sorted_task_ids_ >> 32); + + uint32_t shift = (pos & 7) << 2; + uint32_t id_shifted = id << shift; + + uint32_t mask = (1UL << shift) - 1; + uint32_t inv_mask = ~mask; //Hole mask + + //Calculate both posibilities + uint32_t lo_modified = ((lo & inv_mask) << 4) | (lo & mask) | id_shifted; + uint32_t hi_modified = ((hi & inv_mask) << 4) | (hi & mask) | id_shifted; + + uint32_t hi_spilled = (hi << 4) | (lo >> 28); + + if (pos >= 8) { //this can be done without branching + hi = hi_modified; + // lo remains unchanged + } else { + hi = hi_spilled; + lo = lo_modified; + } + + sorted_task_ids_ = ((uint64_t)hi << 32) | lo; + ++active_task_count_; +} + +void Scheduler::remove_sorted(uint8_t id) { + uint64_t nibble_lsb = 0x1111'1111'1111'1111ULL; + + // pattern = nibble_lsb * id (para obtener id en cada nibble) + uint32_t pattern_32 = id + (id << 4); + pattern_32 = pattern_32 + (pattern_32 << 8); + pattern_32 = pattern_32 + (pattern_32 << 16); + uint64_t pattern = pattern_32; + BFI(((uint32_t*)&pattern)[1], pattern, 0, 32); + + // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids + uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; + + //https://stackoverflow.com/questions/79058066/finding-position-of-zero-nibble-in-64-bits + //https://stackoverflow.com/questions/59480527/fast-lookup-of-a-null-nibble-in-a-64-bit-unsigned + uint64_t nibble_msb = 0x8888'8888'8888'8888ULL; + uint64_t matches = (diff - nibble_lsb) & (~diff & nibble_msb); + + if(matches == 0) [[unlikely]] return; // not found + + uint32_t pos_msb = __builtin_ctzll(matches); + uint32_t pos_lsb = pos_msb - 3; + + // convert pos_lsb to 0x0..0_FFF_0..0 + uint64_t mask = (1ULL << pos_lsb) - 1; + + // Remove element (lower part | higher pushing nibble out of mask) + Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); + Scheduler::active_task_count_--; +} + +void Scheduler::schedule_next_interval() { + if (active_task_count_ == 0) [[unlikely]] { + Scheduler::global_timer_disable(); + current_interval_us_ = 0; + long_wait_remaining_us_ = 0; + return; + } + + Scheduler::global_timer_enable(); + uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] + Task& next_task = tasks_[next_id]; + uint64_t delta = (next_task.next_fire_us > global_tick_us_) + ? (next_task.next_fire_us - global_tick_us_ + 1ULL) : 1ULL; // +1 to ensure we don't miss, means loss in accuracy + + //TODO: Adding 1 accumulates drift over time analyze if acceptable, it can be solved by adding an extra if + + if (delta > kMaxIntervalUs) [[unlikely]] { + current_interval_us_ = kMaxIntervalUs; + long_wait_remaining_us_ = delta - kMaxIntervalUs; + } else { + current_interval_us_ = delta; + long_wait_remaining_us_ = 0; + } + + configure_timer_for_interval(current_interval_us_); +} + +inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { + // NOTE(vic): disabling the timer _might_ be necessary to prevent the timer from firing in the middle of configuring it, highly unlikely since it has a period of at least 1 microsecond + const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; + Scheduler_global_timer->PSC = prescaler; + Scheduler_global_timer->ARR = static_cast(microseconds - 1u); + Scheduler_global_timer->CNT = 0; + Scheduler::global_timer_enable(); +} + +void Scheduler::on_timer_update() { + global_tick_us_ += current_interval_us_; + + if (long_wait_remaining_us_ > 0) [[unlikely]] { + uint64_t next_chunk = std::min(long_wait_remaining_us_, kMaxIntervalUs); + long_wait_remaining_us_ -= next_chunk; + current_interval_us_ = next_chunk; + configure_timer_for_interval(current_interval_us_); + return; + } + + uint8_t candidate_id = Scheduler::front_id(); + Task& task = tasks_[candidate_id]; + pop_front(); + ready_bitmap_ |= (1u << candidate_id); // mark task as ready + + if (task.repeating) [[likely]] { + task.next_fire_us = global_tick_us_ + task.period_us; + insert_sorted(candidate_id); + } + + schedule_next_interval(); +} + +uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repeating) { + if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + + uint8_t slot = allocate_slot(); + if(slot == Scheduler::INVALID_ID) return slot; + + Task& task = tasks_[slot]; + task.callback = func; + task.period_us = period_us; + task.repeating = repeating; + task.next_fire_us = global_tick_us_ + period_us; + + insert_sorted(slot); + schedule_next_interval(); + return slot; +} + +bool Scheduler::unregister_task(uint8_t id) { + if (id >= kMaxTasks) return false; + if (!(used_bitmap_ & (1UL << id))) return false; + + remove_sorted(id); + release_slot(id); + schedule_next_interval(); + return true; +} From 638005340d9d95c6ea897ef555e0d1024d2ce005 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:02:02 +0100 Subject: [PATCH 118/281] Try to fix -Wuninitialized warning --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 0e1faf054..6224b4cba 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -198,7 +198,7 @@ void Scheduler::remove_sorted(uint8_t id) { pattern_32 = pattern_32 + (pattern_32 << 8); pattern_32 = pattern_32 + (pattern_32 << 16); uint64_t pattern = pattern_32; - BFI(((uint32_t*)&pattern)[1], pattern, 0, 32); + BFI(((uint32_t*)&pattern)[1], pattern_32, 0, 32); // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; From 046c80c31e53f7d0d9653f3ca2e69923102e98a7 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:04:53 +0100 Subject: [PATCH 119/281] Try to remove Wuninitialized warning temporarily --- Src/HALAL/Services/Time/Scheduler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 6224b4cba..a8684f536 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -193,6 +193,9 @@ void Scheduler::insert_sorted(uint8_t id) { void Scheduler::remove_sorted(uint8_t id) { uint64_t nibble_lsb = 0x1111'1111'1111'1111ULL; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wuninitialized" + // pattern = nibble_lsb * id (para obtener id en cada nibble) uint32_t pattern_32 = id + (id << 4); pattern_32 = pattern_32 + (pattern_32 << 8); @@ -200,6 +203,8 @@ void Scheduler::remove_sorted(uint8_t id) { uint64_t pattern = pattern_32; BFI(((uint32_t*)&pattern)[1], pattern_32, 0, 32); +#pragma GCC diagnostic pop + // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; From 49ac6d3e6310dffe10ae59d1b72a0d65d8096824 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:27:25 +0100 Subject: [PATCH 120/281] Remove unnecessary clear of task element --- Src/HALAL/Services/Time/Scheduler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index a8684f536..aad615cb1 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -140,7 +140,6 @@ inline uint8_t Scheduler::allocate_slot() { inline void Scheduler::release_slot(uint8_t id) { // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert if(id >= kMaxTasks) return; - tasks_[id] = Task{}; uint32_t clearmask = ~(1u << id); ready_bitmap_ &= clearmask; used_bitmap_ &= clearmask; From 05584992c23f23daab6c0fac84d5b6cf1667d9bc Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 10:41:29 +0100 Subject: [PATCH 121/281] fix: Readability and todo for validation --- Src/HALAL/Services/Time/Scheduler.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index aad615cb1..1167fcfab 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -13,9 +13,13 @@ #include /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ -#define SCHEDULER_RCC_TIMER_ENABLE glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) -#define SCHEDULER_GLOBAL_TIMER_IRQn glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) -#define SCHEDULER_GLOBAL_TIMER_CALLBACK() extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) +#define SCHEDULER_RCC_TIMER_ENABLE \ + glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) +#define SCHEDULER_GLOBAL_TIMER_IRQn \ + glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) +#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ + extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) + #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) /* bit field insert @@ -254,8 +258,7 @@ void Scheduler::schedule_next_interval() { inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { // NOTE(vic): disabling the timer _might_ be necessary to prevent the timer from firing in the middle of configuring it, highly unlikely since it has a period of at least 1 microsecond - const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; - Scheduler_global_timer->PSC = prescaler; + // TODO(vic): Validation: check arr is set correctly here: https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#pullrequestreview-3529132356 Scheduler_global_timer->ARR = static_cast(microseconds - 1u); Scheduler_global_timer->CNT = 0; Scheduler::global_timer_enable(); From 053cd1ba274c2514091c43c5ad4d0baf980567a4 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 12:15:29 +0100 Subject: [PATCH 122/281] fix: allocate_slot --- Src/HALAL/Services/Time/Scheduler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 1167fcfab..98400893d 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -135,7 +135,11 @@ inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } // void Scheduler::global_timer_callback() { on_timer_update(); } inline uint8_t Scheduler::allocate_slot() { - int idx = __builtin_clz(Scheduler::ready_bitmap_); + /* https://developer.arm.com/documentation/dui0204/j/arm-and-thumb-instructions/general-data-processing-instructions/clz + * clz(0) = 32 -> 32 - clz(0) = 0 + * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks + */ + uint32_t idx = 32 - __builtin_clz(Scheduler::used_bitmap_); if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); return static_cast(idx); From 85b038af461b543aaf0701194d44cbe4565c950a Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 12:36:56 +0100 Subject: [PATCH 123/281] Add explenation of sorted_task_ids_, static_assert for the bitmaps --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 ++ Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index e300094cf..9b3643a17 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -68,9 +68,11 @@ struct Scheduler { static std::array tasks_; static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); + /* sorted_task_ids_ is a sorted queue with 4bits for each id in the scheduler's current ids */ static uint64_t sorted_task_ids_; static std::size_t active_task_count_; + static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); static uint32_t ready_bitmap_; static uint32_t used_bitmap_; static uint64_t global_tick_us_; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 98400893d..9cda60689 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -139,7 +139,7 @@ inline uint8_t Scheduler::allocate_slot() { * clz(0) = 32 -> 32 - clz(0) = 0 * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks */ - uint32_t idx = 32 - __builtin_clz(Scheduler::used_bitmap_); + uint32_t idx = 32 - __builtin_clz(~Scheduler::used_bitmap_); if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); return static_cast(idx); From 0c8cc067ef34664a614f173b5c259855481ebabd Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 12:44:10 +0100 Subject: [PATCH 124/281] Remove long_wait_remaining_us_ --- Inc/HALAL/Services/Time/Scheduler.hpp | 1 - Src/HALAL/Services/Time/Scheduler.cpp | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 9b3643a17..0951ca96b 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -76,7 +76,6 @@ struct Scheduler { static uint32_t ready_bitmap_; static uint32_t used_bitmap_; static uint64_t global_tick_us_; - static uint64_t long_wait_remaining_us_; static uint64_t current_interval_us_; static inline uint8_t allocate_slot(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9cda60689..20b77d734 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -47,7 +47,6 @@ std::size_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::used_bitmap_{0}; uint64_t Scheduler::global_tick_us_{0}; -uint64_t Scheduler::long_wait_remaining_us_{0}; uint64_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(std::size_t idx) { @@ -237,7 +236,6 @@ void Scheduler::schedule_next_interval() { if (active_task_count_ == 0) [[unlikely]] { Scheduler::global_timer_disable(); current_interval_us_ = 0; - long_wait_remaining_us_ = 0; return; } @@ -251,10 +249,8 @@ void Scheduler::schedule_next_interval() { if (delta > kMaxIntervalUs) [[unlikely]] { current_interval_us_ = kMaxIntervalUs; - long_wait_remaining_us_ = delta - kMaxIntervalUs; } else { current_interval_us_ = delta; - long_wait_remaining_us_ = 0; } configure_timer_for_interval(current_interval_us_); @@ -271,14 +267,6 @@ inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { void Scheduler::on_timer_update() { global_tick_us_ += current_interval_us_; - if (long_wait_remaining_us_ > 0) [[unlikely]] { - uint64_t next_chunk = std::min(long_wait_remaining_us_, kMaxIntervalUs); - long_wait_remaining_us_ -= next_chunk; - current_interval_us_ = next_chunk; - configure_timer_for_interval(current_interval_us_); - return; - } - uint8_t candidate_id = Scheduler::front_id(); Task& task = tasks_[candidate_id]; pop_front(); From e3c3d137b336d00b07a44996c5c58e8be2af9f13 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:45:38 +0100 Subject: [PATCH 125/281] fix: better get_at --- Inc/HALAL/Services/Time/Scheduler.hpp | 4 ++-- Src/HALAL/Services/Time/Scheduler.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 0951ca96b..d080bb181 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -87,8 +87,8 @@ struct Scheduler { static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); // helpers - static inline uint8_t get_at(std::size_t logical); - static inline void set_at(std::size_t logical, uint8_t id); + static inline uint8_t get_at(uint8_t idx); + static inline void set_at(uint8_t idx, uint8_t id); static inline void pop_front(); static inline uint8_t front_id(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 20b77d734..54beea194 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -49,11 +49,12 @@ uint32_t Scheduler::used_bitmap_{0}; uint64_t Scheduler::global_tick_us_{0}; uint64_t Scheduler::current_interval_us_{0}; -inline uint8_t Scheduler::get_at(std::size_t idx) { - uint32_t shift = idx*4; - return (sorted_task_ids_ & (0x0F << shift)) >> shift; +inline uint8_t Scheduler::get_at(uint8_t idx) { + int word_idx = idx > 7; + uint32_t shift = (idx & 7) << 2; + return (((uint32_t*)sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; } -inline void Scheduler::set_at(std::size_t idx, uint8_t id) { +inline void Scheduler::set_at(uint8_t idx, uint8_t id) { uint32_t shift = idx*4; uint64_t clearmask = ~(0xFF << shift); Scheduler::sorted_task_ids_ = (sorted_task_ids_ & clearmask) | (id << shift); From 446cc359e7c999ba045b75879888f3cd6a76ea2f Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:46:51 +0100 Subject: [PATCH 126/281] fix: better front_id Compiler would've probably optimized it but it's better to make it explicit --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 54beea194..9fda2ae1f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -61,7 +61,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return Scheduler::get_at(0); + return ((uint32_t*)sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From c8ba1931a2c2094dc4dffe4dc358f63fc551906f Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:51:12 +0100 Subject: [PATCH 127/281] fix: endianness in pop_front --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9fda2ae1f..72a91ecca 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -66,7 +66,7 @@ inline uint8_t Scheduler::front_id() { inline void Scheduler::pop_front() { // O(1) remove of logical index 0 Scheduler::active_task_count_--; - Scheduler::sorted_task_ids_ <<= 4; + Scheduler::sorted_task_ids_ >>= 4; } // ---------------------------- From 6a372e48581a7c7b02be74652b3ec26ed9e67ca7 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 15:56:27 +0100 Subject: [PATCH 128/281] Added unlikely to release_slot conditional --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 72a91ecca..57856ebfd 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -147,7 +147,7 @@ inline uint8_t Scheduler::allocate_slot() { inline void Scheduler::release_slot(uint8_t id) { // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert - if(id >= kMaxTasks) return; + if(id >= kMaxTasks) [[unlikely]] return; uint32_t clearmask = ~(1u << id); ready_bitmap_ &= clearmask; used_bitmap_ &= clearmask; From 96b7fc27a4c81430f25f8d5ad989c87e4680ea7e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:03:16 +0100 Subject: [PATCH 129/281] fix: Correct comment explenation --- Src/HALAL/Services/Time/Scheduler.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 57856ebfd..5a25321e4 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -222,10 +222,12 @@ void Scheduler::remove_sorted(uint8_t id) { if(matches == 0) [[unlikely]] return; // not found + /* split the bm in two 0x0000...FFFFFF where removal index is placed + * then invert to keep both sides that surround the discarded index + */ uint32_t pos_msb = __builtin_ctzll(matches); uint32_t pos_lsb = pos_msb - 3; - // convert pos_lsb to 0x0..0_FFF_0..0 uint64_t mask = (1ULL << pos_lsb) - 1; // Remove element (lower part | higher pushing nibble out of mask) From b428cbafe742be26c0ff932ea1ad027a24f8e56d Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:09:18 +0100 Subject: [PATCH 130/281] No bit field insert, it annoyed me --- Src/HALAL/Services/Time/Scheduler.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 5a25321e4..63431ba85 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -22,19 +22,6 @@ #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) -/* bit field insert - * (internally) mask = ((1UL << width) - 1) << pos - * dest = (dest & ~mask) | (source & mask) - * With the condition that pos and width are immediate values - * ref: https://developer.arm.com/documentation/dui0646/c/The-Cortex-M7-Instruction-Set/Bit-field-instructions/BFC-and-BFI - */ -#define BFI(dest, source, pos, width) \ - __asm__( \ - "bfi %0, %1, %2, %3" \ - : "+r" (dest) \ - : "r" (source), "i" (pos), "i" (width) \ - ) - namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; @@ -208,7 +195,7 @@ void Scheduler::remove_sorted(uint8_t id) { pattern_32 = pattern_32 + (pattern_32 << 8); pattern_32 = pattern_32 + (pattern_32 << 16); uint64_t pattern = pattern_32; - BFI(((uint32_t*)&pattern)[1], pattern_32, 0, 32); + ((uint32_t*)&pattern)[1] = pattern_32; #pragma GCC diagnostic pop From 4ae1dbb0afbfd8a0bdd55d6a7d500b8126568b93 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:09:59 +0100 Subject: [PATCH 131/281] No more diagnostic ignore --- Src/HALAL/Services/Time/Scheduler.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 63431ba85..a9044789e 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -187,9 +187,6 @@ void Scheduler::insert_sorted(uint8_t id) { void Scheduler::remove_sorted(uint8_t id) { uint64_t nibble_lsb = 0x1111'1111'1111'1111ULL; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wuninitialized" - // pattern = nibble_lsb * id (para obtener id en cada nibble) uint32_t pattern_32 = id + (id << 4); pattern_32 = pattern_32 + (pattern_32 << 8); @@ -197,8 +194,6 @@ void Scheduler::remove_sorted(uint8_t id) { uint64_t pattern = pattern_32; ((uint32_t*)&pattern)[1] = pattern_32; -#pragma GCC diagnostic pop - // diff becomes 0xid..id_0_id..id where 0 is the nibble where id is in sorted_task_ids uint64_t diff = Scheduler::sorted_task_ids_ ^ pattern; From 9d11dd351b606d782b131ad968b2daaa8eb35af8 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:13:51 +0100 Subject: [PATCH 132/281] fix: loss in accuracy by not adding 1: https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#discussion_r2581260196 --- Src/HALAL/Services/Time/Scheduler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index a9044789e..ff58b1c09 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -227,10 +227,8 @@ void Scheduler::schedule_next_interval() { Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; - uint64_t delta = (next_task.next_fire_us > global_tick_us_) - ? (next_task.next_fire_us - global_tick_us_ + 1ULL) : 1ULL; // +1 to ensure we don't miss, means loss in accuracy - - //TODO: Adding 1 accumulates drift over time analyze if acceptable, it can be solved by adding an extra if + uint64_t delta = (next_task.next_fire_us > (global_tick_us_ - 1ULL)) + ? (next_task.next_fire_us - global_tick_us_) : 1ULL; if (delta > kMaxIntervalUs) [[unlikely]] { current_interval_us_ = kMaxIntervalUs; From 89c5873fff5597177e05ded62feed57c757e2216 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 16:19:19 +0100 Subject: [PATCH 133/281] fix: Moved active_task_count_ modification --- Src/HALAL/Services/Time/Scheduler.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ff58b1c09..ebd0b0578 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -89,7 +89,6 @@ void Scheduler::start() { // LL_TIM_DisableExternalClock(Scheduler_global_timer); // |-> does this: Scheduler_global_timer->SMCR &= ~TIM_SMCR_ECE; /* Disable external clock */ - active_task_count_ = 0; Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); @@ -129,6 +128,7 @@ inline uint8_t Scheduler::allocate_slot() { uint32_t idx = 32 - __builtin_clz(~Scheduler::used_bitmap_); if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + Scheduler::active_task_count_++; return static_cast(idx); } @@ -138,6 +138,7 @@ inline void Scheduler::release_slot(uint8_t id) { uint32_t clearmask = ~(1u << id); ready_bitmap_ &= clearmask; used_bitmap_ &= clearmask; + Scheduler::active_task_count_--; } void Scheduler::insert_sorted(uint8_t id) { @@ -181,7 +182,6 @@ void Scheduler::insert_sorted(uint8_t id) { } sorted_task_ids_ = ((uint64_t)hi << 32) | lo; - ++active_task_count_; } void Scheduler::remove_sorted(uint8_t id) { @@ -214,7 +214,6 @@ void Scheduler::remove_sorted(uint8_t id) { // Remove element (lower part | higher pushing nibble out of mask) Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); - Scheduler::active_task_count_--; } void Scheduler::schedule_next_interval() { From 5c2a17cb4b0459826a3832591608ea3457a0911c Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 2 Dec 2025 20:05:13 +0100 Subject: [PATCH 134/281] Actually set used_bitmap_ in allocate_slot --- Src/HALAL/Services/Time/Scheduler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ebd0b0578..7b056a2eb 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -129,6 +129,7 @@ inline uint8_t Scheduler::allocate_slot() { if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); Scheduler::active_task_count_++; + Scheduler::used_bitmap_ |= (1UL << idx); return static_cast(idx); } From 7d65723290a31c9f691d9e1aa9f3336a617a8724 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 4 Dec 2025 15:44:45 +0100 Subject: [PATCH 135/281] fix: used_bitmap_ -> free_bitmap_ --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index d080bb181..ef3f976fc 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -74,7 +74,7 @@ struct Scheduler { static std::size_t active_task_count_; static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); static uint32_t ready_bitmap_; - static uint32_t used_bitmap_; + static uint32_t free_bitmap_; static uint64_t global_tick_us_; static uint64_t current_interval_us_; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 7b056a2eb..a457612ed 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -32,7 +32,7 @@ uint64_t Scheduler::sorted_task_ids_ = 0; std::size_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; -uint32_t Scheduler::used_bitmap_{0}; +uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; uint64_t Scheduler::current_interval_us_{0}; @@ -125,20 +125,19 @@ inline uint8_t Scheduler::allocate_slot() { * clz(0) = 32 -> 32 - clz(0) = 0 * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks */ - uint32_t idx = 32 - __builtin_clz(~Scheduler::used_bitmap_); + uint32_t idx = __builtin_ffs(~Scheduler::free_bitmap_) - 1; if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); Scheduler::active_task_count_++; - Scheduler::used_bitmap_ |= (1UL << idx); + Scheduler::free_bitmap_ &= ~(1UL << idx); return static_cast(idx); } inline void Scheduler::release_slot(uint8_t id) { // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert if(id >= kMaxTasks) [[unlikely]] return; - uint32_t clearmask = ~(1u << id); - ready_bitmap_ &= clearmask; - used_bitmap_ &= clearmask; + ready_bitmap_ &= ~(1u << id); + free_bitmap_ |= (1u << id); Scheduler::active_task_count_--; } @@ -282,7 +281,7 @@ uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repea bool Scheduler::unregister_task(uint8_t id) { if (id >= kMaxTasks) return false; - if (!(used_bitmap_ & (1UL << id))) return false; + if (free_bitmap_ & (1UL << id)) return false; remove_sorted(id); release_slot(id); From 34306845a8f7b05406a1dc4d83b905fd43378b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:26:55 +0100 Subject: [PATCH 136/281] only include sources when cross-compiling --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 037e4f115..2e7054310 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,6 +222,9 @@ add_library(${STLIB_LIBRARY} STATIC $<$,$>:${STLIB_HIGH_CPP_ETH}> $<$:${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp> + + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/HALAL/Services/Time/Scheduler.cpp> + ) set_target_properties(${STLIB_LIBRARY} PROPERTIES From 57f1c158fedf031668546f46e04b637968e19146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:27:34 +0100 Subject: [PATCH 137/281] modify CMakeLists inside Tests --- Tests/CMakeLists.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 4ee61c8b6..5f2759919 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,9 +1,11 @@ +cmake_minimum_required(VERSION 3.14) if(DEFINED STLIB_NAME_SUFFIX) set(STLIB_TEST_EXECUTABLE st-lib-${STLIB_NAME_SUFFIX}-test) else() set(STLIB_TEST_EXECUTABLE st-lib-test) endif() +project( ${STLIB_TEST_EXECUTABLE}) include(FetchContent) FetchContent_Declare( googletest @@ -14,7 +16,7 @@ FetchContent_MakeAvailable(googletest) message(STATUS "Generating test executable for ST-LIB") add_executable(${STLIB_TEST_EXECUTABLE} - # ${CMAKE_CURRENT_LIST_DIR}/Time/scheduler_test.cpp + ${CMAKE_CURRENT_LIST_DIR}/Time/scheduler_test.cpp ) set_target_properties(${STLIB_TEST_EXECUTABLE} PROPERTIES @@ -29,6 +31,10 @@ target_link_libraries( GTest::gtest_main ${STLIB_LIBRARY} ) +if(MINGW OR CYGWIN) + # Force static linking of libgcc and libstdc++ to avoid DLL version mismatches + target_link_options(${STLIB_TEST_EXECUTABLE} PRIVATE -static) +endif() if(MINGW OR CYGWIN) target_link_options(${STLIB_TEST_EXECUTABLE} PRIVATE -static) From 920536fc2f52363bf6c72f9dc0f8c4ff9e3dc74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:28:29 +0100 Subject: [PATCH 138/281] feat: use ugly ifdef guards for host testing purposes --- Inc/HALAL/Services/Time/Scheduler.hpp | 38 +++++++++------ Src/HALAL/Services/Time/Scheduler.cpp | 67 +++++++++++++++++++-------- 2 files changed, 72 insertions(+), 33 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index ef3f976fc..f33f567ad 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -6,8 +6,9 @@ */ #pragma once -#include "stm32h7xx_ll_tim.h" - +#ifndef TESTING_ENV + #include "stm32h7xx_ll_tim.h" +#endif #include #include #include @@ -19,15 +20,22 @@ # define SCHEDULER_TIMER_IDX 2 #endif -#define glue_(a,b) a ## b -#define glue(a,b) glue_(a,b) -#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) - -// Used to reserve a TimerPeripheral -#include "stm32h7xx_hal_tim.h" -#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) -extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; - +#ifndef TESTING_ENV + #define glue_(a,b) a ## b + #define glue(a,b) glue_(a,b) + #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) + + // Used to reserve a TimerPeripheral + #include "stm32h7xx_hal_tim.h" + #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) + extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; +#else +struct FakeTimer{ + int64_t CNT; + int64_t ARR; +}; +extern FakeTimer* Scheduler_global_timer; +#endif struct Scheduler { using callback_t = void (*)(); static constexpr uint32_t INVALID_ID = 0xFFu; @@ -51,10 +59,14 @@ struct Scheduler { // static void global_timer_callback(); // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise - static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + #ifndef TESTING_ENV + static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + #endif static void on_timer_update(); -private: +#ifndef TESTING_ENV + private: +#endif struct Task { uint64_t next_fire_us{0}; callback_t callback{}; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index a457612ed..e72e6bf69 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -6,22 +6,26 @@ */ #include "HALAL/Services/Time/Scheduler.hpp" -// This is needed to register a TimerPeripheral -#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" - +#ifndef TESTING_ENV + // This is needed to register a TimerPeripheral + #include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" +#else + #include +#endif #include #include -/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ -#define SCHEDULER_RCC_TIMER_ENABLE \ - glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) -#define SCHEDULER_GLOBAL_TIMER_IRQn \ - glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) -#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ - extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) - -#define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) - +#ifndef TESTING_ENV + /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ + #define SCHEDULER_RCC_TIMER_ENABLE \ + glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) + #define SCHEDULER_GLOBAL_TIMER_IRQn \ + glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) + #define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ + extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) + + #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) +#endif namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; @@ -59,21 +63,35 @@ inline void Scheduler::pop_front() { // ---------------------------- inline void Scheduler::global_timer_disable() { +#ifndef TESTING_ENV LL_TIM_DisableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 &= ~TIM_CR1_CEN; +#endif } inline void Scheduler::global_timer_enable() { +#ifndef TESTING_ENV LL_TIM_EnableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 |= TIM_CR1_CEN; +#endif } // ---------------------------- - +FakeTimer* Scheduler_global_timer; +void TimerCallback(); +void simulate_ticking(){ + Scheduler_global_timer->CNT++; + if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ + TimerCallback(); + std::cout<<"overflow\n"; + Scheduler_global_timer->CNT = -1; + } +} void Scheduler::start() { static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; static_assert(prescaler < 0xFFFF'FFFF, "Prescaler is 16 bit, so it must be in that range"); +#ifndef TESTING_ENV // Register a TimerPeripheral so it's not used anywhere else // hopefully we can move to something better than TimerPeripheral @@ -95,15 +113,24 @@ void Scheduler::start() { Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() // Scheduler::global_timer_enable(); - +#else + active_task_count_ = 0; + Scheduler_global_timer = new FakeTimer(); + Scheduler_global_timer->CNT = 0; + Scheduler_global_timer->ARR = 0; +#endif Scheduler::schedule_next_interval(); } -SCHEDULER_GLOBAL_TIMER_CALLBACK() { - Scheduler_global_timer->SR &= ~TIM_SR_UIF; - Scheduler::on_timer_update(); -} - +#ifndef TESTING_ENV + SCHEDULER_GLOBAL_TIMER_CALLBACK() { + Scheduler_global_timer->SR &= ~TIM_SR_UIF; +#else + void TimerCallback(){ +#endif + + Scheduler::on_timer_update(); + } void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); From 2565412999b564fdd1a2241494d3a87805208ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:28:53 +0100 Subject: [PATCH 139/281] add sample tests for Scheduler --- Tests/Time/scheduler_test.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Tests/Time/scheduler_test.cpp diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp new file mode 100644 index 000000000..45d2fe390 --- /dev/null +++ b/Tests/Time/scheduler_test.cpp @@ -0,0 +1,18 @@ +#include +#include +#include +#include "HALAL/Services/Time/Scheduler.hpp" +int count = 0; +void fake_workload(){ + count++; +} + +TEST(SchedulerTests, UsedBitmap) { + Scheduler::register_task(10,&fake_workload); + EXPECT_EQ(Scheduler::used_bitmap_,1); +} + +TEST(SchedulerTests, TaskRegistration) { + Scheduler::register_task(10,&fake_workload); + EXPECT_EQ(Scheduler::tasks_[0].callback,fake_workload); +} \ No newline at end of file From 9883981809a25edbfff9109fa9c7f236a2bc40aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:39:11 +0100 Subject: [PATCH 140/281] add emulated ticking --- Inc/HALAL/Services/Time/Scheduler.hpp | 13 ++++++++----- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index f33f567ad..75d92c99b 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -30,11 +30,12 @@ #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; #else -struct FakeTimer{ - int64_t CNT; - int64_t ARR; -}; -extern FakeTimer* Scheduler_global_timer; + + struct FakeTimer{ + int64_t CNT; + int64_t ARR; + }; + extern FakeTimer* Scheduler_global_timer; #endif struct Scheduler { using callback_t = void (*)(); @@ -61,6 +62,8 @@ struct Scheduler { // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise #ifndef TESTING_ENV static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; + #else + static void simulate_ticking(); #endif static void on_timer_update(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index e72e6bf69..4537f4feb 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -78,7 +78,7 @@ inline void Scheduler::global_timer_enable() { // ---------------------------- FakeTimer* Scheduler_global_timer; void TimerCallback(); -void simulate_ticking(){ +void Scheduler::simulate_ticking(){ Scheduler_global_timer->CNT++; if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ TimerCallback(); From 152732a2e2f455cc54874de193f37be48fda5a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:39:23 +0100 Subject: [PATCH 141/281] test for execution count --- Tests/Time/scheduler_test.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 45d2fe390..4c3d1ed7a 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -15,4 +15,15 @@ TEST(SchedulerTests, UsedBitmap) { TEST(SchedulerTests, TaskRegistration) { Scheduler::register_task(10,&fake_workload); EXPECT_EQ(Scheduler::tasks_[0].callback,fake_workload); +} + +TEST(SchedulerTests, TaskExecution) { + Scheduler::register_task(10,&fake_workload); + Scheduler::start(); + constexpr int NUM_TICKS = 1'000'000; + for(int i = 0; i < NUM_TICKS; i++){ + Scheduler::simulate_ticking(); + Scheduler::update(); + } + EXPECT_EQ(count,100'000); } \ No newline at end of file From d4cbd83d8047313a20dc4f31aef79989d5ed7154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 22:44:21 +0100 Subject: [PATCH 142/281] fix: CI --- Src/HALAL/Services/Time/Scheduler.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4537f4feb..0c9f55f7f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -76,16 +76,18 @@ inline void Scheduler::global_timer_enable() { } // ---------------------------- -FakeTimer* Scheduler_global_timer; -void TimerCallback(); -void Scheduler::simulate_ticking(){ - Scheduler_global_timer->CNT++; - if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ - TimerCallback(); - std::cout<<"overflow\n"; - Scheduler_global_timer->CNT = -1; +#ifdef TESTING_ENV + FakeTimer* Scheduler_global_timer; + void TimerCallback(); + void Scheduler::simulate_ticking(){ + Scheduler_global_timer->CNT++; + if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ + TimerCallback(); + std::cout<<"overflow\n"; + Scheduler_global_timer->CNT = -1; + } } -} +#endif void Scheduler::start() { static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); From 36595a9c8e7090b8422c93ffe815ee38d01b3f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Tue, 2 Dec 2025 23:25:26 +0100 Subject: [PATCH 143/281] fix: expected result in test case + explanation --- Tests/Time/scheduler_test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 4c3d1ed7a..e090f3dfd 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -21,9 +21,11 @@ TEST(SchedulerTests, TaskExecution) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); constexpr int NUM_TICKS = 1'000'000; - for(int i = 0; i < NUM_TICKS; i++){ + for(int i = 0; i <= NUM_TICKS; i++){ Scheduler::simulate_ticking(); Scheduler::update(); } + // one tick is 1us, and we register a task that executes every 10us + // thus it should execute NUM_TICKS/10 EXPECT_EQ(count,100'000); } \ No newline at end of file From 440be7620779658919129c81d358b7a17b7db393 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:51:41 +0100 Subject: [PATCH 144/281] add compiler specific and CoreMacros --- Inc/MockedDrivers/common.hpp | 106 ++++++++++++++++++++++++ Inc/MockedDrivers/compiler_specific.hpp | 10 +++ 2 files changed, 116 insertions(+) create mode 100644 Inc/MockedDrivers/common.hpp create mode 100644 Inc/MockedDrivers/compiler_specific.hpp diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp new file mode 100644 index 000000000..b7f33c2bc --- /dev/null +++ b/Inc/MockedDrivers/common.hpp @@ -0,0 +1,106 @@ +#pragma once +#include "MockedDrivers/compiler_specific.hpp" +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +typedef enum +{ + RESET = 0, + SET = !RESET +} FlagStatus, ITStatus; + +typedef enum +{ + DISABLE = 0, + ENABLE = !DISABLE +} FunctionalState; +#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) + +typedef enum +{ + SUCCESS = 0, + ERROR = !SUCCESS +} ErrorStatus; + + +#define SET_BIT(REG, BIT) ((REG) |= (BIT)) + +#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) + +#define READ_BIT(REG, BIT) ((REG) & (BIT)) + +#define CLEAR_REG(REG) ((REG) = (0x0)) + +#define WRITE_REG(REG, VAL) ((REG) = (VAL)) + +#define READ_REG(REG) ((REG)) + +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) + +#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) + + +/* Use of CMSIS compiler intrinsics for register exclusive access */ +/* Atomic 32-bit register access macro to set one or several bits */ +#define ATOMIC_SET_BIT(REG, BIT) \ + do { \ + uint32_t val; \ + do { \ + val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \ + } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 32-bit register access macro to clear one or several bits */ +#define ATOMIC_CLEAR_BIT(REG, BIT) \ + do { \ + uint32_t val; \ + do { \ + val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \ + } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 32-bit register access macro to clear and set one or several bits */ +#define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \ + do { \ + uint32_t val; \ + do { \ + val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 16-bit register access macro to set one or several bits */ +#define ATOMIC_SETH_BIT(REG, BIT) \ + do { \ + uint16_t val; \ + do { \ + val = __LDREXH((__IO uint16_t *)&(REG)) | (BIT); \ + } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 16-bit register access macro to clear one or several bits */ +#define ATOMIC_CLEARH_BIT(REG, BIT) \ + do { \ + uint16_t val; \ + do { \ + val = __LDREXH((__IO uint16_t *)&(REG)) & ~(BIT); \ + } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ + } while(0) + +/* Atomic 16-bit register access macro to clear and set one or several bits */ +#define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) \ + do { \ + uint16_t val; \ + do { \ + val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ + } while(0) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp new file mode 100644 index 000000000..fdad61521 --- /dev/null +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -0,0 +1,10 @@ +#pragma once + +/* + +This file contains implementatios or altername names for +ARM GCC compiler that don't work in x86_64 + +*/ +#define __RBIT +#define __CLZ __builtin_clz From 7570cc7665446068f033498550e0361f81c4e331 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:52:29 +0100 Subject: [PATCH 145/281] copy files from LL and CMSIS for TIM Registers --- Inc/MockedDrivers/ll_tim_interface.h | 5215 +++++++++++++++++ .../tim_register_definitions.hpp | 914 +++ 2 files changed, 6129 insertions(+) create mode 100644 Inc/MockedDrivers/ll_tim_interface.h create mode 100644 Inc/MockedDrivers/tim_register_definitions.hpp diff --git a/Inc/MockedDrivers/ll_tim_interface.h b/Inc/MockedDrivers/ll_tim_interface.h new file mode 100644 index 000000000..dfb2587b9 --- /dev/null +++ b/Inc/MockedDrivers/ll_tim_interface.h @@ -0,0 +1,5215 @@ +/** + ****************************************************************************** + * @file stm32h7xx_ll_tim.h + * @author MCD Application Team + * @brief Header file of TIM LL 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_LL_TIM_H +#define __STM32H7xx_LL_TIM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "mocked_ll_tim.hpp" + +#define TIM1 + +/** @addtogroup STM32H7xx_LL_Driver + * @{ + */ + +#if defined (TIM1) || defined (TIM2) || defined (TIM3) || defined (TIM4) || defined (TIM5) || defined (TIM6) || defined (TIM7) || defined (TIM8) || defined (TIM12) || defined (TIM13) || defined (TIM14) || defined (TIM15) || defined (TIM16) || defined (TIM17) || defined (TIM23) || defined (TIM24) + +/** @defgroup TIM_LL TIM + * @{ + */ + +/* Private types -------------------------------------------------------------*/ +/* Private variables ---------------------------------------------------------*/ +/** @defgroup TIM_LL_Private_Variables TIM Private Variables + * @{ + */ +static const uint8_t OFFSET_TAB_CCMRx[] = +{ + 0x00U, /* 0: TIMx_CH1 */ + 0x00U, /* 1: TIMx_CH1N */ + 0x00U, /* 2: TIMx_CH2 */ + 0x00U, /* 3: TIMx_CH2N */ + 0x04U, /* 4: TIMx_CH3 */ + 0x04U, /* 5: TIMx_CH3N */ + 0x04U, /* 6: TIMx_CH4 */ + 0x3CU, /* 7: TIMx_CH5 */ + 0x3CU /* 8: TIMx_CH6 */ +}; + +static const uint8_t SHIFT_TAB_OCxx[] = +{ + 0U, /* 0: OC1M, OC1FE, OC1PE */ + 0U, /* 1: - NA */ + 8U, /* 2: OC2M, OC2FE, OC2PE */ + 0U, /* 3: - NA */ + 0U, /* 4: OC3M, OC3FE, OC3PE */ + 0U, /* 5: - NA */ + 8U, /* 6: OC4M, OC4FE, OC4PE */ + 0U, /* 7: OC5M, OC5FE, OC5PE */ + 8U /* 8: OC6M, OC6FE, OC6PE */ +}; + +static const uint8_t SHIFT_TAB_ICxx[] = +{ + 0U, /* 0: CC1S, IC1PSC, IC1F */ + 0U, /* 1: - NA */ + 8U, /* 2: CC2S, IC2PSC, IC2F */ + 0U, /* 3: - NA */ + 0U, /* 4: CC3S, IC3PSC, IC3F */ + 0U, /* 5: - NA */ + 8U, /* 6: CC4S, IC4PSC, IC4F */ + 0U, /* 7: - NA */ + 0U /* 8: - NA */ +}; + +static const uint8_t SHIFT_TAB_CCxP[] = +{ + 0U, /* 0: CC1P */ + 2U, /* 1: CC1NP */ + 4U, /* 2: CC2P */ + 6U, /* 3: CC2NP */ + 8U, /* 4: CC3P */ + 10U, /* 5: CC3NP */ + 12U, /* 6: CC4P */ + 16U, /* 7: CC5P */ + 20U /* 8: CC6P */ +}; + +static const uint8_t SHIFT_TAB_OISx[] = +{ + 0U, /* 0: OIS1 */ + 1U, /* 1: OIS1N */ + 2U, /* 2: OIS2 */ + 3U, /* 3: OIS2N */ + 4U, /* 4: OIS3 */ + 5U, /* 5: OIS3N */ + 6U, /* 6: OIS4 */ + 8U, /* 7: OIS5 */ + 10U /* 8: OIS6 */ +}; +/** + * @} + */ + +/* Private constants ---------------------------------------------------------*/ +/** @defgroup TIM_LL_Private_Constants TIM Private Constants + * @{ + */ + +#if defined(TIM_BREAK_INPUT_SUPPORT) +/* Defines used for the bit position in the register and perform offsets */ +#define TIM_POSITION_BRK_SOURCE (POSITION_VAL(Source) & 0x1FUL) + +/* Generic bit definitions for TIMx_AF1 register */ +#define TIMx_AF1_BKINP TIM1_AF1_BKINP /*!< BRK BKIN input polarity */ +#define TIMx_AF1_ETRSEL TIM1_AF1_ETRSEL /*!< TIMx ETR source selection */ +#endif /* TIM_BREAK_INPUT_SUPPORT */ + + +/* Mask used to set the TDG[x:0] of the DTG bits of the TIMx_BDTR register */ +#define DT_DELAY_1 ((uint8_t)0x7F) +#define DT_DELAY_2 ((uint8_t)0x3F) +#define DT_DELAY_3 ((uint8_t)0x1F) +#define DT_DELAY_4 ((uint8_t)0x1F) + +/* Mask used to set the DTG[7:5] bits of the DTG bits of the TIMx_BDTR register */ +#define DT_RANGE_1 ((uint8_t)0x00) +#define DT_RANGE_2 ((uint8_t)0x80) +#define DT_RANGE_3 ((uint8_t)0xC0) +#define DT_RANGE_4 ((uint8_t)0xE0) + + +/** + * @} + */ + +/* Private macros ------------------------------------------------------------*/ +/** @defgroup TIM_LL_Private_Macros TIM Private Macros + * @{ + */ +/** @brief Convert channel id into channel index. + * @param __CHANNEL__ This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval none + */ +#define TIM_GET_CHANNEL_INDEX( __CHANNEL__) \ + (((__CHANNEL__) == LL_TIM_CHANNEL_CH1) ? 0U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH1N) ? 1U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH2) ? 2U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH2N) ? 3U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH3) ? 4U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH3N) ? 5U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH4) ? 6U :\ + ((__CHANNEL__) == LL_TIM_CHANNEL_CH5) ? 7U : 8U) + +/** @brief Calculate the deadtime sampling period(in ps). + * @param __TIMCLK__ timer input clock frequency (in Hz). + * @param __CKD__ This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + * @retval none + */ +#define TIM_CALC_DTS(__TIMCLK__, __CKD__) \ + (((__CKD__) == LL_TIM_CLOCKDIVISION_DIV1) ? ((uint64_t)1000000000000U/(__TIMCLK__)) : \ + ((__CKD__) == LL_TIM_CLOCKDIVISION_DIV2) ? ((uint64_t)1000000000000U/((__TIMCLK__) >> 1U)) : \ + ((uint64_t)1000000000000U/((__TIMCLK__) >> 2U))) +/** + * @} + */ + + +/* Exported types ------------------------------------------------------------*/ +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_ES_INIT TIM Exported Init structure + * @{ + */ + +/** + * @brief TIM Time Base configuration structure definition. + */ +typedef struct +{ + uint16_t Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock. + This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetPrescaler().*/ + + uint32_t CounterMode; /*!< Specifies the counter mode. + This parameter can be a value of @ref TIM_LL_EC_COUNTERMODE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetCounterMode().*/ + + uint32_t Autoreload; /*!< Specifies the auto reload value to be loaded into the active + Auto-Reload Register at the next update event. + This parameter must be a number between Min_Data=0x0000 and Max_Data=0xFFFF. + Some timer instances may support 32 bits counters. In that case this parameter must + be a number between 0x0000 and 0xFFFFFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetAutoReload().*/ + + uint32_t ClockDivision; /*!< Specifies the clock division. + This parameter can be a value of @ref TIM_LL_EC_CLOCKDIVISION. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetClockDivision().*/ + + uint32_t RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter + reaches zero, an update event is generated and counting restarts + from the RCR value (N). + This means in PWM mode that (N+1) corresponds to: + - the number of PWM periods in edge-aligned mode + - the number of half PWM period in center-aligned mode + GP timers: this parameter must be a number between Min_Data = 0x00 and + Max_Data = 0xFF. + Advanced timers: this parameter must be a number between Min_Data = 0x0000 and + Max_Data = 0xFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetRepetitionCounter().*/ +} LL_TIM_InitTypeDef; + +/** + * @brief TIM Output Compare configuration structure definition. + */ +typedef struct +{ + uint32_t OCMode; /*!< Specifies the output mode. + This parameter can be a value of @ref TIM_LL_EC_OCMODE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetMode().*/ + + uint32_t OCState; /*!< Specifies the TIM Output Compare state. + This parameter can be a value of @ref TIM_LL_EC_OCSTATE. + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ + + uint32_t OCNState; /*!< Specifies the TIM complementary Output Compare state. + This parameter can be a value of @ref TIM_LL_EC_OCSTATE. + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ + + uint32_t CompareValue; /*!< Specifies the Compare value to be loaded into the Capture Compare Register. + This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. + + This feature can be modified afterwards using unitary function + LL_TIM_OC_SetCompareCHx (x=1..6).*/ + + uint32_t OCPolarity; /*!< Specifies the output polarity. + This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetPolarity().*/ + + uint32_t OCNPolarity; /*!< Specifies the complementary output polarity. + This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetPolarity().*/ + + + uint32_t OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. + This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetIdleState().*/ + + uint32_t OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. + This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetIdleState().*/ +} LL_TIM_OC_InitTypeDef; + +/** + * @brief TIM Input Capture configuration structure definition. + */ + +typedef struct +{ + + uint32_t ICPolarity; /*!< Specifies the active edge of the input signal. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t ICActiveInput; /*!< Specifies the input. + This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetActiveInput().*/ + + uint32_t ICPrescaler; /*!< Specifies the Input Capture Prescaler. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t ICFilter; /*!< Specifies the input capture filter. + This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ +} LL_TIM_IC_InitTypeDef; + + +/** + * @brief TIM Encoder interface configuration structure definition. + */ +typedef struct +{ + uint32_t EncoderMode; /*!< Specifies the encoder resolution (x2 or x4). + This parameter can be a value of @ref TIM_LL_EC_ENCODERMODE. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetEncoderMode().*/ + + uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t IC1ActiveInput; /*!< Specifies the TI1 input source + This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetActiveInput().*/ + + uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t IC1Filter; /*!< Specifies the TI1 input filter. + This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ + + uint32_t IC2Polarity; /*!< Specifies the active edge of TI2 input. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t IC2ActiveInput; /*!< Specifies the TI2 input source + This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetActiveInput().*/ + + uint32_t IC2Prescaler; /*!< Specifies the TI2 input prescaler value. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t IC2Filter; /*!< Specifies the TI2 input filter. + This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ + +} LL_TIM_ENCODER_InitTypeDef; + +/** + * @brief TIM Hall sensor interface configuration structure definition. + */ +typedef struct +{ + + uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. + This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPolarity().*/ + + uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. + Prescaler must be set to get a maximum counter period longer than the + time interval between 2 consecutive changes on the Hall inputs. + This parameter can be a value of @ref TIM_LL_EC_ICPSC. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetPrescaler().*/ + + uint32_t IC1Filter; /*!< Specifies the TI1 input filter. + This parameter can be a value of + @ref TIM_LL_EC_IC_FILTER. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_IC_SetFilter().*/ + + uint32_t CommutationDelay; /*!< Specifies the compare value to be loaded into the Capture Compare Register. + A positive pulse (TRGO event) is generated with a programmable delay every time + a change occurs on the Hall inputs. + This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetCompareCH2().*/ +} LL_TIM_HALLSENSOR_InitTypeDef; + +/** + * @brief BDTR (Break and Dead Time) structure definition + */ +typedef struct +{ + uint32_t OSSRState; /*!< Specifies the Off-State selection used in Run mode. + This parameter can be a value of @ref TIM_LL_EC_OSSR + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetOffStates() + + @note This bit-field cannot be modified as long as LOCK level 2 has been + programmed. */ + + uint32_t OSSIState; /*!< Specifies the Off-State used in Idle state. + This parameter can be a value of @ref TIM_LL_EC_OSSI + + This feature can be modified afterwards using unitary function + @ref LL_TIM_SetOffStates() + + @note This bit-field cannot be modified as long as LOCK level 2 has been + programmed. */ + + uint32_t LockLevel; /*!< Specifies the LOCK level parameters. + This parameter can be a value of @ref TIM_LL_EC_LOCKLEVEL + + @note The LOCK bits can be written only once after the reset. Once the TIMx_BDTR + register has been written, their content is frozen until the next reset.*/ + + uint8_t DeadTime; /*!< Specifies the delay time between the switching-off and the + switching-on of the outputs. + This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF. + + This feature can be modified afterwards using unitary function + @ref LL_TIM_OC_SetDeadTime() + + @note This bit-field can not be modified as long as LOCK level 1, 2 or 3 has been + programmed. */ + + uint16_t BreakState; /*!< Specifies whether the TIM Break input is enabled or not. + This parameter can be a value of @ref TIM_LL_EC_BREAK_ENABLE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_EnableBRK() or @ref LL_TIM_DisableBRK() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t BreakPolarity; /*!< Specifies the TIM Break Input pin polarity. + This parameter can be a value of @ref TIM_LL_EC_BREAK_POLARITY + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t BreakFilter; /*!< Specifies the TIM Break Filter. + This parameter can be a value of @ref TIM_LL_EC_BREAK_FILTER + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#if defined(TIM_BDTR_BKBID) + uint32_t BreakAFMode; /*!< Specifies the alternate function mode of the break input. + This parameter can be a value of @ref TIM_LL_EC_BREAK_AFMODE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_ConfigBRK() + + @note Bidirectional break input is only supported by advanced timers instances. + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#endif /*TIM_BDTR_BKBID */ + uint32_t Break2State; /*!< Specifies whether the TIM Break2 input is enabled or not. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_ENABLE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_EnableBRK2() or @ref LL_TIM_DisableBRK2() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t Break2Polarity; /*!< Specifies the TIM Break2 Input pin polarity. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_POLARITY + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK2() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + + uint32_t Break2Filter; /*!< Specifies the TIM Break2 Filter. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_FILTER + + This feature can be modified afterwards using unitary function + @ref LL_TIM_ConfigBRK2() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#if defined(TIM_BDTR_BKBID) + uint32_t Break2AFMode; /*!< Specifies the alternate function mode of the break2 input. + This parameter can be a value of @ref TIM_LL_EC_BREAK2_AFMODE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_ConfigBRK2() + + @note Bidirectional break input is only supported by advanced timers instances. + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ + +#endif /*TIM_BDTR_BKBID */ + uint32_t AutomaticOutput; /*!< Specifies whether the TIM Automatic Output feature is enabled or not. + This parameter can be a value of @ref TIM_LL_EC_AUTOMATICOUTPUT_ENABLE + + This feature can be modified afterwards using unitary functions + @ref LL_TIM_EnableAutomaticOutput() or @ref LL_TIM_DisableAutomaticOutput() + + @note This bit-field can not be modified as long as LOCK level 1 has been + programmed. */ +} LL_TIM_BDTR_InitTypeDef; + +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/* Exported constants --------------------------------------------------------*/ +/** @defgroup TIM_LL_Exported_Constants TIM Exported Constants + * @{ + */ + +/** @defgroup TIM_LL_EC_GET_FLAG Get Flags Defines + * @brief Flags defines which can be used with LL_TIM_ReadReg function. + * @{ + */ +#define LL_TIM_SR_UIF TIM_SR_UIF /*!< Update interrupt flag */ +#define LL_TIM_SR_CC1IF TIM_SR_CC1IF /*!< Capture/compare 1 interrupt flag */ +#define LL_TIM_SR_CC2IF TIM_SR_CC2IF /*!< Capture/compare 2 interrupt flag */ +#define LL_TIM_SR_CC3IF TIM_SR_CC3IF /*!< Capture/compare 3 interrupt flag */ +#define LL_TIM_SR_CC4IF TIM_SR_CC4IF /*!< Capture/compare 4 interrupt flag */ +#define LL_TIM_SR_CC5IF TIM_SR_CC5IF /*!< Capture/compare 5 interrupt flag */ +#define LL_TIM_SR_CC6IF TIM_SR_CC6IF /*!< Capture/compare 6 interrupt flag */ +#define LL_TIM_SR_COMIF TIM_SR_COMIF /*!< COM interrupt flag */ +#define LL_TIM_SR_TIF TIM_SR_TIF /*!< Trigger interrupt flag */ +#define LL_TIM_SR_BIF TIM_SR_BIF /*!< Break interrupt flag */ +#define LL_TIM_SR_B2IF TIM_SR_B2IF /*!< Second break interrupt flag */ +#define LL_TIM_SR_CC1OF TIM_SR_CC1OF /*!< Capture/Compare 1 overcapture flag */ +#define LL_TIM_SR_CC2OF TIM_SR_CC2OF /*!< Capture/Compare 2 overcapture flag */ +#define LL_TIM_SR_CC3OF TIM_SR_CC3OF /*!< Capture/Compare 3 overcapture flag */ +#define LL_TIM_SR_CC4OF TIM_SR_CC4OF /*!< Capture/Compare 4 overcapture flag */ +#define LL_TIM_SR_SBIF TIM_SR_SBIF /*!< System Break interrupt flag */ +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_EC_BREAK_ENABLE Break Enable + * @{ + */ +#define LL_TIM_BREAK_DISABLE 0x00000000U /*!< Break function disabled */ +#define LL_TIM_BREAK_ENABLE TIM_BDTR_BKE /*!< Break function enabled */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_BREAK2_ENABLE Break2 Enable + * @{ + */ +#define LL_TIM_BREAK2_DISABLE 0x00000000U /*!< Break2 function disabled */ +#define LL_TIM_BREAK2_ENABLE TIM_BDTR_BK2E /*!< Break2 function enabled */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_AUTOMATICOUTPUT_ENABLE Automatic output enable + * @{ + */ +#define LL_TIM_AUTOMATICOUTPUT_DISABLE 0x00000000U /*!< MOE can be set only by software */ +#define LL_TIM_AUTOMATICOUTPUT_ENABLE TIM_BDTR_AOE /*!< MOE can be set by software or automatically at the next update event */ +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** @defgroup TIM_LL_EC_IT IT Defines + * @brief IT defines which can be used with LL_TIM_ReadReg and LL_TIM_WriteReg functions. + * @{ + */ +#define LL_TIM_DIER_UIE TIM_DIER_UIE /*!< Update interrupt enable */ +#define LL_TIM_DIER_CC1IE TIM_DIER_CC1IE /*!< Capture/compare 1 interrupt enable */ +#define LL_TIM_DIER_CC2IE TIM_DIER_CC2IE /*!< Capture/compare 2 interrupt enable */ +#define LL_TIM_DIER_CC3IE TIM_DIER_CC3IE /*!< Capture/compare 3 interrupt enable */ +#define LL_TIM_DIER_CC4IE TIM_DIER_CC4IE /*!< Capture/compare 4 interrupt enable */ +#define LL_TIM_DIER_COMIE TIM_DIER_COMIE /*!< COM interrupt enable */ +#define LL_TIM_DIER_TIE TIM_DIER_TIE /*!< Trigger interrupt enable */ +#define LL_TIM_DIER_BIE TIM_DIER_BIE /*!< Break interrupt enable */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_UPDATESOURCE Update Source + * @{ + */ +#define LL_TIM_UPDATESOURCE_REGULAR 0x00000000U /*!< Counter overflow/underflow, Setting the UG bit or Update generation through the slave mode controller generates an update request */ +#define LL_TIM_UPDATESOURCE_COUNTER TIM_CR1_URS /*!< Only counter overflow/underflow generates an update request */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_ONEPULSEMODE One Pulse Mode + * @{ + */ +#define LL_TIM_ONEPULSEMODE_SINGLE TIM_CR1_OPM /*!< Counter stops counting at the next update event */ +#define LL_TIM_ONEPULSEMODE_REPETITIVE 0x00000000U /*!< Counter is not stopped at update event */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_COUNTERMODE Counter Mode + * @{ + */ +#define LL_TIM_COUNTERMODE_UP 0x00000000U /*!< Counter used as upcounter */ +#define LL_TIM_COUNTERMODE_DOWN TIM_CR1_DIR /*!< Counter used as downcounter */ +#define LL_TIM_COUNTERMODE_CENTER_DOWN TIM_CR1_CMS_0 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting down. */ +#define LL_TIM_COUNTERMODE_CENTER_UP TIM_CR1_CMS_1 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up */ +#define LL_TIM_COUNTERMODE_CENTER_UP_DOWN TIM_CR1_CMS /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up or down. */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CLOCKDIVISION Clock Division + * @{ + */ +#define LL_TIM_CLOCKDIVISION_DIV1 0x00000000U /*!< tDTS=tCK_INT */ +#define LL_TIM_CLOCKDIVISION_DIV2 TIM_CR1_CKD_0 /*!< tDTS=2*tCK_INT */ +#define LL_TIM_CLOCKDIVISION_DIV4 TIM_CR1_CKD_1 /*!< tDTS=4*tCK_INT */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_COUNTERDIRECTION Counter Direction + * @{ + */ +#define LL_TIM_COUNTERDIRECTION_UP 0x00000000U /*!< Timer counter counts up */ +#define LL_TIM_COUNTERDIRECTION_DOWN TIM_CR1_DIR /*!< Timer counter counts down */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CCUPDATESOURCE Capture Compare Update Source + * @{ + */ +#define LL_TIM_CCUPDATESOURCE_COMG_ONLY 0x00000000U /*!< Capture/compare control bits are updated by setting the COMG bit only */ +#define LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI TIM_CR2_CCUS /*!< Capture/compare control bits are updated by setting the COMG bit or when a rising edge occurs on trigger input (TRGI) */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CCDMAREQUEST Capture Compare DMA Request + * @{ + */ +#define LL_TIM_CCDMAREQUEST_CC 0x00000000U /*!< CCx DMA request sent when CCx event occurs */ +#define LL_TIM_CCDMAREQUEST_UPDATE TIM_CR2_CCDS /*!< CCx DMA requests sent when update event occurs */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_LOCKLEVEL Lock Level + * @{ + */ +#define LL_TIM_LOCKLEVEL_OFF 0x00000000U /*!< LOCK OFF - No bit is write protected */ +#define LL_TIM_LOCKLEVEL_1 TIM_BDTR_LOCK_0 /*!< LOCK Level 1 */ +#define LL_TIM_LOCKLEVEL_2 TIM_BDTR_LOCK_1 /*!< LOCK Level 2 */ +#define LL_TIM_LOCKLEVEL_3 TIM_BDTR_LOCK /*!< LOCK Level 3 */ +/** + * @} + */ + +/** @defgroup TIM_LL_EC_CHANNEL Channel + * @{ + */ +#define LL_TIM_CHANNEL_CH1 TIM_CCER_CC1E /*!< Timer input/output channel 1 */ +#define LL_TIM_CHANNEL_CH1N TIM_CCER_CC1NE /*!< Timer complementary output channel 1 */ +#define LL_TIM_CHANNEL_CH2 TIM_CCER_CC2E /*!< Timer input/output channel 2 */ +#define LL_TIM_CHANNEL_CH2N TIM_CCER_CC2NE /*!< Timer complementary output channel 2 */ +#define LL_TIM_CHANNEL_CH3 TIM_CCER_CC3E /*!< Timer input/output channel 3 */ +#define LL_TIM_CHANNEL_CH3N TIM_CCER_CC3NE /*!< Timer complementary output channel 3 */ +#define LL_TIM_CHANNEL_CH4 TIM_CCER_CC4E /*!< Timer input/output channel 4 */ +#define LL_TIM_CHANNEL_CH5 TIM_CCER_CC5E /*!< Timer output channel 5 */ +#define LL_TIM_CHANNEL_CH6 TIM_CCER_CC6E /*!< Timer output channel 6 */ +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_EC_OCSTATE Output Configuration State + * @{ + */ +#define LL_TIM_OCSTATE_DISABLE 0x00000000U /*!< OCx is not active */ +#define LL_TIM_OCSTATE_ENABLE TIM_CCER_CC1E /*!< OCx signal is output on the corresponding output pin */ +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** Legacy definitions for compatibility purpose +@cond 0 + */ +#define LL_TIM_OCMODE_ASSYMETRIC_PWM1 LL_TIM_OCMODE_ASYMMETRIC_PWM1 +#define LL_TIM_OCMODE_ASSYMETRIC_PWM2 LL_TIM_OCMODE_ASYMMETRIC_PWM2 +/** +@endcond + */ + +/** @defgroup TIM_LL_EC_OCMODE Output Configuration Mode + * @{ + */ +#define LL_TIM_OCMODE_FROZEN 0x00000000U /*!TIMx_CCRy else active.*/ +#define LL_TIM_OCMODE_PWM2 (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0) /*!TIMx_CCRy else inactive*/ +#define LL_TIM_OCMODE_RETRIG_OPM1 TIM_CCMR1_OC1M_3 /*!__REG__, (__VALUE__)) + +/** + * @brief Read a value in TIM register. + * @param __INSTANCE__ TIM Instance + * @param __REG__ Register to be read + * @retval Register value + */ +#define LL_TIM_ReadReg(__INSTANCE__, __REG__) READ_REG((__INSTANCE__)->__REG__) +/** + * @} + */ + +/** + * @brief HELPER macro retrieving the UIFCPY flag from the counter value. + * @note ex: @ref __LL_TIM_GETFLAG_UIFCPY (@ref LL_TIM_GetCounter ()); + * @note Relevant only if UIF flag remapping has been enabled (UIF status bit is copied + * to TIMx_CNT register bit 31) + * @param __CNT__ Counter value + * @retval UIF status bit + */ +#define __LL_TIM_GETFLAG_UIFCPY(__CNT__) \ + (READ_BIT((__CNT__), TIM_CNT_UIFCPY) >> TIM_CNT_UIFCPY_Pos) + +/** + * @brief HELPER macro calculating DTG[0:7] in the TIMx_BDTR register to achieve the requested dead time duration. + * @note ex: @ref __LL_TIM_CALC_DEADTIME (80000000, @ref LL_TIM_GetClockDivision (), 120); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __CKD__ This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + * @param __DT__ deadtime duration (in ns) + * @retval DTG[0:7] + */ +#define __LL_TIM_CALC_DEADTIME(__TIMCLK__, __CKD__, __DT__) \ + ( (((uint64_t)((__DT__)*1000U)) < ((DT_DELAY_1+1U) * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(((uint64_t)((__DT__)*1000U) / TIM_CALC_DTS((__TIMCLK__), (__CKD__))) & DT_DELAY_1) : \ + (((uint64_t)((__DT__)*1000U)) < ((64U + (DT_DELAY_2+1U)) * 2U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(DT_RANGE_2 | ((uint8_t)((uint8_t)((((uint64_t)((__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ + (__CKD__))) >> 1U) - (uint8_t) 64) & DT_DELAY_2)) :\ + (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_3+1U)) * 8U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(DT_RANGE_3 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ + (__CKD__))) >> 3U) - (uint8_t) 32) & DT_DELAY_3)) :\ + (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_4+1U)) * 16U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ + (uint8_t)(DT_RANGE_4 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ + (__CKD__))) >> 4U) - (uint8_t) 32) & DT_DELAY_4)) :\ + 0U) + +/** + * @brief HELPER macro calculating the prescaler value to achieve the required counter clock frequency. + * @note ex: @ref __LL_TIM_CALC_PSC (80000000, 1000000); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __CNTCLK__ counter clock frequency (in Hz) + * @retval Prescaler value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_PSC(__TIMCLK__, __CNTCLK__) \ + (((__TIMCLK__) >= (__CNTCLK__)) ? (uint32_t)((((__TIMCLK__) + (__CNTCLK__)/2U)/(__CNTCLK__)) - 1U) : 0U) + +/** + * @brief HELPER macro calculating the auto-reload value to achieve the required output signal frequency. + * @note ex: @ref __LL_TIM_CALC_ARR (1000000, @ref LL_TIM_GetPrescaler (), 10000); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __PSC__ prescaler + * @param __FREQ__ output signal frequency (in Hz) + * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_ARR(__TIMCLK__, __PSC__, __FREQ__) \ + ((((__TIMCLK__)/((__PSC__) + 1U)) >= (__FREQ__)) ? (((__TIMCLK__)/((__FREQ__) * ((__PSC__) + 1U))) - 1U) : 0U) + +/** + * @brief HELPER macro calculating the compare value required to achieve the required timer output compare + * active/inactive delay. + * @note ex: @ref __LL_TIM_CALC_DELAY (1000000, @ref LL_TIM_GetPrescaler (), 10); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __PSC__ prescaler + * @param __DELAY__ timer output compare active/inactive delay (in us) + * @retval Compare value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_DELAY(__TIMCLK__, __PSC__, __DELAY__) \ + ((uint32_t)(((uint64_t)(__TIMCLK__) * (uint64_t)(__DELAY__)) \ + / ((uint64_t)1000000U * (uint64_t)((__PSC__) + 1U)))) + +/** + * @brief HELPER macro calculating the auto-reload value to achieve the required pulse duration + * (when the timer operates in one pulse mode). + * @note ex: @ref __LL_TIM_CALC_PULSE (1000000, @ref LL_TIM_GetPrescaler (), 10, 20); + * @param __TIMCLK__ timer input clock frequency (in Hz) + * @param __PSC__ prescaler + * @param __DELAY__ timer output compare active/inactive delay (in us) + * @param __PULSE__ pulse duration (in us) + * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) + */ +#define __LL_TIM_CALC_PULSE(__TIMCLK__, __PSC__, __DELAY__, __PULSE__) \ + ((uint32_t)(__LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__PULSE__)) \ + + __LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__DELAY__)))) + +/** + * @brief HELPER macro retrieving the ratio of the input capture prescaler + * @note ex: @ref __LL_TIM_GET_ICPSC_RATIO (@ref LL_TIM_IC_GetPrescaler ()); + * @param __ICPSC__ This parameter can be one of the following values: + * @arg @ref LL_TIM_ICPSC_DIV1 + * @arg @ref LL_TIM_ICPSC_DIV2 + * @arg @ref LL_TIM_ICPSC_DIV4 + * @arg @ref LL_TIM_ICPSC_DIV8 + * @retval Input capture prescaler ratio (1, 2, 4 or 8) + */ +#define __LL_TIM_GET_ICPSC_RATIO(__ICPSC__) \ + ((uint32_t)(0x01U << (((__ICPSC__) >> 16U) >> TIM_CCMR1_IC1PSC_Pos))) + + +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @defgroup TIM_LL_Exported_Functions TIM Exported Functions + * @{ + */ + +/** @defgroup TIM_LL_EF_Time_Base Time Base configuration + * @{ + */ +/** + * @brief Enable timer counter. + * @rmtoll CR1 CEN LL_TIM_EnableCounter + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableCounter(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_CEN); +} + +/** + * @brief Disable timer counter. + * @rmtoll CR1 CEN LL_TIM_DisableCounter + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableCounter(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_CEN); +} + +/** + * @brief Indicates whether the timer counter is enabled. + * @rmtoll CR1 CEN LL_TIM_IsEnabledCounter + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledCounter(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR1, TIM_CR1_CEN) == (TIM_CR1_CEN)) ? 1UL : 0UL); +} + +/** + * @brief Enable update event generation. + * @rmtoll CR1 UDIS LL_TIM_EnableUpdateEvent + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableUpdateEvent(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_UDIS); +} + +/** + * @brief Disable update event generation. + * @rmtoll CR1 UDIS LL_TIM_DisableUpdateEvent + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableUpdateEvent(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_UDIS); +} + +/** + * @brief Indicates whether update event generation is enabled. + * @rmtoll CR1 UDIS LL_TIM_IsEnabledUpdateEvent + * @param TIMx Timer instance + * @retval Inverted state of bit (0 or 1). + */ +static inline uint32_t LL_TIM_IsEnabledUpdateEvent(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR1, TIM_CR1_UDIS) == (uint32_t)RESET) ? 1UL : 0UL); +} + +/** + * @brief Set update event source + * @note Update event source set to LL_TIM_UPDATESOURCE_REGULAR: any of the following events + * generate an update interrupt or DMA request if enabled: + * - Counter overflow/underflow + * - Setting the UG bit + * - Update generation through the slave mode controller + * @note Update event source set to LL_TIM_UPDATESOURCE_COUNTER: only counter + * overflow/underflow generates an update interrupt or DMA request if enabled. + * @rmtoll CR1 URS LL_TIM_SetUpdateSource + * @param TIMx Timer instance + * @param UpdateSource This parameter can be one of the following values: + * @arg @ref LL_TIM_UPDATESOURCE_REGULAR + * @arg @ref LL_TIM_UPDATESOURCE_COUNTER + * @retval None + */ +static inline void LL_TIM_SetUpdateSource(TIM_TypeDef *TIMx, uint32_t UpdateSource) +{ + MODIFY_REG(TIMx->CR1, TIM_CR1_URS, UpdateSource); +} + +/** + * @brief Get actual event update source + * @rmtoll CR1 URS LL_TIM_GetUpdateSource + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_UPDATESOURCE_REGULAR + * @arg @ref LL_TIM_UPDATESOURCE_COUNTER + */ +static inline uint32_t LL_TIM_GetUpdateSource(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_URS)); +} + +/** + * @brief Set one pulse mode (one shot v.s. repetitive). + * @rmtoll CR1 OPM LL_TIM_SetOnePulseMode + * @param TIMx Timer instance + * @param OnePulseMode This parameter can be one of the following values: + * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE + * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE + * @retval None + */ +static inline void LL_TIM_SetOnePulseMode(TIM_TypeDef *TIMx, uint32_t OnePulseMode) +{ + MODIFY_REG(TIMx->CR1, TIM_CR1_OPM, OnePulseMode); +} + +/** + * @brief Get actual one pulse mode. + * @rmtoll CR1 OPM LL_TIM_GetOnePulseMode + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE + * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE + */ +static inline uint32_t LL_TIM_GetOnePulseMode(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_OPM)); +} + +/** + * @brief Set the timer counter counting mode. + * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to + * check whether or not the counter mode selection feature is supported + * by a timer instance. + * @note Switching from Center Aligned counter mode to Edge counter mode (or reverse) + * requires a timer reset to avoid unexpected direction + * due to DIR bit readonly in center aligned mode. + * @rmtoll CR1 DIR LL_TIM_SetCounterMode\n + * CR1 CMS LL_TIM_SetCounterMode + * @param TIMx Timer instance + * @param CounterMode This parameter can be one of the following values: + * @arg @ref LL_TIM_COUNTERMODE_UP + * @arg @ref LL_TIM_COUNTERMODE_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP + * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN + * @retval None + */ +static inline void LL_TIM_SetCounterMode(TIM_TypeDef *TIMx, uint32_t CounterMode) +{ + MODIFY_REG(TIMx->CR1, (TIM_CR1_DIR | TIM_CR1_CMS), CounterMode); +} + +/** + * @brief Get actual counter mode. + * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to + * check whether or not the counter mode selection feature is supported + * by a timer instance. + * @rmtoll CR1 DIR LL_TIM_GetCounterMode\n + * CR1 CMS LL_TIM_GetCounterMode + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_COUNTERMODE_UP + * @arg @ref LL_TIM_COUNTERMODE_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP + * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN + * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN + */ +static inline uint32_t LL_TIM_GetCounterMode(const TIM_TypeDef *TIMx) +{ + uint32_t counter_mode; + + counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CMS)); + + if (counter_mode == 0U) + { + counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); + } + + return counter_mode; +} + +/** + * @brief Enable auto-reload (ARR) preload. + * @rmtoll CR1 ARPE LL_TIM_EnableARRPreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableARRPreload(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_ARPE); +} + +/** + * @brief Disable auto-reload (ARR) preload. + * @rmtoll CR1 ARPE LL_TIM_DisableARRPreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableARRPreload(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_ARPE); +} + +/** + * @brief Indicates whether auto-reload (ARR) preload is enabled. + * @rmtoll CR1 ARPE LL_TIM_IsEnabledARRPreload + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledARRPreload(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR1, TIM_CR1_ARPE) == (TIM_CR1_ARPE)) ? 1UL : 0UL); +} + +/** + * @brief Set the division ratio between the timer clock and the sampling clock used by the dead-time generators + * (when supported) and the digital filters. + * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check + * whether or not the clock division feature is supported by the timer + * instance. + * @rmtoll CR1 CKD LL_TIM_SetClockDivision + * @param TIMx Timer instance + * @param ClockDivision This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + * @retval None + */ +static inline void LL_TIM_SetClockDivision(TIM_TypeDef *TIMx, uint32_t ClockDivision) +{ + MODIFY_REG(TIMx->CR1, TIM_CR1_CKD, ClockDivision); +} + +/** + * @brief Get the actual division ratio between the timer clock and the sampling clock used by the dead-time + * generators (when supported) and the digital filters. + * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check + * whether or not the clock division feature is supported by the timer + * instance. + * @rmtoll CR1 CKD LL_TIM_GetClockDivision + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 + * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 + */ +static inline uint32_t LL_TIM_GetClockDivision(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CKD)); +} + +/** + * @brief Set the counter value. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @rmtoll CNT CNT LL_TIM_SetCounter + * @param TIMx Timer instance + * @param Counter Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) + * @retval None + */ +static inline void LL_TIM_SetCounter(TIM_TypeDef *TIMx, uint32_t Counter) +{ + WRITE_REG(TIMx->CNT, Counter); +} + +/** + * @brief Get the counter value. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @rmtoll CNT CNT LL_TIM_GetCounter + * @param TIMx Timer instance + * @retval Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) + */ +static inline uint32_t LL_TIM_GetCounter(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CNT)); +} + +/** + * @brief Get the current direction of the counter + * @rmtoll CR1 DIR LL_TIM_GetDirection + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_COUNTERDIRECTION_UP + * @arg @ref LL_TIM_COUNTERDIRECTION_DOWN + */ +static inline uint32_t LL_TIM_GetDirection(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); +} + +/** + * @brief Set the prescaler value. + * @note The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1). + * @note The prescaler can be changed on the fly as this control register is buffered. The new + * prescaler ratio is taken into account at the next update event. + * @note Helper macro @ref __LL_TIM_CALC_PSC can be used to calculate the Prescaler parameter + * @rmtoll PSC PSC LL_TIM_SetPrescaler + * @param TIMx Timer instance + * @param Prescaler between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Prescaler) +{ + WRITE_REG(TIMx->PSC, Prescaler); +} + +/** + * @brief Get the prescaler value. + * @rmtoll PSC PSC LL_TIM_GetPrescaler + * @param TIMx Timer instance + * @retval Prescaler value between Min_Data=0 and Max_Data=65535 + */ +static inline uint32_t LL_TIM_GetPrescaler(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->PSC)); +} + +/** + * @brief Set the auto-reload value. + * @note The counter is blocked while the auto-reload value is null. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Helper macro @ref __LL_TIM_CALC_ARR can be used to calculate the AutoReload parameter + * @rmtoll ARR ARR LL_TIM_SetAutoReload + * @param TIMx Timer instance + * @param AutoReload between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_SetAutoReload(TIM_TypeDef *TIMx, uint32_t AutoReload) +{ + WRITE_REG(TIMx->ARR, AutoReload); +} + +/** + * @brief Get the auto-reload value. + * @rmtoll ARR ARR LL_TIM_GetAutoReload + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @param TIMx Timer instance + * @retval Auto-reload value + */ +static inline uint32_t LL_TIM_GetAutoReload(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->ARR)); +} + +/** + * @brief Set the repetition counter value. + * @note For advanced timer instances RepetitionCounter can be up to 65535. + * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a repetition counter. + * @rmtoll RCR REP LL_TIM_SetRepetitionCounter + * @param TIMx Timer instance + * @param RepetitionCounter between Min_Data=0 and Max_Data=255 or 65535 for advanced timer. + * @retval None + */ +static inline void LL_TIM_SetRepetitionCounter(TIM_TypeDef *TIMx, uint32_t RepetitionCounter) +{ + WRITE_REG(TIMx->RCR, RepetitionCounter); +} + +/** + * @brief Get the repetition counter value. + * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a repetition counter. + * @rmtoll RCR REP LL_TIM_GetRepetitionCounter + * @param TIMx Timer instance + * @retval Repetition counter value + */ +static inline uint32_t LL_TIM_GetRepetitionCounter(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->RCR)); +} + +/** + * @brief Force a continuous copy of the update interrupt flag (UIF) into the timer counter register (bit 31). + * @note This allows both the counter value and a potential roll-over condition signalled by the UIFCPY flag to be read + * in an atomic way. + * @rmtoll CR1 UIFREMAP LL_TIM_EnableUIFRemap + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableUIFRemap(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); +} + +/** + * @brief Disable update interrupt flag (UIF) remapping. + * @rmtoll CR1 UIFREMAP LL_TIM_DisableUIFRemap + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableUIFRemap(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); +} + +/** + * @brief Indicate whether update interrupt flag (UIF) copy is set. + * @param Counter Counter value + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveUIFCPY(const uint32_t Counter) +{ + return (((Counter & TIM_CNT_UIFCPY) == (TIM_CNT_UIFCPY)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Capture_Compare Capture Compare configuration + * @{ + */ +/** + * @brief Enable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. + * @note CCxE, CCxNE and OCxM bits are preloaded, after having been written, + * they are updated only when a commutation event (COM) occurs. + * @note Only on channels that have a complementary output. + * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check + * whether or not a timer instance is able to generate a commutation event. + * @rmtoll CR2 CCPC LL_TIM_CC_EnablePreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_CC_EnablePreload(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR2, TIM_CR2_CCPC); +} + +/** + * @brief Disable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. + * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check + * whether or not a timer instance is able to generate a commutation event. + * @rmtoll CR2 CCPC LL_TIM_CC_DisablePreload + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_CC_DisablePreload(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR2, TIM_CR2_CCPC); +} + +/** + * @brief Indicates whether the capture/compare control bits (CCxE, CCxNE and OCxM) preload is enabled. + * @rmtoll CR2 CCPC LL_TIM_CC_IsEnabledPreload + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_CC_IsEnabledPreload(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR2, TIM_CR2_CCPC) == (TIM_CR2_CCPC)) ? 1UL : 0UL); +} + +/** + * @brief Set the updated source of the capture/compare control bits (CCxE, CCxNE and OCxM). + * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check + * whether or not a timer instance is able to generate a commutation event. + * @rmtoll CR2 CCUS LL_TIM_CC_SetUpdate + * @param TIMx Timer instance + * @param CCUpdateSource This parameter can be one of the following values: + * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_ONLY + * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI + * @retval None + */ +static inline void LL_TIM_CC_SetUpdate(TIM_TypeDef *TIMx, uint32_t CCUpdateSource) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_CCUS, CCUpdateSource); +} + +/** + * @brief Set the trigger of the capture/compare DMA request. + * @rmtoll CR2 CCDS LL_TIM_CC_SetDMAReqTrigger + * @param TIMx Timer instance + * @param DMAReqTrigger This parameter can be one of the following values: + * @arg @ref LL_TIM_CCDMAREQUEST_CC + * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE + * @retval None + */ +static inline void LL_TIM_CC_SetDMAReqTrigger(TIM_TypeDef *TIMx, uint32_t DMAReqTrigger) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_CCDS, DMAReqTrigger); +} + +/** + * @brief Get actual trigger of the capture/compare DMA request. + * @rmtoll CR2 CCDS LL_TIM_CC_GetDMAReqTrigger + * @param TIMx Timer instance + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_CCDMAREQUEST_CC + * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE + */ +static inline uint32_t LL_TIM_CC_GetDMAReqTrigger(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CR2, TIM_CR2_CCDS)); +} + +/** + * @brief Set the lock level to freeze the + * configuration of several capture/compare parameters. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * the lock mechanism is supported by a timer instance. + * @rmtoll BDTR LOCK LL_TIM_CC_SetLockLevel + * @param TIMx Timer instance + * @param LockLevel This parameter can be one of the following values: + * @arg @ref LL_TIM_LOCKLEVEL_OFF + * @arg @ref LL_TIM_LOCKLEVEL_1 + * @arg @ref LL_TIM_LOCKLEVEL_2 + * @arg @ref LL_TIM_LOCKLEVEL_3 + * @retval None + */ +static inline void LL_TIM_CC_SetLockLevel(TIM_TypeDef *TIMx, uint32_t LockLevel) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_LOCK, LockLevel); +} + +/** + * @brief Enable capture/compare channels. + * @rmtoll CCER CC1E LL_TIM_CC_EnableChannel\n + * CCER CC1NE LL_TIM_CC_EnableChannel\n + * CCER CC2E LL_TIM_CC_EnableChannel\n + * CCER CC2NE LL_TIM_CC_EnableChannel\n + * CCER CC3E LL_TIM_CC_EnableChannel\n + * CCER CC3NE LL_TIM_CC_EnableChannel\n + * CCER CC4E LL_TIM_CC_EnableChannel\n + * CCER CC5E LL_TIM_CC_EnableChannel\n + * CCER CC6E LL_TIM_CC_EnableChannel + * @param TIMx Timer instance + * @param Channels This parameter can be a combination of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_CC_EnableChannel(TIM_TypeDef *TIMx, uint32_t Channels) +{ + SET_BIT(TIMx->CCER, Channels); +} + +/** + * @brief Disable capture/compare channels. + * @rmtoll CCER CC1E LL_TIM_CC_DisableChannel\n + * CCER CC1NE LL_TIM_CC_DisableChannel\n + * CCER CC2E LL_TIM_CC_DisableChannel\n + * CCER CC2NE LL_TIM_CC_DisableChannel\n + * CCER CC3E LL_TIM_CC_DisableChannel\n + * CCER CC3NE LL_TIM_CC_DisableChannel\n + * CCER CC4E LL_TIM_CC_DisableChannel\n + * CCER CC5E LL_TIM_CC_DisableChannel\n + * CCER CC6E LL_TIM_CC_DisableChannel + * @param TIMx Timer instance + * @param Channels This parameter can be a combination of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_CC_DisableChannel(TIM_TypeDef *TIMx, uint32_t Channels) +{ + CLEAR_BIT(TIMx->CCER, Channels); +} + +/** + * @brief Indicate whether channel(s) is(are) enabled. + * @rmtoll CCER CC1E LL_TIM_CC_IsEnabledChannel\n + * CCER CC1NE LL_TIM_CC_IsEnabledChannel\n + * CCER CC2E LL_TIM_CC_IsEnabledChannel\n + * CCER CC2NE LL_TIM_CC_IsEnabledChannel\n + * CCER CC3E LL_TIM_CC_IsEnabledChannel\n + * CCER CC3NE LL_TIM_CC_IsEnabledChannel\n + * CCER CC4E LL_TIM_CC_IsEnabledChannel\n + * CCER CC5E LL_TIM_CC_IsEnabledChannel\n + * CCER CC6E LL_TIM_CC_IsEnabledChannel + * @param TIMx Timer instance + * @param Channels This parameter can be a combination of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_CC_IsEnabledChannel(const TIM_TypeDef *TIMx, uint32_t Channels) +{ + return ((READ_BIT(TIMx->CCER, Channels) == (Channels)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Output_Channel Output channel configuration + * @{ + */ +/** + * @brief Configure an output channel. + * @rmtoll CCMR1 CC1S LL_TIM_OC_ConfigOutput\n + * CCMR1 CC2S LL_TIM_OC_ConfigOutput\n + * CCMR2 CC3S LL_TIM_OC_ConfigOutput\n + * CCMR2 CC4S LL_TIM_OC_ConfigOutput\n + * CCMR3 CC5S LL_TIM_OC_ConfigOutput\n + * CCMR3 CC6S LL_TIM_OC_ConfigOutput\n + * CCER CC1P LL_TIM_OC_ConfigOutput\n + * CCER CC2P LL_TIM_OC_ConfigOutput\n + * CCER CC3P LL_TIM_OC_ConfigOutput\n + * CCER CC4P LL_TIM_OC_ConfigOutput\n + * CCER CC5P LL_TIM_OC_ConfigOutput\n + * CCER CC6P LL_TIM_OC_ConfigOutput\n + * CR2 OIS1 LL_TIM_OC_ConfigOutput\n + * CR2 OIS2 LL_TIM_OC_ConfigOutput\n + * CR2 OIS3 LL_TIM_OC_ConfigOutput\n + * CR2 OIS4 LL_TIM_OC_ConfigOutput\n + * CR2 OIS5 LL_TIM_OC_ConfigOutput\n + * CR2 OIS6 LL_TIM_OC_ConfigOutput + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param Configuration This parameter must be a combination of all the following values: + * @arg @ref LL_TIM_OCPOLARITY_HIGH or @ref LL_TIM_OCPOLARITY_LOW + * @arg @ref LL_TIM_OCIDLESTATE_LOW or @ref LL_TIM_OCIDLESTATE_HIGH + * @retval None + */ +static inline void LL_TIM_OC_ConfigOutput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_CC1S << SHIFT_TAB_OCxx[iChannel])); + MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), + (Configuration & TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]); + MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), + (Configuration & TIM_CR2_OIS1) << SHIFT_TAB_OISx[iChannel]); +} + +/** + * @brief Define the behavior of the output reference signal OCxREF from which + * OCx and OCxN (when relevant) are derived. + * @rmtoll CCMR1 OC1M LL_TIM_OC_SetMode\n + * CCMR1 OC2M LL_TIM_OC_SetMode\n + * CCMR2 OC3M LL_TIM_OC_SetMode\n + * CCMR2 OC4M LL_TIM_OC_SetMode\n + * CCMR3 OC5M LL_TIM_OC_SetMode\n + * CCMR3 OC6M LL_TIM_OC_SetMode + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param Mode This parameter can be one of the following values: + * @arg @ref LL_TIM_OCMODE_FROZEN + * @arg @ref LL_TIM_OCMODE_ACTIVE + * @arg @ref LL_TIM_OCMODE_INACTIVE + * @arg @ref LL_TIM_OCMODE_TOGGLE + * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE + * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE + * @arg @ref LL_TIM_OCMODE_PWM1 + * @arg @ref LL_TIM_OCMODE_PWM2 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 + * @retval None + */ +static inline void LL_TIM_OC_SetMode(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Mode) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel]), Mode << SHIFT_TAB_OCxx[iChannel]); +} + +/** + * @brief Get the output compare mode of an output channel. + * @rmtoll CCMR1 OC1M LL_TIM_OC_GetMode\n + * CCMR1 OC2M LL_TIM_OC_GetMode\n + * CCMR2 OC3M LL_TIM_OC_GetMode\n + * CCMR2 OC4M LL_TIM_OC_GetMode\n + * CCMR3 OC5M LL_TIM_OC_GetMode\n + * CCMR3 OC6M LL_TIM_OC_GetMode + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_OCMODE_FROZEN + * @arg @ref LL_TIM_OCMODE_ACTIVE + * @arg @ref LL_TIM_OCMODE_INACTIVE + * @arg @ref LL_TIM_OCMODE_TOGGLE + * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE + * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE + * @arg @ref LL_TIM_OCMODE_PWM1 + * @arg @ref LL_TIM_OCMODE_PWM2 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 + * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 + * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 + * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 + */ +static inline uint32_t LL_TIM_OC_GetMode(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return (READ_BIT(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel])) >> SHIFT_TAB_OCxx[iChannel]); +} + +/** + * @brief Set the polarity of an output channel. + * @rmtoll CCER CC1P LL_TIM_OC_SetPolarity\n + * CCER CC1NP LL_TIM_OC_SetPolarity\n + * CCER CC2P LL_TIM_OC_SetPolarity\n + * CCER CC2NP LL_TIM_OC_SetPolarity\n + * CCER CC3P LL_TIM_OC_SetPolarity\n + * CCER CC3NP LL_TIM_OC_SetPolarity\n + * CCER CC4P LL_TIM_OC_SetPolarity\n + * CCER CC5P LL_TIM_OC_SetPolarity\n + * CCER CC6P LL_TIM_OC_SetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_OCPOLARITY_HIGH + * @arg @ref LL_TIM_OCPOLARITY_LOW + * @retval None + */ +static inline void LL_TIM_OC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Polarity) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), Polarity << SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Get the polarity of an output channel. + * @rmtoll CCER CC1P LL_TIM_OC_GetPolarity\n + * CCER CC1NP LL_TIM_OC_GetPolarity\n + * CCER CC2P LL_TIM_OC_GetPolarity\n + * CCER CC2NP LL_TIM_OC_GetPolarity\n + * CCER CC3P LL_TIM_OC_GetPolarity\n + * CCER CC3NP LL_TIM_OC_GetPolarity\n + * CCER CC4P LL_TIM_OC_GetPolarity\n + * CCER CC5P LL_TIM_OC_GetPolarity\n + * CCER CC6P LL_TIM_OC_GetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_OCPOLARITY_HIGH + * @arg @ref LL_TIM_OCPOLARITY_LOW + */ +static inline uint32_t LL_TIM_OC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + return (READ_BIT(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel])) >> SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Set the IDLE state of an output channel + * @note This function is significant only for the timer instances + * supporting the break feature. Macro IS_TIM_BREAK_INSTANCE(TIMx) + * can be used to check whether or not a timer instance provides + * a break input. + * @rmtoll CR2 OIS1 LL_TIM_OC_SetIdleState\n + * CR2 OIS2N LL_TIM_OC_SetIdleState\n + * CR2 OIS2 LL_TIM_OC_SetIdleState\n + * CR2 OIS2N LL_TIM_OC_SetIdleState\n + * CR2 OIS3 LL_TIM_OC_SetIdleState\n + * CR2 OIS3N LL_TIM_OC_SetIdleState\n + * CR2 OIS4 LL_TIM_OC_SetIdleState\n + * CR2 OIS5 LL_TIM_OC_SetIdleState\n + * CR2 OIS6 LL_TIM_OC_SetIdleState + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @param IdleState This parameter can be one of the following values: + * @arg @ref LL_TIM_OCIDLESTATE_LOW + * @arg @ref LL_TIM_OCIDLESTATE_HIGH + * @retval None + */ +static inline void LL_TIM_OC_SetIdleState(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t IdleState) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), IdleState << SHIFT_TAB_OISx[iChannel]); +} + +/** + * @brief Get the IDLE state of an output channel + * @rmtoll CR2 OIS1 LL_TIM_OC_GetIdleState\n + * CR2 OIS2N LL_TIM_OC_GetIdleState\n + * CR2 OIS2 LL_TIM_OC_GetIdleState\n + * CR2 OIS2N LL_TIM_OC_GetIdleState\n + * CR2 OIS3 LL_TIM_OC_GetIdleState\n + * CR2 OIS3N LL_TIM_OC_GetIdleState\n + * CR2 OIS4 LL_TIM_OC_GetIdleState\n + * CR2 OIS5 LL_TIM_OC_GetIdleState\n + * CR2 OIS6 LL_TIM_OC_GetIdleState + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH1N + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH2N + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH3N + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_OCIDLESTATE_LOW + * @arg @ref LL_TIM_OCIDLESTATE_HIGH + */ +static inline uint32_t LL_TIM_OC_GetIdleState(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + return (READ_BIT(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel])) >> SHIFT_TAB_OISx[iChannel]); +} + +/** + * @brief Enable fast mode for the output channel. + * @note Acts only if the channel is configured in PWM1 or PWM2 mode. + * @rmtoll CCMR1 OC1FE LL_TIM_OC_EnableFast\n + * CCMR1 OC2FE LL_TIM_OC_EnableFast\n + * CCMR2 OC3FE LL_TIM_OC_EnableFast\n + * CCMR2 OC4FE LL_TIM_OC_EnableFast\n + * CCMR3 OC5FE LL_TIM_OC_EnableFast\n + * CCMR3 OC6FE LL_TIM_OC_EnableFast + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_EnableFast(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + SET_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); + +} + +/** + * @brief Disable fast mode for the output channel. + * @rmtoll CCMR1 OC1FE LL_TIM_OC_DisableFast\n + * CCMR1 OC2FE LL_TIM_OC_DisableFast\n + * CCMR2 OC3FE LL_TIM_OC_DisableFast\n + * CCMR2 OC4FE LL_TIM_OC_DisableFast\n + * CCMR3 OC5FE LL_TIM_OC_DisableFast\n + * CCMR3 OC6FE LL_TIM_OC_DisableFast + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_DisableFast(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); + +} + +/** + * @brief Indicates whether fast mode is enabled for the output channel. + * @rmtoll CCMR1 OC1FE LL_TIM_OC_IsEnabledFast\n + * CCMR1 OC2FE LL_TIM_OC_IsEnabledFast\n + * CCMR2 OC3FE LL_TIM_OC_IsEnabledFast\n + * CCMR2 OC4FE LL_TIM_OC_IsEnabledFast\n + * CCMR3 OC5FE LL_TIM_OC_IsEnabledFast\n + * CCMR3 OC6FE LL_TIM_OC_IsEnabledFast + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_OC_IsEnabledFast(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + uint32_t bitfield = TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel]; + return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); +} + +/** + * @brief Enable compare register (TIMx_CCRx) preload for the output channel. + * @rmtoll CCMR1 OC1PE LL_TIM_OC_EnablePreload\n + * CCMR1 OC2PE LL_TIM_OC_EnablePreload\n + * CCMR2 OC3PE LL_TIM_OC_EnablePreload\n + * CCMR2 OC4PE LL_TIM_OC_EnablePreload\n + * CCMR3 OC5PE LL_TIM_OC_EnablePreload\n + * CCMR3 OC6PE LL_TIM_OC_EnablePreload + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_EnablePreload(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + SET_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Disable compare register (TIMx_CCRx) preload for the output channel. + * @rmtoll CCMR1 OC1PE LL_TIM_OC_DisablePreload\n + * CCMR1 OC2PE LL_TIM_OC_DisablePreload\n + * CCMR2 OC3PE LL_TIM_OC_DisablePreload\n + * CCMR2 OC4PE LL_TIM_OC_DisablePreload\n + * CCMR3 OC5PE LL_TIM_OC_DisablePreload\n + * CCMR3 OC6PE LL_TIM_OC_DisablePreload + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_DisablePreload(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Indicates whether compare register (TIMx_CCRx) preload is enabled for the output channel. + * @rmtoll CCMR1 OC1PE LL_TIM_OC_IsEnabledPreload\n + * CCMR1 OC2PE LL_TIM_OC_IsEnabledPreload\n + * CCMR2 OC3PE LL_TIM_OC_IsEnabledPreload\n + * CCMR2 OC4PE LL_TIM_OC_IsEnabledPreload\n + * CCMR3 OC5PE LL_TIM_OC_IsEnabledPreload\n + * CCMR3 OC6PE LL_TIM_OC_IsEnabledPreload + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_OC_IsEnabledPreload(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + uint32_t bitfield = TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel]; + return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); +} + +/** + * @brief Enable clearing the output channel on an external event. + * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. + * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether + * or not a timer instance can clear the OCxREF signal on an external event. + * @rmtoll CCMR1 OC1CE LL_TIM_OC_EnableClear\n + * CCMR1 OC2CE LL_TIM_OC_EnableClear\n + * CCMR2 OC3CE LL_TIM_OC_EnableClear\n + * CCMR2 OC4CE LL_TIM_OC_EnableClear\n + * CCMR3 OC5CE LL_TIM_OC_EnableClear\n + * CCMR3 OC6CE LL_TIM_OC_EnableClear + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_EnableClear(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + SET_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Disable clearing the output channel on an external event. + * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether + * or not a timer instance can clear the OCxREF signal on an external event. + * @rmtoll CCMR1 OC1CE LL_TIM_OC_DisableClear\n + * CCMR1 OC2CE LL_TIM_OC_DisableClear\n + * CCMR2 OC3CE LL_TIM_OC_DisableClear\n + * CCMR2 OC4CE LL_TIM_OC_DisableClear\n + * CCMR3 OC5CE LL_TIM_OC_DisableClear\n + * CCMR3 OC6CE LL_TIM_OC_DisableClear + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval None + */ +static inline void LL_TIM_OC_DisableClear(TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + CLEAR_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); +} + +/** + * @brief Indicates clearing the output channel on an external event is enabled for the output channel. + * @note This function enables clearing the output channel on an external event. + * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. + * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether + * or not a timer instance can clear the OCxREF signal on an external event. + * @rmtoll CCMR1 OC1CE LL_TIM_OC_IsEnabledClear\n + * CCMR1 OC2CE LL_TIM_OC_IsEnabledClear\n + * CCMR2 OC3CE LL_TIM_OC_IsEnabledClear\n + * CCMR2 OC4CE LL_TIM_OC_IsEnabledClear\n + * CCMR3 OC5CE LL_TIM_OC_IsEnabledClear\n + * CCMR3 OC6CE LL_TIM_OC_IsEnabledClear + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @arg @ref LL_TIM_CHANNEL_CH5 + * @arg @ref LL_TIM_CHANNEL_CH6 + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_OC_IsEnabledClear(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + uint32_t bitfield = TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel]; + return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); +} + +/** + * @brief Set the dead-time delay (delay inserted between the rising edge of the OCxREF signal and the rising edge of + * the Ocx and OCxN signals). + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * dead-time insertion feature is supported by a timer instance. + * @note Helper macro @ref __LL_TIM_CALC_DEADTIME can be used to calculate the DeadTime parameter + * @rmtoll BDTR DTG LL_TIM_OC_SetDeadTime + * @param TIMx Timer instance + * @param DeadTime between Min_Data=0 and Max_Data=255 + * @retval None + */ +static inline void LL_TIM_OC_SetDeadTime(TIM_TypeDef *TIMx, uint32_t DeadTime) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_DTG, DeadTime); +} + +/** + * @brief Set compare value for output channel 1 (TIMx_CCR1). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not + * output channel 1 is supported by a timer instance. + * @rmtoll CCR1 CCR1 LL_TIM_OC_SetCompareCH1 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH1(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR1, CompareValue); +} + +/** + * @brief Set compare value for output channel 2 (TIMx_CCR2). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not + * output channel 2 is supported by a timer instance. + * @rmtoll CCR2 CCR2 LL_TIM_OC_SetCompareCH2 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH2(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR2, CompareValue); +} + +/** + * @brief Set compare value for output channel 3 (TIMx_CCR3). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not + * output channel is supported by a timer instance. + * @rmtoll CCR3 CCR3 LL_TIM_OC_SetCompareCH3 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH3(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR3, CompareValue); +} + +/** + * @brief Set compare value for output channel 4 (TIMx_CCR4). + * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not + * output channel 4 is supported by a timer instance. + * @rmtoll CCR4 CCR4 LL_TIM_OC_SetCompareCH4 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH4(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR4, CompareValue); +} + +/** + * @brief Set compare value for output channel 5 (TIMx_CCR5). + * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not + * output channel 5 is supported by a timer instance. + * @rmtoll CCR5 CCR5 LL_TIM_OC_SetCompareCH5 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH5(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + MODIFY_REG(TIMx->CCR5, TIM_CCR5_CCR5, CompareValue); +} + +/** + * @brief Set compare value for output channel 6 (TIMx_CCR6). + * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not + * output channel 6 is supported by a timer instance. + * @rmtoll CCR6 CCR6 LL_TIM_OC_SetCompareCH6 + * @param TIMx Timer instance + * @param CompareValue between Min_Data=0 and Max_Data=65535 + * @retval None + */ +static inline void LL_TIM_OC_SetCompareCH6(TIM_TypeDef *TIMx, uint32_t CompareValue) +{ + WRITE_REG(TIMx->CCR6, CompareValue); +} + +/** + * @brief Get compare value (TIMx_CCR1) set for output channel 1. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not + * output channel 1 is supported by a timer instance. + * @rmtoll CCR1 CCR1 LL_TIM_OC_GetCompareCH1 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH1(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR1)); +} + +/** + * @brief Get compare value (TIMx_CCR2) set for output channel 2. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not + * output channel 2 is supported by a timer instance. + * @rmtoll CCR2 CCR2 LL_TIM_OC_GetCompareCH2 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH2(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR2)); +} + +/** + * @brief Get compare value (TIMx_CCR3) set for output channel 3. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not + * output channel 3 is supported by a timer instance. + * @rmtoll CCR3 CCR3 LL_TIM_OC_GetCompareCH3 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH3(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR3)); +} + +/** + * @brief Get compare value (TIMx_CCR4) set for output channel 4. + * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not + * output channel 4 is supported by a timer instance. + * @rmtoll CCR4 CCR4 LL_TIM_OC_GetCompareCH4 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH4(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR4)); +} + +/** + * @brief Get compare value (TIMx_CCR5) set for output channel 5. + * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not + * output channel 5 is supported by a timer instance. + * @rmtoll CCR5 CCR5 LL_TIM_OC_GetCompareCH5 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH5(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_BIT(TIMx->CCR5, TIM_CCR5_CCR5)); +} + +/** + * @brief Get compare value (TIMx_CCR6) set for output channel 6. + * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not + * output channel 6 is supported by a timer instance. + * @rmtoll CCR6 CCR6 LL_TIM_OC_GetCompareCH6 + * @param TIMx Timer instance + * @retval CompareValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_OC_GetCompareCH6(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR6)); +} + +/** + * @brief Select on which reference signal the OC5REF is combined to. + * @note Macro IS_TIM_COMBINED3PHASEPWM_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports the combined 3-phase PWM mode. + * @rmtoll CCR5 GC5C3 LL_TIM_SetCH5CombinedChannels\n + * CCR5 GC5C2 LL_TIM_SetCH5CombinedChannels\n + * CCR5 GC5C1 LL_TIM_SetCH5CombinedChannels + * @param TIMx Timer instance + * @param GroupCH5 This parameter can be a combination of the following values: + * @arg @ref LL_TIM_GROUPCH5_NONE + * @arg @ref LL_TIM_GROUPCH5_OC1REFC + * @arg @ref LL_TIM_GROUPCH5_OC2REFC + * @arg @ref LL_TIM_GROUPCH5_OC3REFC + * @retval None + */ +static inline void LL_TIM_SetCH5CombinedChannels(TIM_TypeDef *TIMx, uint32_t GroupCH5) +{ + MODIFY_REG(TIMx->CCR5, (TIM_CCR5_GC5C3 | TIM_CCR5_GC5C2 | TIM_CCR5_GC5C1), GroupCH5); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Input_Channel Input channel configuration + * @{ + */ +/** + * @brief Configure input channel. + * @rmtoll CCMR1 CC1S LL_TIM_IC_Config\n + * CCMR1 IC1PSC LL_TIM_IC_Config\n + * CCMR1 IC1F LL_TIM_IC_Config\n + * CCMR1 CC2S LL_TIM_IC_Config\n + * CCMR1 IC2PSC LL_TIM_IC_Config\n + * CCMR1 IC2F LL_TIM_IC_Config\n + * CCMR2 CC3S LL_TIM_IC_Config\n + * CCMR2 IC3PSC LL_TIM_IC_Config\n + * CCMR2 IC3F LL_TIM_IC_Config\n + * CCMR2 CC4S LL_TIM_IC_Config\n + * CCMR2 IC4PSC LL_TIM_IC_Config\n + * CCMR2 IC4F LL_TIM_IC_Config\n + * CCER CC1P LL_TIM_IC_Config\n + * CCER CC1NP LL_TIM_IC_Config\n + * CCER CC2P LL_TIM_IC_Config\n + * CCER CC2NP LL_TIM_IC_Config\n + * CCER CC3P LL_TIM_IC_Config\n + * CCER CC3NP LL_TIM_IC_Config\n + * CCER CC4P LL_TIM_IC_Config\n + * CCER CC4NP LL_TIM_IC_Config + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param Configuration This parameter must be a combination of all the following values: + * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI or @ref LL_TIM_ACTIVEINPUT_INDIRECTTI or @ref LL_TIM_ACTIVEINPUT_TRC + * @arg @ref LL_TIM_ICPSC_DIV1 or ... or @ref LL_TIM_ICPSC_DIV8 + * @arg @ref LL_TIM_IC_FILTER_FDIV1 or ... or @ref LL_TIM_IC_FILTER_FDIV32_N8 + * @arg @ref LL_TIM_IC_POLARITY_RISING or @ref LL_TIM_IC_POLARITY_FALLING or @ref LL_TIM_IC_POLARITY_BOTHEDGE + * @retval None + */ +static inline void LL_TIM_IC_Config(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), + ((Configuration >> 16U) & (TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S)) \ + << SHIFT_TAB_ICxx[iChannel]); + MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), + (Configuration & (TIM_CCER_CC1NP | TIM_CCER_CC1P)) << SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Set the active input. + * @rmtoll CCMR1 CC1S LL_TIM_IC_SetActiveInput\n + * CCMR1 CC2S LL_TIM_IC_SetActiveInput\n + * CCMR2 CC3S LL_TIM_IC_SetActiveInput\n + * CCMR2 CC4S LL_TIM_IC_SetActiveInput + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICActiveInput This parameter can be one of the following values: + * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_TRC + * @retval None + */ +static inline void LL_TIM_IC_SetActiveInput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICActiveInput) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), (ICActiveInput >> 16U) << SHIFT_TAB_ICxx[iChannel]); +} + +/** + * @brief Get the current active input. + * @rmtoll CCMR1 CC1S LL_TIM_IC_GetActiveInput\n + * CCMR1 CC2S LL_TIM_IC_GetActiveInput\n + * CCMR2 CC3S LL_TIM_IC_GetActiveInput\n + * CCMR2 CC4S LL_TIM_IC_GetActiveInput + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI + * @arg @ref LL_TIM_ACTIVEINPUT_TRC + */ +static inline uint32_t LL_TIM_IC_GetActiveInput(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return ((READ_BIT(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); +} + +/** + * @brief Set the prescaler of input channel. + * @rmtoll CCMR1 IC1PSC LL_TIM_IC_SetPrescaler\n + * CCMR1 IC2PSC LL_TIM_IC_SetPrescaler\n + * CCMR2 IC3PSC LL_TIM_IC_SetPrescaler\n + * CCMR2 IC4PSC LL_TIM_IC_SetPrescaler + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICPrescaler This parameter can be one of the following values: + * @arg @ref LL_TIM_ICPSC_DIV1 + * @arg @ref LL_TIM_ICPSC_DIV2 + * @arg @ref LL_TIM_ICPSC_DIV4 + * @arg @ref LL_TIM_ICPSC_DIV8 + * @retval None + */ +static inline void LL_TIM_IC_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPrescaler) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel]), (ICPrescaler >> 16U) << SHIFT_TAB_ICxx[iChannel]); +} + +/** + * @brief Get the current prescaler value acting on an input channel. + * @rmtoll CCMR1 IC1PSC LL_TIM_IC_GetPrescaler\n + * CCMR1 IC2PSC LL_TIM_IC_GetPrescaler\n + * CCMR2 IC3PSC LL_TIM_IC_GetPrescaler\n + * CCMR2 IC4PSC LL_TIM_IC_GetPrescaler + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_ICPSC_DIV1 + * @arg @ref LL_TIM_ICPSC_DIV2 + * @arg @ref LL_TIM_ICPSC_DIV4 + * @arg @ref LL_TIM_ICPSC_DIV8 + */ +static inline uint32_t LL_TIM_IC_GetPrescaler(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); +} + +/** + * @brief Set the input filter duration. + * @rmtoll CCMR1 IC1F LL_TIM_IC_SetFilter\n + * CCMR1 IC2F LL_TIM_IC_SetFilter\n + * CCMR2 IC3F LL_TIM_IC_SetFilter\n + * CCMR2 IC4F LL_TIM_IC_SetFilter + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_IC_FILTER_FDIV1 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_IC_SetFilter(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICFilter) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel]), (ICFilter >> 16U) << SHIFT_TAB_ICxx[iChannel]); +} + +/** + * @brief Get the input filter duration. + * @rmtoll CCMR1 IC1F LL_TIM_IC_GetFilter\n + * CCMR1 IC2F LL_TIM_IC_GetFilter\n + * CCMR2 IC3F LL_TIM_IC_GetFilter\n + * CCMR2 IC4F LL_TIM_IC_GetFilter + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_IC_FILTER_FDIV1 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 + */ +static inline uint32_t LL_TIM_IC_GetFilter(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); + return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); +} + +/** + * @brief Set the input channel polarity. + * @rmtoll CCER CC1P LL_TIM_IC_SetPolarity\n + * CCER CC1NP LL_TIM_IC_SetPolarity\n + * CCER CC2P LL_TIM_IC_SetPolarity\n + * CCER CC2NP LL_TIM_IC_SetPolarity\n + * CCER CC3P LL_TIM_IC_SetPolarity\n + * CCER CC3NP LL_TIM_IC_SetPolarity\n + * CCER CC4P LL_TIM_IC_SetPolarity\n + * CCER CC4NP LL_TIM_IC_SetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @param ICPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_IC_POLARITY_RISING + * @arg @ref LL_TIM_IC_POLARITY_FALLING + * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE + * @retval None + */ +static inline void LL_TIM_IC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPolarity) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), + ICPolarity << SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Get the current input channel polarity. + * @rmtoll CCER CC1P LL_TIM_IC_GetPolarity\n + * CCER CC1NP LL_TIM_IC_GetPolarity\n + * CCER CC2P LL_TIM_IC_GetPolarity\n + * CCER CC2NP LL_TIM_IC_GetPolarity\n + * CCER CC3P LL_TIM_IC_GetPolarity\n + * CCER CC3NP LL_TIM_IC_GetPolarity\n + * CCER CC4P LL_TIM_IC_GetPolarity\n + * CCER CC4NP LL_TIM_IC_GetPolarity + * @param TIMx Timer instance + * @param Channel This parameter can be one of the following values: + * @arg @ref LL_TIM_CHANNEL_CH1 + * @arg @ref LL_TIM_CHANNEL_CH2 + * @arg @ref LL_TIM_CHANNEL_CH3 + * @arg @ref LL_TIM_CHANNEL_CH4 + * @retval Returned value can be one of the following values: + * @arg @ref LL_TIM_IC_POLARITY_RISING + * @arg @ref LL_TIM_IC_POLARITY_FALLING + * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE + */ +static inline uint32_t LL_TIM_IC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) +{ + uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); + return (READ_BIT(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel])) >> + SHIFT_TAB_CCxP[iChannel]); +} + +/** + * @brief Connect the TIMx_CH1, CH2 and CH3 pins to the TI1 input (XOR combination). + * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an XOR input. + * @rmtoll CR2 TI1S LL_TIM_IC_EnableXORCombination + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_IC_EnableXORCombination(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->CR2, TIM_CR2_TI1S); +} + +/** + * @brief Disconnect the TIMx_CH1, CH2 and CH3 pins from the TI1 input. + * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an XOR input. + * @rmtoll CR2 TI1S LL_TIM_IC_DisableXORCombination + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_IC_DisableXORCombination(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->CR2, TIM_CR2_TI1S); +} + +/** + * @brief Indicates whether the TIMx_CH1, CH2 and CH3 pins are connectected to the TI1 input. + * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an XOR input. + * @rmtoll CR2 TI1S LL_TIM_IC_IsEnabledXORCombination + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IC_IsEnabledXORCombination(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->CR2, TIM_CR2_TI1S) == (TIM_CR2_TI1S)) ? 1UL : 0UL); +} + +/** + * @brief Get captured value for input channel 1. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not + * input channel 1 is supported by a timer instance. + * @rmtoll CCR1 CCR1 LL_TIM_IC_GetCaptureCH1 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH1(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR1)); +} + +/** + * @brief Get captured value for input channel 2. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not + * input channel 2 is supported by a timer instance. + * @rmtoll CCR2 CCR2 LL_TIM_IC_GetCaptureCH2 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH2(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR2)); +} + +/** + * @brief Get captured value for input channel 3. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not + * input channel 3 is supported by a timer instance. + * @rmtoll CCR3 CCR3 LL_TIM_IC_GetCaptureCH3 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH3(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR3)); +} + +/** + * @brief Get captured value for input channel 4. + * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. + * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports a 32 bits counter. + * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not + * input channel 4 is supported by a timer instance. + * @rmtoll CCR4 CCR4 LL_TIM_IC_GetCaptureCH4 + * @param TIMx Timer instance + * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) + */ +static inline uint32_t LL_TIM_IC_GetCaptureCH4(const TIM_TypeDef *TIMx) +{ + return (uint32_t)(READ_REG(TIMx->CCR4)); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Clock_Selection Counter clock selection + * @{ + */ +/** + * @brief Enable external clock mode 2. + * @note When external clock mode 2 is enabled the counter is clocked by any active edge on the ETRF signal. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR ECE LL_TIM_EnableExternalClock + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableExternalClock(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->SMCR, TIM_SMCR_ECE); +} + +/** + * @brief Disable external clock mode 2. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR ECE LL_TIM_DisableExternalClock + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableExternalClock(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->SMCR, TIM_SMCR_ECE); +} + +/** + * @brief Indicate whether external clock mode 2 is enabled. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR ECE LL_TIM_IsEnabledExternalClock + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledExternalClock(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SMCR, TIM_SMCR_ECE) == (TIM_SMCR_ECE)) ? 1UL : 0UL); +} + +/** + * @brief Set the clock source of the counter clock. + * @note when selected clock source is external clock mode 1, the timer input + * the external clock is applied is selected by calling the @ref LL_TIM_SetTriggerInput() + * function. This timer input must be configured by calling + * the @ref LL_TIM_IC_Config() function. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE1_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode1. + * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports external clock mode2. + * @rmtoll SMCR SMS LL_TIM_SetClockSource\n + * SMCR ECE LL_TIM_SetClockSource + * @param TIMx Timer instance + * @param ClockSource This parameter can be one of the following values: + * @arg @ref LL_TIM_CLOCKSOURCE_INTERNAL + * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE1 + * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE2 + * @retval None + */ +static inline void LL_TIM_SetClockSource(TIM_TypeDef *TIMx, uint32_t ClockSource) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS | TIM_SMCR_ECE, ClockSource); +} + +/** + * @brief Set the encoder interface mode. + * @note Macro IS_TIM_ENCODER_INTERFACE_INSTANCE(TIMx) can be used to check + * whether or not a timer instance supports the encoder mode. + * @rmtoll SMCR SMS LL_TIM_SetEncoderMode + * @param TIMx Timer instance + * @param EncoderMode This parameter can be one of the following values: + * @arg @ref LL_TIM_ENCODERMODE_X2_TI1 + * @arg @ref LL_TIM_ENCODERMODE_X2_TI2 + * @arg @ref LL_TIM_ENCODERMODE_X4_TI12 + * @retval None + */ +static inline void LL_TIM_SetEncoderMode(TIM_TypeDef *TIMx, uint32_t EncoderMode) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, EncoderMode); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Timer_Synchronization Timer synchronisation configuration + * @{ + */ +/** + * @brief Set the trigger output (TRGO) used for timer synchronization . + * @note Macro IS_TIM_MASTER_INSTANCE(TIMx) can be used to check + * whether or not a timer instance can operate as a master timer. + * @rmtoll CR2 MMS LL_TIM_SetTriggerOutput + * @param TIMx Timer instance + * @param TimerSynchronization This parameter can be one of the following values: + * @arg @ref LL_TIM_TRGO_RESET + * @arg @ref LL_TIM_TRGO_ENABLE + * @arg @ref LL_TIM_TRGO_UPDATE + * @arg @ref LL_TIM_TRGO_CC1IF + * @arg @ref LL_TIM_TRGO_OC1REF + * @arg @ref LL_TIM_TRGO_OC2REF + * @arg @ref LL_TIM_TRGO_OC3REF + * @arg @ref LL_TIM_TRGO_OC4REF + * @retval None + */ +static inline void LL_TIM_SetTriggerOutput(TIM_TypeDef *TIMx, uint32_t TimerSynchronization) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_MMS, TimerSynchronization); +} + +/** + * @brief Set the trigger output 2 (TRGO2) used for ADC synchronization . + * @note Macro IS_TIM_TRGO2_INSTANCE(TIMx) can be used to check + * whether or not a timer instance can be used for ADC synchronization. + * @rmtoll CR2 MMS2 LL_TIM_SetTriggerOutput2 + * @param TIMx Timer Instance + * @param ADCSynchronization This parameter can be one of the following values: + * @arg @ref LL_TIM_TRGO2_RESET + * @arg @ref LL_TIM_TRGO2_ENABLE + * @arg @ref LL_TIM_TRGO2_UPDATE + * @arg @ref LL_TIM_TRGO2_CC1F + * @arg @ref LL_TIM_TRGO2_OC1 + * @arg @ref LL_TIM_TRGO2_OC2 + * @arg @ref LL_TIM_TRGO2_OC3 + * @arg @ref LL_TIM_TRGO2_OC4 + * @arg @ref LL_TIM_TRGO2_OC5 + * @arg @ref LL_TIM_TRGO2_OC6 + * @arg @ref LL_TIM_TRGO2_OC4_RISINGFALLING + * @arg @ref LL_TIM_TRGO2_OC6_RISINGFALLING + * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_RISING + * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_FALLING + * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_RISING + * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_FALLING + * @retval None + */ +static inline void LL_TIM_SetTriggerOutput2(TIM_TypeDef *TIMx, uint32_t ADCSynchronization) +{ + MODIFY_REG(TIMx->CR2, TIM_CR2_MMS2, ADCSynchronization); +} + +/** + * @brief Set the synchronization mode of a slave timer. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR SMS LL_TIM_SetSlaveMode + * @param TIMx Timer instance + * @param SlaveMode This parameter can be one of the following values: + * @arg @ref LL_TIM_SLAVEMODE_DISABLED + * @arg @ref LL_TIM_SLAVEMODE_RESET + * @arg @ref LL_TIM_SLAVEMODE_GATED + * @arg @ref LL_TIM_SLAVEMODE_TRIGGER + * @arg @ref LL_TIM_SLAVEMODE_COMBINED_RESETTRIGGER + * @retval None + */ +static inline void LL_TIM_SetSlaveMode(TIM_TypeDef *TIMx, uint32_t SlaveMode) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, SlaveMode); +} + +/** + * @brief Set the selects the trigger input to be used to synchronize the counter. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR TS LL_TIM_SetTriggerInput + * @param TIMx Timer instance + * @param TriggerInput This parameter can be one of the following values: + * @arg @ref LL_TIM_TS_ITR0 + * @arg @ref LL_TIM_TS_ITR1 + * @arg @ref LL_TIM_TS_ITR2 + * @arg @ref LL_TIM_TS_ITR3 + * @arg @ref LL_TIM_TS_ITR4 + * @arg @ref LL_TIM_TS_ITR5 + * @arg @ref LL_TIM_TS_ITR6 + * @arg @ref LL_TIM_TS_ITR7 + * @arg @ref LL_TIM_TS_ITR8 (*) + * @arg @ref LL_TIM_TS_ITR9 (*) + * @arg @ref LL_TIM_TS_ITR10 (*) + * @arg @ref LL_TIM_TS_ITR11 (*) + * @arg @ref LL_TIM_TS_ITR12 (*) + * @arg @ref LL_TIM_TS_ITR13 (*) + * @arg @ref LL_TIM_TS_TI1F_ED + * @arg @ref LL_TIM_TS_TI1FP1 + * @arg @ref LL_TIM_TS_TI2FP2 + * @arg @ref LL_TIM_TS_ETRF + * + * (*) Value not defined in all devices. + * @retval None + */ +static inline void LL_TIM_SetTriggerInput(TIM_TypeDef *TIMx, uint32_t TriggerInput) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_TS, TriggerInput); +} + +/** + * @brief Enable the Master/Slave mode. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR MSM LL_TIM_EnableMasterSlaveMode + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableMasterSlaveMode(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->SMCR, TIM_SMCR_MSM); +} + +/** + * @brief Disable the Master/Slave mode. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR MSM LL_TIM_DisableMasterSlaveMode + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableMasterSlaveMode(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->SMCR, TIM_SMCR_MSM); +} + +/** + * @brief Indicates whether the Master/Slave mode is enabled. + * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not + * a timer instance can operate as a slave timer. + * @rmtoll SMCR MSM LL_TIM_IsEnabledMasterSlaveMode + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledMasterSlaveMode(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SMCR, TIM_SMCR_MSM) == (TIM_SMCR_MSM)) ? 1UL : 0UL); +} + +/** + * @brief Configure the external trigger (ETR) input. + * @note Macro IS_TIM_ETR_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides an external trigger input. + * @rmtoll SMCR ETP LL_TIM_ConfigETR\n + * SMCR ETPS LL_TIM_ConfigETR\n + * SMCR ETF LL_TIM_ConfigETR + * @param TIMx Timer instance + * @param ETRPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_ETR_POLARITY_NONINVERTED + * @arg @ref LL_TIM_ETR_POLARITY_INVERTED + * @param ETRPrescaler This parameter can be one of the following values: + * @arg @ref LL_TIM_ETR_PRESCALER_DIV1 + * @arg @ref LL_TIM_ETR_PRESCALER_DIV2 + * @arg @ref LL_TIM_ETR_PRESCALER_DIV4 + * @arg @ref LL_TIM_ETR_PRESCALER_DIV8 + * @param ETRFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_ETR_FILTER_FDIV1 + * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_ConfigETR(TIM_TypeDef *TIMx, uint32_t ETRPolarity, uint32_t ETRPrescaler, + uint32_t ETRFilter) +{ + MODIFY_REG(TIMx->SMCR, TIM_SMCR_ETP | TIM_SMCR_ETPS | TIM_SMCR_ETF, ETRPolarity | ETRPrescaler | ETRFilter); +} + +/** + * @brief Select the external trigger (ETR) input source. + * @note Macro IS_TIM_ETRSEL_INSTANCE(TIMx) can be used to check whether or + * not a timer instance supports ETR source selection. + * @rmtoll AF1 ETRSEL LL_TIM_SetETRSource + * @param TIMx Timer instance + * @param ETRSource This parameter can be one of the following values: + * For TIM1, the parameter is one of the following values: + * @arg LL_TIM_TIM1_ETRSOURCE_GPIO: TIM1_ETR is connected to GPIO + * @arg LL_TIM_TIM1_ETRSOURCE_COMP1: TIM1_ETR is connected to COMP1 output + * @arg LL_TIM_TIM1_ETRSOURCE_COMP2: TIM1_ETR is connected to COMP2 output + * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD1: TIM1_ETR is connected to ADC1 AWD1 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD2: TIM1_ETR is connected to ADC1 AWD2 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD3: TIM1_ETR is connected to ADC1 AWD3 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD1: TIM1_ETR is connected to ADC3 AWD1 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD2: TIM1_ETR is connected to ADC3 AWD2 + * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD3: TIM1_ETR is connected to ADC3 AWD3 + * + * For TIM2, the parameter is one of the following values: + * @arg LL_TIM_TIM2_ETRSOURCE_GPIO: TIM2_ETR is connected to GPIO + * @arg LL_TIM_TIM2_ETRSOURCE_COMP1: TIM2_ETR is connected to COMP1 output + * @arg LL_TIM_TIM2_ETRSOURCE_COMP2: TIM2_ETR is connected to COMP2 output + * @arg LL_TIM_TIM2_ETRSOURCE_LSE: TIM2_ETR is connected to LSE + * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSA: TIM2_ETR is connected to SAI1 FS_A + * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSB: TIM2_ETR is connected to SAI1 FS_B + * + * For TIM3, the parameter is one of the following values: + * @arg LL_TIM_TIM3_ETRSOURCE_GPIO: TIM3_ETR is connected to GPIO + * @arg LL_TIM_TIM3_ETRSOURCE_COMP1: TIM3_ETR is connected to COMP1 output + * + * For TIM5, the parameter is one of the following values: + * @arg LL_TIM_TIM5_ETRSOURCE_GPIO: TIM5_ETR is connected to GPIO + * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSA: TIM5_ETR is connected to SAI2 FS_A (*) + * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSB: TIM5_ETR is connected to SAI2 FS_B (*) + * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSA: TIM5_ETR is connected to SAI2 FS_A (*) + * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSB: TIM5_ETR is connected to SAI2 FS_B (*) + * + * For TIM8, the parameter is one of the following values: + * @arg LL_TIM_TIM8_ETRSOURCE_GPIO: TIM8_ETR is connected to GPIO + * @arg LL_TIM_TIM8_ETRSOURCE_COMP1: TIM8_ETR is connected to COMP1 output + * @arg LL_TIM_TIM8_ETRSOURCE_COMP2: TIM8_ETR is connected to COMP2 output + * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD1: TIM8_ETR is connected to ADC2 AWD1 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD2: TIM8_ETR is connected to ADC2 AWD2 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD3: TIM8_ETR is connected to ADC2 AWD3 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD1: TIM8_ETR is connected to ADC3 AWD1 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD2: TIM8_ETR is connected to ADC3 AWD2 + * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD3: TIM8_ETR is connected to ADC3 AWD3 + * + * For TIM23, the parameter is one of the following values: (*) + * @arg LL_TIM_TIM23_ETRSOURCE_GPIO TIM23_ETR is connected to GPIO + * @arg LL_TIM_TIM23_ETRSOURCE_COMP1 TIM23_ETR is connected to COMP1 output + * @arg LL_TIM_TIM23_ETRSOURCE_COMP2 TIM23_ETR is connected to COMP2 output + * + * For TIM24, the parameter is one of the following values: (*) + * @arg LL_TIM_TIM24_ETRSOURCE_GPIO TIM24_ETR is connected to GPIO + * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSA TIM24_ETR is connected to SAI4 FS_A + * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSB TIM24_ETR is connected to SAI4 FS_B + * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSA TIM24_ETR is connected to SAI1 FS_A + * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSB TIM24_ETR is connected to SAI1 FS_B + * + * (*) Value not defined in all devices. + * @retval None + */ +static inline void LL_TIM_SetETRSource(TIM_TypeDef *TIMx, uint32_t ETRSource) +{ + MODIFY_REG(TIMx->AF1, TIMx_AF1_ETRSEL, ETRSource); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Break_Function Break function configuration + * @{ + */ +/** + * @brief Enable the break function. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR BKE LL_TIM_EnableBRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableBRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BKE); +} + +/** + * @brief Disable the break function. + * @rmtoll BDTR BKE LL_TIM_DisableBRK + * @param TIMx Timer instance + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @retval None + */ +static inline void LL_TIM_DisableBRK(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BKE); +} + +#if defined(TIM_BDTR_BKBID) +/** + * @brief Configure the break input. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @note Bidirectional mode is only supported by advanced timer instances. + * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not + * a timer instance is an advanced-control timer. + * @note In bidirectional mode (BKBID bit set), the Break input is configured both + * in input mode and in open drain output mode. Any active Break event will + * assert a low logic level on the Break input to indicate an internal break + * event to external devices. + * @note When bidirectional mode isn't supported, BreakAFMode must be set to + * LL_TIM_BREAK_AFMODE_INPUT. + * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n + * BDTR BKF LL_TIM_ConfigBRK\n + * BDTR BKBID LL_TIM_ConfigBRK + * @param TIMx Timer instance + * @param BreakPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_POLARITY_LOW + * @arg @ref LL_TIM_BREAK_POLARITY_HIGH + * @param BreakFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 + * @param BreakAFMode This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_AFMODE_INPUT + * @arg @ref LL_TIM_BREAK_AFMODE_BIDIRECTIONAL + * @retval None + */ +static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, uint32_t BreakFilter, + uint32_t BreakAFMode) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF | TIM_BDTR_BKBID, BreakPolarity | BreakFilter | BreakAFMode); +} + +#else +/** + * @brief Configure the break input. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n + * BDTR BKF LL_TIM_ConfigBRK + * @param TIMx Timer instance + * @param BreakPolarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_POLARITY_LOW + * @arg @ref LL_TIM_BREAK_POLARITY_HIGH + * @param BreakFilter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, + uint32_t BreakFilter) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF, BreakPolarity | BreakFilter); +} + +#endif /* TIM_BDTR_BKBID */ +#if defined(TIM_BDTR_BKBID) +/** + * @brief Disarm the break input (when it operates in bidirectional mode). + * @note The break input can be disarmed only when it is configured in + * bidirectional mode and when when MOE is reset. + * @note Purpose is to be able to have the input voltage back to high-state, + * whatever the time constant on the output . + * @rmtoll BDTR BKDSRM LL_TIM_DisarmBRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisarmBRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BKDSRM); +} + +#endif /*TIM_BDTR_BKBID */ +/** + * @brief Enable the break 2 function. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @rmtoll BDTR BK2E LL_TIM_EnableBRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableBRK2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BK2E); +} + +/** + * @brief Disable the break 2 function. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @rmtoll BDTR BK2E LL_TIM_DisableBRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableBRK2(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BK2E); +} + +#if defined(TIM_BDTR_BKBID) +/** + * @brief Configure the break 2 input. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @note Bidirectional mode is only supported by advanced timer instances. + * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not + * a timer instance is an advanced-control timer. + * @note In bidirectional mode (BK2BID bit set), the Break 2 input is configured both + * in input mode and in open drain output mode. Any active Break event will + * assert a low logic level on the Break 2 input to indicate an internal break + * event to external devices. + * @note When bidirectional mode isn't supported, Break2AFMode must be set to + * LL_TIM_BREAK2_AFMODE_INPUT. + * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n + * BDTR BK2F LL_TIM_ConfigBRK2\n + * BDTR BK2BID LL_TIM_ConfigBRK2 + * @param TIMx Timer instance + * @param Break2Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_POLARITY_LOW + * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH + * @param Break2Filter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 + * @param Break2AFMode This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_AFMODE_INPUT + * @arg @ref LL_TIM_BREAK2_AFMODE_BIDIRECTIONAL + * @retval None + */ +static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter, + uint32_t Break2AFMode) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F | TIM_BDTR_BK2BID, Break2Polarity | Break2Filter | Break2AFMode); +} + +#else +/** + * @brief Configure the break 2 input. + * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a second break input. + * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n + * BDTR BK2F LL_TIM_ConfigBRK2 + * @param TIMx Timer instance + * @param Break2Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_POLARITY_LOW + * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH + * @param Break2Filter This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 + * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 + * @retval None + */ +static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F, Break2Polarity | Break2Filter); +} + +#endif /*TIM_BDTR_BKBID */ +#if defined(TIM_BDTR_BKBID) +/** + * @brief Disarm the break 2 input (when it operates in bidirectional mode). + * @note The break 2 input can be disarmed only when it is configured in + * bidirectional mode and when when MOE is reset. + * @note Purpose is to be able to have the input voltage back to high-state, + * whatever the time constant on the output. + * @rmtoll BDTR BK2DSRM LL_TIM_DisarmBRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisarmBRK2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_BK2DSRM); +} + +#endif /*TIM_BDTR_BKBID */ +/** + * @brief Select the outputs off state (enabled v.s. disabled) in Idle and Run modes. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR OSSI LL_TIM_SetOffStates\n + * BDTR OSSR LL_TIM_SetOffStates + * @param TIMx Timer instance + * @param OffStateIdle This parameter can be one of the following values: + * @arg @ref LL_TIM_OSSI_DISABLE + * @arg @ref LL_TIM_OSSI_ENABLE + * @param OffStateRun This parameter can be one of the following values: + * @arg @ref LL_TIM_OSSR_DISABLE + * @arg @ref LL_TIM_OSSR_ENABLE + * @retval None + */ +static inline void LL_TIM_SetOffStates(TIM_TypeDef *TIMx, uint32_t OffStateIdle, uint32_t OffStateRun) +{ + MODIFY_REG(TIMx->BDTR, TIM_BDTR_OSSI | TIM_BDTR_OSSR, OffStateIdle | OffStateRun); +} + +/** + * @brief Enable automatic output (MOE can be set by software or automatically when a break input is active). + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR AOE LL_TIM_EnableAutomaticOutput + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableAutomaticOutput(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_AOE); +} + +/** + * @brief Disable automatic output (MOE can be set only by software). + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR AOE LL_TIM_DisableAutomaticOutput + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableAutomaticOutput(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_AOE); +} + +/** + * @brief Indicate whether automatic output is enabled. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR AOE LL_TIM_IsEnabledAutomaticOutput + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledAutomaticOutput(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->BDTR, TIM_BDTR_AOE) == (TIM_BDTR_AOE)) ? 1UL : 0UL); +} + +/** + * @brief Enable the outputs (set the MOE bit in TIMx_BDTR register). + * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by + * software and is reset in case of break or break2 event + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR MOE LL_TIM_EnableAllOutputs + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableAllOutputs(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->BDTR, TIM_BDTR_MOE); +} + +/** + * @brief Disable the outputs (reset the MOE bit in TIMx_BDTR register). + * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by + * software and is reset in case of break or break2 event. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR MOE LL_TIM_DisableAllOutputs + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableAllOutputs(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->BDTR, TIM_BDTR_MOE); +} + +/** + * @brief Indicates whether outputs are enabled. + * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not + * a timer instance provides a break input. + * @rmtoll BDTR MOE LL_TIM_IsEnabledAllOutputs + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledAllOutputs(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->BDTR, TIM_BDTR_MOE) == (TIM_BDTR_MOE)) ? 1UL : 0UL); +} + +#if defined(TIM_BREAK_INPUT_SUPPORT) +/** + * @brief Enable the signals connected to the designated timer break input. + * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether + * or not a timer instance allows for break input selection. + * @rmtoll AF1 BKINE LL_TIM_EnableBreakInputSource\n + * AF1 BKCMP1E LL_TIM_EnableBreakInputSource\n + * AF1 BKCMP2E LL_TIM_EnableBreakInputSource\n + * AF1 BKDF1BK0E LL_TIM_EnableBreakInputSource\n + * AF2 BK2INE LL_TIM_EnableBreakInputSource\n + * AF2 BK2CMP1E LL_TIM_EnableBreakInputSource\n + * AF2 BK2CMP2E LL_TIM_EnableBreakInputSource\n + * AF2 BK2DF1BK1E LL_TIM_EnableBreakInputSource + * @param TIMx Timer instance + * @param BreakInput This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_INPUT_BKIN + * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 + * @param Source This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_SOURCE_BKIN + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 + * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK + * @retval None + */ +static inline void LL_TIM_EnableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) +{ + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); + SET_BIT(*pReg, Source); +} + +/** + * @brief Disable the signals connected to the designated timer break input. + * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether + * or not a timer instance allows for break input selection. + * @rmtoll AF1 BKINE LL_TIM_DisableBreakInputSource\n + * AF1 BKCMP1E LL_TIM_DisableBreakInputSource\n + * AF1 BKCMP2E LL_TIM_DisableBreakInputSource\n + * AF1 BKDF1BK0E LL_TIM_DisableBreakInputSource\n + * AF2 BK2INE LL_TIM_DisableBreakInputSource\n + * AF2 BK2CMP1E LL_TIM_DisableBreakInputSource\n + * AF2 BK2CMP2E LL_TIM_DisableBreakInputSource\n + * AF2 BK2DF1BK1E LL_TIM_DisableBreakInputSource + * @param TIMx Timer instance + * @param BreakInput This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_INPUT_BKIN + * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 + * @param Source This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_SOURCE_BKIN + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 + * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK + * @retval None + */ +static inline void LL_TIM_DisableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) +{ + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); + CLEAR_BIT(*pReg, Source); +} + +/** + * @brief Set the polarity of the break signal for the timer break input. + * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether + * or not a timer instance allows for break input selection. + * @rmtoll AF1 BKINP LL_TIM_SetBreakInputSourcePolarity\n + * AF1 BKCMP1P LL_TIM_SetBreakInputSourcePolarity\n + * AF1 BKCMP2P LL_TIM_SetBreakInputSourcePolarity\n + * AF2 BK2INP LL_TIM_SetBreakInputSourcePolarity\n + * AF2 BK2CMP1P LL_TIM_SetBreakInputSourcePolarity\n + * AF2 BK2CMP2P LL_TIM_SetBreakInputSourcePolarity + * @param TIMx Timer instance + * @param BreakInput This parameter can be one of the following values: + * @arg @ref LL_TIM_BREAK_INPUT_BKIN + * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 + * @param Source This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_SOURCE_BKIN + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 + * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 + * @param Polarity This parameter can be one of the following values: + * @arg @ref LL_TIM_BKIN_POLARITY_LOW + * @arg @ref LL_TIM_BKIN_POLARITY_HIGH + * @retval None + */ +static inline void LL_TIM_SetBreakInputSourcePolarity(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source, + uint32_t Polarity) +{ + __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); + MODIFY_REG(*pReg, (TIMx_AF1_BKINP << TIM_POSITION_BRK_SOURCE), (Polarity << TIM_POSITION_BRK_SOURCE)); +} +#endif /* TIM_BREAK_INPUT_SUPPORT */ +/** + * @} + */ + +/** @defgroup TIM_LL_EF_DMA_Burst_Mode DMA burst mode configuration + * @{ + */ +/** + * @brief Configures the timer DMA burst feature. + * @note Macro IS_TIM_DMABURST_INSTANCE(TIMx) can be used to check whether or + * not a timer instance supports the DMA burst mode. + * @rmtoll DCR DBL LL_TIM_ConfigDMABurst\n + * DCR DBA LL_TIM_ConfigDMABurst + * @param TIMx Timer instance + * @param DMABurstBaseAddress This parameter can be one of the following values: + * @arg @ref LL_TIM_DMABURST_BASEADDR_CR1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CR2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_SMCR + * @arg @ref LL_TIM_DMABURST_BASEADDR_DIER + * @arg @ref LL_TIM_DMABURST_BASEADDR_SR + * @arg @ref LL_TIM_DMABURST_BASEADDR_EGR + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCER + * @arg @ref LL_TIM_DMABURST_BASEADDR_CNT + * @arg @ref LL_TIM_DMABURST_BASEADDR_PSC + * @arg @ref LL_TIM_DMABURST_BASEADDR_ARR + * @arg @ref LL_TIM_DMABURST_BASEADDR_RCR + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR3 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR4 + * @arg @ref LL_TIM_DMABURST_BASEADDR_BDTR + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR3 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR5 + * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR6 + * @arg @ref LL_TIM_DMABURST_BASEADDR_AF1 + * @arg @ref LL_TIM_DMABURST_BASEADDR_AF2 + * @arg @ref LL_TIM_DMABURST_BASEADDR_TISEL + * + * @param DMABurstLength This parameter can be one of the following values: + * @arg @ref LL_TIM_DMABURST_LENGTH_1TRANSFER + * @arg @ref LL_TIM_DMABURST_LENGTH_2TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_3TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_4TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_5TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_6TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_7TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_8TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_9TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_10TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_11TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_12TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_13TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_14TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_15TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_16TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_17TRANSFERS + * @arg @ref LL_TIM_DMABURST_LENGTH_18TRANSFERS + * @retval None + */ +static inline void LL_TIM_ConfigDMABurst(TIM_TypeDef *TIMx, uint32_t DMABurstBaseAddress, uint32_t DMABurstLength) +{ + MODIFY_REG(TIMx->DCR, (TIM_DCR_DBL | TIM_DCR_DBA), (DMABurstBaseAddress | DMABurstLength)); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_Timer_Inputs_Remapping Timer input remapping + * @{ + */ +/** + * @brief Remap TIM inputs (input channel, internal/external triggers). + * @note Macro IS_TIM_REMAP_INSTANCE(TIMx) can be used to check whether or not + * a some timer inputs can be remapped. + * TIM1: one of the following values: + * @arg LL_TIM_TIM1_TI1_RMP_GPIO: TIM1 TI1 is connected to GPIO + * @arg LL_TIM_TIM1_TI1_RMP_COMP1: TIM1 TI1 is connected to COMP1 output + * + * TIM2: one of the following values: + * @arg LL_TIM_TIM2_TI4_RMP_GPIO: TIM2 TI4 is connected to GPIO + * @arg LL_TIM_TIM2_TI4_RMP_COMP1: TIM2 TI4 is connected to COMP1 output + * @arg LL_TIM_TIM2_TI4_RMP_COMP2: TIM2 TI4 is connected to COMP2 output + * @arg LL_TIM_TIM2_TI4_RMP_COMP1_COMP2: TIM2 TI4 is connected to logical OR between COMP1 and COMP2 output + * + * TIM3: one of the following values: + * @arg LL_TIM_TIM3_TI1_RMP_GPIO: TIM3 TI1 is connected to GPIO + * @arg LL_TIM_TIM3_TI1_RMP_COMP1: TIM3 TI1 is connected to COMP1 output + * @arg LL_TIM_TIM3_TI1_RMP_COMP2: TIM3 TI1 is connected to COMP2 output + * @arg LL_TIM_TIM3_TI1_RMP_COMP1_COMP2: TIM3 TI1 is connected to logical OR between COMP1 and COMP2 output + * + * TIM5: one of the following values: + * @arg LL_TIM_TIM5_TI1_RMP_GPIO: TIM5 TI1 is connected to GPIO + * @arg LL_TIM_TIM5_TI1_RMP_CAN_TMP: TIM5 TI1 is connected to CAN TMP + * @arg LL_TIM_TIM5_TI1_RMP_CAN_RTP: TIM5 TI1 is connected to CAN RTP + * + * TIM8: one of the following values: + * @arg LL_TIM_TIM8_TI1_RMP_GPIO: TIM8 TI1 is connected to GPIO + * @arg LL_TIM_TIM8_TI1_RMP_COMP2: TIM8 TI1 is connected to COMP2 output + * + * TIM12: one of the following values: (*) + * @arg LL_TIM_TIM12_TI1_RMP_GPIO: TIM12 TI1 is connected to GPIO + * @arg LL_TIM_TIM12_TI1_RMP_SPDIF_FS: TIM12 TI1 is connected to SPDIF FS + * + * TIM15: one of the following values: + * @arg LL_TIM_TIM15_TI1_RMP_GPIO: TIM15 TI1 is connected to GPIO + * @arg LL_TIM_TIM15_TI1_RMP_TIM2: TIM15 TI1 is connected to TIM2 CH1 + * @arg LL_TIM_TIM15_TI1_RMP_TIM3: TIM15 TI1 is connected to TIM3 CH1 + * @arg LL_TIM_TIM15_TI1_RMP_TIM4: TIM15 TI1 is connected to TIM4 CH1 + * @arg LL_TIM_TIM15_TI1_RMP_LSE: TIM15 TI1 is connected to LSE + * @arg LL_TIM_TIM15_TI1_RMP_CSI: TIM15 TI1 is connected to CSI + * @arg LL_TIM_TIM15_TI1_RMP_MCO2: TIM15 TI1 is connected to MCO2 + * @arg LL_TIM_TIM15_TI2_RMP_GPIO: TIM15 TI2 is connected to GPIO + * @arg LL_TIM_TIM15_TI2_RMP_TIM2: TIM15 TI2 is connected to TIM2 CH2 + * @arg LL_TIM_TIM15_TI2_RMP_TIM3: TIM15 TI2 is connected to TIM3 CH2 + * @arg LL_TIM_TIM15_TI2_RMP_TIM4: TIM15 TI2 is connected to TIM4 CH2 + * + * TIM16: one of the following values: + * @arg LL_TIM_TIM16_TI1_RMP_GPIO: TIM16 TI1 is connected to GPIO + * @arg LL_TIM_TIM16_TI1_RMP_LSI: TIM16 TI1 is connected to LSI + * @arg LL_TIM_TIM16_TI1_RMP_LSE: TIM16 TI1 is connected to LSE + * @arg LL_TIM_TIM16_TI1_RMP_RTC: TIM16 TI1 is connected to RTC wakeup interrupt + * + * TIM17: one of the following values: + * @arg LL_TIM_TIM17_TI1_RMP_GPIO: TIM17 TI1 is connected to GPIO + * @arg LL_TIM_TIM17_TI1_RMP_SPDIF_FS: TIM17 TI1 is connected to SPDIF FS (*) + * @arg LL_TIM_TIM17_TI1_RMP_HSE_1MHZ: TIM17 TI1 is connected to HSE 1MHz + * @arg LL_TIM_TIM17_TI1_RMP_MCO1: TIM17 TI1 is connected to MCO1 + * + * TIM23: one of the following values: (*) + * @arg LL_TIM_TIM23_TI4_RMP_GPIO TIM23_TI4 is connected to GPIO + * @arg LL_TIM_TIM23_TI4_RMP_COMP1 TIM23_TI4 is connected to COMP1 output + * @arg LL_TIM_TIM23_TI4_RMP_COMP2 TIM23_TI4 is connected to COMP2 output + * @arg LL_TIM_TIM23_TI4_RMP_COMP1_COMP2 TIM23_TI4 is connected to COMP2 output + * + * TIM24: one of the following values: (*) + * @arg LL_TIM_TIM24_TI1_RMP_GPIO TIM24_TI1 is connected to GPIO + * @arg LL_TIM_TIM24_TI1_RMP_CAN_TMP TIM24_TI1 is connected to CAN_TMP + * @arg LL_TIM_TIM24_TI1_RMP_CAN_RTP TIM24_TI1 is connected to CAN_RTP + * @arg LL_TIM_TIM24_TI1_RMP_CAN_SOC TIM24_TI1 is connected to CAN_SOC + * + * (*) Value not defined in all devices. \n + * @retval None + */ +static inline void LL_TIM_SetRemap(TIM_TypeDef *TIMx, uint32_t Remap) +{ + MODIFY_REG(TIMx->TISEL, (TIM_TISEL_TI1SEL | TIM_TISEL_TI2SEL | TIM_TISEL_TI3SEL | TIM_TISEL_TI4SEL), Remap); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_FLAG_Management FLAG-Management + * @{ + */ +/** + * @brief Clear the update interrupt flag (UIF). + * @rmtoll SR UIF LL_TIM_ClearFlag_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_UPDATE(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_UIF)); +} + +/** + * @brief Indicate whether update interrupt flag (UIF) is set (update interrupt is pending). + * @rmtoll SR UIF LL_TIM_IsActiveFlag_UPDATE + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_UPDATE(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_UIF) == (TIM_SR_UIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 1 interrupt flag (CC1F). + * @rmtoll SR CC1IF LL_TIM_ClearFlag_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC1(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC1IF)); +} + +/** + * @brief Indicate whether Capture/Compare 1 interrupt flag (CC1F) is set (Capture/Compare 1 interrupt is pending). + * @rmtoll SR CC1IF LL_TIM_IsActiveFlag_CC1 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC1(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC1IF) == (TIM_SR_CC1IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 2 interrupt flag (CC2F). + * @rmtoll SR CC2IF LL_TIM_ClearFlag_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC2(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC2IF)); +} + +/** + * @brief Indicate whether Capture/Compare 2 interrupt flag (CC2F) is set (Capture/Compare 2 interrupt is pending). + * @rmtoll SR CC2IF LL_TIM_IsActiveFlag_CC2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC2IF) == (TIM_SR_CC2IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 3 interrupt flag (CC3F). + * @rmtoll SR CC3IF LL_TIM_ClearFlag_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC3(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC3IF)); +} + +/** + * @brief Indicate whether Capture/Compare 3 interrupt flag (CC3F) is set (Capture/Compare 3 interrupt is pending). + * @rmtoll SR CC3IF LL_TIM_IsActiveFlag_CC3 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC3(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC3IF) == (TIM_SR_CC3IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 4 interrupt flag (CC4F). + * @rmtoll SR CC4IF LL_TIM_ClearFlag_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC4(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC4IF)); +} + +/** + * @brief Indicate whether Capture/Compare 4 interrupt flag (CC4F) is set (Capture/Compare 4 interrupt is pending). + * @rmtoll SR CC4IF LL_TIM_IsActiveFlag_CC4 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC4(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC4IF) == (TIM_SR_CC4IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 5 interrupt flag (CC5F). + * @rmtoll SR CC5IF LL_TIM_ClearFlag_CC5 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC5(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC5IF)); +} + +/** + * @brief Indicate whether Capture/Compare 5 interrupt flag (CC5F) is set (Capture/Compare 5 interrupt is pending). + * @rmtoll SR CC5IF LL_TIM_IsActiveFlag_CC5 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC5(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC5IF) == (TIM_SR_CC5IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 6 interrupt flag (CC6F). + * @rmtoll SR CC6IF LL_TIM_ClearFlag_CC6 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC6(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC6IF)); +} + +/** + * @brief Indicate whether Capture/Compare 6 interrupt flag (CC6F) is set (Capture/Compare 6 interrupt is pending). + * @rmtoll SR CC6IF LL_TIM_IsActiveFlag_CC6 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC6(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC6IF) == (TIM_SR_CC6IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the commutation interrupt flag (COMIF). + * @rmtoll SR COMIF LL_TIM_ClearFlag_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_COM(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_COMIF)); +} + +/** + * @brief Indicate whether commutation interrupt flag (COMIF) is set (commutation interrupt is pending). + * @rmtoll SR COMIF LL_TIM_IsActiveFlag_COM + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_COM(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_COMIF) == (TIM_SR_COMIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the trigger interrupt flag (TIF). + * @rmtoll SR TIF LL_TIM_ClearFlag_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_TRIG(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_TIF)); +} + +/** + * @brief Indicate whether trigger interrupt flag (TIF) is set (trigger interrupt is pending). + * @rmtoll SR TIF LL_TIM_IsActiveFlag_TRIG + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_TRIG(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_TIF) == (TIM_SR_TIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the break interrupt flag (BIF). + * @rmtoll SR BIF LL_TIM_ClearFlag_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_BRK(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_BIF)); +} + +/** + * @brief Indicate whether break interrupt flag (BIF) is set (break interrupt is pending). + * @rmtoll SR BIF LL_TIM_IsActiveFlag_BRK + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_BRK(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_BIF) == (TIM_SR_BIF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the break 2 interrupt flag (B2IF). + * @rmtoll SR B2IF LL_TIM_ClearFlag_BRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_BRK2(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_B2IF)); +} + +/** + * @brief Indicate whether break 2 interrupt flag (B2IF) is set (break 2 interrupt is pending). + * @rmtoll SR B2IF LL_TIM_IsActiveFlag_BRK2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_BRK2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_B2IF) == (TIM_SR_B2IF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 1 over-capture interrupt flag (CC1OF). + * @rmtoll SR CC1OF LL_TIM_ClearFlag_CC1OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC1OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC1OF)); +} + +/** + * @brief Indicate whether Capture/Compare 1 over-capture interrupt flag (CC1OF) is set + * (Capture/Compare 1 interrupt is pending). + * @rmtoll SR CC1OF LL_TIM_IsActiveFlag_CC1OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC1OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC1OF) == (TIM_SR_CC1OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 2 over-capture interrupt flag (CC2OF). + * @rmtoll SR CC2OF LL_TIM_ClearFlag_CC2OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC2OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC2OF)); +} + +/** + * @brief Indicate whether Capture/Compare 2 over-capture interrupt flag (CC2OF) is set + * (Capture/Compare 2 over-capture interrupt is pending). + * @rmtoll SR CC2OF LL_TIM_IsActiveFlag_CC2OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC2OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC2OF) == (TIM_SR_CC2OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 3 over-capture interrupt flag (CC3OF). + * @rmtoll SR CC3OF LL_TIM_ClearFlag_CC3OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC3OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC3OF)); +} + +/** + * @brief Indicate whether Capture/Compare 3 over-capture interrupt flag (CC3OF) is set + * (Capture/Compare 3 over-capture interrupt is pending). + * @rmtoll SR CC3OF LL_TIM_IsActiveFlag_CC3OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC3OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC3OF) == (TIM_SR_CC3OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the Capture/Compare 4 over-capture interrupt flag (CC4OF). + * @rmtoll SR CC4OF LL_TIM_ClearFlag_CC4OVR + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_CC4OVR(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_CC4OF)); +} + +/** + * @brief Indicate whether Capture/Compare 4 over-capture interrupt flag (CC4OF) is set + * (Capture/Compare 4 over-capture interrupt is pending). + * @rmtoll SR CC4OF LL_TIM_IsActiveFlag_CC4OVR + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_CC4OVR(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_CC4OF) == (TIM_SR_CC4OF)) ? 1UL : 0UL); +} + +/** + * @brief Clear the system break interrupt flag (SBIF). + * @rmtoll SR SBIF LL_TIM_ClearFlag_SYSBRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_ClearFlag_SYSBRK(TIM_TypeDef *TIMx) +{ + WRITE_REG(TIMx->SR, ~(TIM_SR_SBIF)); +} + +/** + * @brief Indicate whether system break interrupt flag (SBIF) is set (system break interrupt is pending). + * @rmtoll SR SBIF LL_TIM_IsActiveFlag_SYSBRK + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsActiveFlag_SYSBRK(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->SR, TIM_SR_SBIF) == (TIM_SR_SBIF)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_IT_Management IT-Management + * @{ + */ +/** + * @brief Enable update interrupt (UIE). + * @rmtoll DIER UIE LL_TIM_EnableIT_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_UPDATE(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_UIE); +} + +/** + * @brief Disable update interrupt (UIE). + * @rmtoll DIER UIE LL_TIM_DisableIT_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_UPDATE(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_UIE); +} + +/** + * @brief Indicates whether the update interrupt (UIE) is enabled. + * @rmtoll DIER UIE LL_TIM_IsEnabledIT_UPDATE + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_UPDATE(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_UIE) == (TIM_DIER_UIE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 1 interrupt (CC1IE). + * @rmtoll DIER CC1IE LL_TIM_EnableIT_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC1(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC1IE); +} + +/** + * @brief Disable capture/compare 1 interrupt (CC1IE). + * @rmtoll DIER CC1IE LL_TIM_DisableIT_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC1(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1IE); +} + +/** + * @brief Indicates whether the capture/compare 1 interrupt (CC1IE) is enabled. + * @rmtoll DIER CC1IE LL_TIM_IsEnabledIT_CC1 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC1(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1IE) == (TIM_DIER_CC1IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 2 interrupt (CC2IE). + * @rmtoll DIER CC2IE LL_TIM_EnableIT_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC2IE); +} + +/** + * @brief Disable capture/compare 2 interrupt (CC2IE). + * @rmtoll DIER CC2IE LL_TIM_DisableIT_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC2(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2IE); +} + +/** + * @brief Indicates whether the capture/compare 2 interrupt (CC2IE) is enabled. + * @rmtoll DIER CC2IE LL_TIM_IsEnabledIT_CC2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2IE) == (TIM_DIER_CC2IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 3 interrupt (CC3IE). + * @rmtoll DIER CC3IE LL_TIM_EnableIT_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC3(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC3IE); +} + +/** + * @brief Disable capture/compare 3 interrupt (CC3IE). + * @rmtoll DIER CC3IE LL_TIM_DisableIT_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC3(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3IE); +} + +/** + * @brief Indicates whether the capture/compare 3 interrupt (CC3IE) is enabled. + * @rmtoll DIER CC3IE LL_TIM_IsEnabledIT_CC3 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC3(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3IE) == (TIM_DIER_CC3IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 4 interrupt (CC4IE). + * @rmtoll DIER CC4IE LL_TIM_EnableIT_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_CC4(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC4IE); +} + +/** + * @brief Disable capture/compare 4 interrupt (CC4IE). + * @rmtoll DIER CC4IE LL_TIM_DisableIT_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_CC4(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4IE); +} + +/** + * @brief Indicates whether the capture/compare 4 interrupt (CC4IE) is enabled. + * @rmtoll DIER CC4IE LL_TIM_IsEnabledIT_CC4 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_CC4(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4IE) == (TIM_DIER_CC4IE)) ? 1UL : 0UL); +} + +/** + * @brief Enable commutation interrupt (COMIE). + * @rmtoll DIER COMIE LL_TIM_EnableIT_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_COM(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_COMIE); +} + +/** + * @brief Disable commutation interrupt (COMIE). + * @rmtoll DIER COMIE LL_TIM_DisableIT_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_COM(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_COMIE); +} + +/** + * @brief Indicates whether the commutation interrupt (COMIE) is enabled. + * @rmtoll DIER COMIE LL_TIM_IsEnabledIT_COM + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_COM(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_COMIE) == (TIM_DIER_COMIE)) ? 1UL : 0UL); +} + +/** + * @brief Enable trigger interrupt (TIE). + * @rmtoll DIER TIE LL_TIM_EnableIT_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_TRIG(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_TIE); +} + +/** + * @brief Disable trigger interrupt (TIE). + * @rmtoll DIER TIE LL_TIM_DisableIT_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_TRIG(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_TIE); +} + +/** + * @brief Indicates whether the trigger interrupt (TIE) is enabled. + * @rmtoll DIER TIE LL_TIM_IsEnabledIT_TRIG + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_TRIG(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_TIE) == (TIM_DIER_TIE)) ? 1UL : 0UL); +} + +/** + * @brief Enable break interrupt (BIE). + * @rmtoll DIER BIE LL_TIM_EnableIT_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableIT_BRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_BIE); +} + +/** + * @brief Disable break interrupt (BIE). + * @rmtoll DIER BIE LL_TIM_DisableIT_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableIT_BRK(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_BIE); +} + +/** + * @brief Indicates whether the break interrupt (BIE) is enabled. + * @rmtoll DIER BIE LL_TIM_IsEnabledIT_BRK + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledIT_BRK(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_BIE) == (TIM_DIER_BIE)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_DMA_Management DMA Management + * @{ + */ +/** + * @brief Enable update DMA request (UDE). + * @rmtoll DIER UDE LL_TIM_EnableDMAReq_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_UPDATE(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_UDE); +} + +/** + * @brief Disable update DMA request (UDE). + * @rmtoll DIER UDE LL_TIM_DisableDMAReq_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_UPDATE(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_UDE); +} + +/** + * @brief Indicates whether the update DMA request (UDE) is enabled. + * @rmtoll DIER UDE LL_TIM_IsEnabledDMAReq_UPDATE + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_UPDATE(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_UDE) == (TIM_DIER_UDE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 1 DMA request (CC1DE). + * @rmtoll DIER CC1DE LL_TIM_EnableDMAReq_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC1(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC1DE); +} + +/** + * @brief Disable capture/compare 1 DMA request (CC1DE). + * @rmtoll DIER CC1DE LL_TIM_DisableDMAReq_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC1(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1DE); +} + +/** + * @brief Indicates whether the capture/compare 1 DMA request (CC1DE) is enabled. + * @rmtoll DIER CC1DE LL_TIM_IsEnabledDMAReq_CC1 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC1(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1DE) == (TIM_DIER_CC1DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 2 DMA request (CC2DE). + * @rmtoll DIER CC2DE LL_TIM_EnableDMAReq_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC2DE); +} + +/** + * @brief Disable capture/compare 2 DMA request (CC2DE). + * @rmtoll DIER CC2DE LL_TIM_DisableDMAReq_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC2(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2DE); +} + +/** + * @brief Indicates whether the capture/compare 2 DMA request (CC2DE) is enabled. + * @rmtoll DIER CC2DE LL_TIM_IsEnabledDMAReq_CC2 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC2(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2DE) == (TIM_DIER_CC2DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 3 DMA request (CC3DE). + * @rmtoll DIER CC3DE LL_TIM_EnableDMAReq_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC3(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC3DE); +} + +/** + * @brief Disable capture/compare 3 DMA request (CC3DE). + * @rmtoll DIER CC3DE LL_TIM_DisableDMAReq_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC3(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3DE); +} + +/** + * @brief Indicates whether the capture/compare 3 DMA request (CC3DE) is enabled. + * @rmtoll DIER CC3DE LL_TIM_IsEnabledDMAReq_CC3 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC3(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3DE) == (TIM_DIER_CC3DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable capture/compare 4 DMA request (CC4DE). + * @rmtoll DIER CC4DE LL_TIM_EnableDMAReq_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_CC4(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_CC4DE); +} + +/** + * @brief Disable capture/compare 4 DMA request (CC4DE). + * @rmtoll DIER CC4DE LL_TIM_DisableDMAReq_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_CC4(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4DE); +} + +/** + * @brief Indicates whether the capture/compare 4 DMA request (CC4DE) is enabled. + * @rmtoll DIER CC4DE LL_TIM_IsEnabledDMAReq_CC4 + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_CC4(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4DE) == (TIM_DIER_CC4DE)) ? 1UL : 0UL); +} + +/** + * @brief Enable commutation DMA request (COMDE). + * @rmtoll DIER COMDE LL_TIM_EnableDMAReq_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_COM(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_COMDE); +} + +/** + * @brief Disable commutation DMA request (COMDE). + * @rmtoll DIER COMDE LL_TIM_DisableDMAReq_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_COM(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_COMDE); +} + +/** + * @brief Indicates whether the commutation DMA request (COMDE) is enabled. + * @rmtoll DIER COMDE LL_TIM_IsEnabledDMAReq_COM + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_COM(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_COMDE) == (TIM_DIER_COMDE)) ? 1UL : 0UL); +} + +/** + * @brief Enable trigger interrupt (TDE). + * @rmtoll DIER TDE LL_TIM_EnableDMAReq_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_EnableDMAReq_TRIG(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->DIER, TIM_DIER_TDE); +} + +/** + * @brief Disable trigger interrupt (TDE). + * @rmtoll DIER TDE LL_TIM_DisableDMAReq_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_DisableDMAReq_TRIG(TIM_TypeDef *TIMx) +{ + CLEAR_BIT(TIMx->DIER, TIM_DIER_TDE); +} + +/** + * @brief Indicates whether the trigger interrupt (TDE) is enabled. + * @rmtoll DIER TDE LL_TIM_IsEnabledDMAReq_TRIG + * @param TIMx Timer instance + * @retval State of bit (1 or 0). + */ +static inline uint32_t LL_TIM_IsEnabledDMAReq_TRIG(const TIM_TypeDef *TIMx) +{ + return ((READ_BIT(TIMx->DIER, TIM_DIER_TDE) == (TIM_DIER_TDE)) ? 1UL : 0UL); +} + +/** + * @} + */ + +/** @defgroup TIM_LL_EF_EVENT_Management EVENT-Management + * @{ + */ +/** + * @brief Generate an update event. + * @rmtoll EGR UG LL_TIM_GenerateEvent_UPDATE + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_UPDATE(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_UG); +} + +/** + * @brief Generate Capture/Compare 1 event. + * @rmtoll EGR CC1G LL_TIM_GenerateEvent_CC1 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC1(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC1G); +} + +/** + * @brief Generate Capture/Compare 2 event. + * @rmtoll EGR CC2G LL_TIM_GenerateEvent_CC2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC2G); +} + +/** + * @brief Generate Capture/Compare 3 event. + * @rmtoll EGR CC3G LL_TIM_GenerateEvent_CC3 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC3(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC3G); +} + +/** + * @brief Generate Capture/Compare 4 event. + * @rmtoll EGR CC4G LL_TIM_GenerateEvent_CC4 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_CC4(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_CC4G); +} + +/** + * @brief Generate commutation event. + * @rmtoll EGR COMG LL_TIM_GenerateEvent_COM + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_COM(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_COMG); +} + +/** + * @brief Generate trigger event. + * @rmtoll EGR TG LL_TIM_GenerateEvent_TRIG + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_TRIG(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_TG); +} + +/** + * @brief Generate break event. + * @rmtoll EGR BG LL_TIM_GenerateEvent_BRK + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_BRK(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_BG); +} + +/** + * @brief Generate break 2 event. + * @rmtoll EGR B2G LL_TIM_GenerateEvent_BRK2 + * @param TIMx Timer instance + * @retval None + */ +static inline void LL_TIM_GenerateEvent_BRK2(TIM_TypeDef *TIMx) +{ + SET_BIT(TIMx->EGR, TIM_EGR_B2G); +} + +/** + * @} + */ + +#if defined(USE_FULL_LL_DRIVER) +/** @defgroup TIM_LL_EF_Init Initialisation and deinitialisation functions + * @{ + */ + +ErrorStatus LL_TIM_DeInit(const TIM_TypeDef *TIMx); +void LL_TIM_StructInit(LL_TIM_InitTypeDef *TIM_InitStruct); +ErrorStatus LL_TIM_Init(TIM_TypeDef *TIMx, const LL_TIM_InitTypeDef *TIM_InitStruct); +void LL_TIM_OC_StructInit(LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); +ErrorStatus LL_TIM_OC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); +void LL_TIM_IC_StructInit(LL_TIM_IC_InitTypeDef *TIM_ICInitStruct); +ErrorStatus LL_TIM_IC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_IC_InitTypeDef *TIM_IC_InitStruct); +void LL_TIM_ENCODER_StructInit(LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); +ErrorStatus LL_TIM_ENCODER_Init(TIM_TypeDef *TIMx, const LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); +void LL_TIM_HALLSENSOR_StructInit(LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); +ErrorStatus LL_TIM_HALLSENSOR_Init(TIM_TypeDef *TIMx, const LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); +void LL_TIM_BDTR_StructInit(LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); +ErrorStatus LL_TIM_BDTR_Init(TIM_TypeDef *TIMx, const LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); +/** + * @} + */ +#endif /* USE_FULL_LL_DRIVER */ + +/** + * @} + */ + +/** + * @} + */ + +#endif /* TIM1 || TIM2 || TIM3 || TIM4 || TIM5 || TIM6 || TIM7 || TIM8 || TIM12 || TIM13 ||TIM14 || TIM15 || TIM16 || TIM17 || TIM23 || TIM24 */ + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __STM32H7xx_LL_TIM_H */ diff --git a/Inc/MockedDrivers/tim_register_definitions.hpp b/Inc/MockedDrivers/tim_register_definitions.hpp new file mode 100644 index 000000000..1788be399 --- /dev/null +++ b/Inc/MockedDrivers/tim_register_definitions.hpp @@ -0,0 +1,914 @@ +#pragma once +/******************************************************************************/ +/* */ +/* TIM */ +/* */ +/******************************************************************************/ +#define TIM_BREAK_INPUT_SUPPORT /*! Date: Wed, 3 Dec 2025 15:53:09 +0100 Subject: [PATCH 146/281] bridge between LL MMIO Timer and user defined TIMER --- Inc/MockedDrivers/mocked_ll_tim.hpp | 68 +++++++++++++++++++++++ Src/MockedDrivers/mocked_ll_tim.cpp | 85 +++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 Inc/MockedDrivers/mocked_ll_tim.hpp create mode 100644 Src/MockedDrivers/mocked_ll_tim.cpp diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp new file mode 100644 index 000000000..b3dc95056 --- /dev/null +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -0,0 +1,68 @@ +#pragma once +#include +#include "MockedDrivers/common.hpp" +#include "MockedDrivers/tim_register_definitions.hpp" +class TIM_TypeDef{ +public: + TIM_TypeDef(void(* irq_handler)(void)): + callback{irq_handler} + {} + void simulate_ticking(); + void generate_update(); + volatile uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ + volatile uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ + volatile uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + volatile uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + volatile uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ + volatile uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ + volatile uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + volatile uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + volatile uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + volatile uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ + volatile uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ + volatile uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + volatile uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + volatile uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + volatile uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + volatile uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + volatile uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + volatile uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + volatile uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + volatile uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + uint32_t RESERVED1; /*!< Reserved, 0x50 */ + volatile uint32_t CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ + volatile uint32_t CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ + volatile uint32_t CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ + volatile uint32_t AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + volatile uint32_t AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + volatile uint32_t TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ +private: + // ======================================================================== + // Internal Hardware State (Shadow Registers & Hidden Counters) + // ======================================================================== + + // Internal counter for the prescaler (counts 0 to active_PSC) + uint32_t internal_psc_cnt = 0; + + // Internal counter for repetition (counts down from active_RCR to 0) + uint32_t internal_rcr_cnt = 0; + + // "Shadow" registers. These hold the values currently being used by the hardware logic. + // They are updated from the public registers (Preload registers) only on an Update Event (UEV). + uint32_t active_PSC = 0; + uint32_t active_ARR = 0; + uint32_t active_RCR = 0; + void(*callback)(); +}; + +#define DECLARE_TIMER(TIM_IDX) \ + extern TIM_TypeDef* TIM_IDX##_BASE; \ + extern "C"{ \ + void TIM_IDX##_IRQHandler(void); \ + } +#define INSTANTIATE_TIMER(TIM_IDX) \ + TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler}; \ + TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; + +DECLARE_TIMER(TIM1) +DECLARE_TIMER(TIM2) diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp new file mode 100644 index 000000000..f0bf81beb --- /dev/null +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -0,0 +1,85 @@ +#include "MockedDrivers/mocked_ll_tim.hpp" + +#include + +INSTANTIATE_TIMER(TIM2) +void TIM_TypeDef::generate_update() { + active_PSC = PSC; + active_ARR = ARR; + active_RCR = RCR; + internal_rcr_cnt = active_RCR; + internal_psc_cnt = 0; + CNT = 0; // Usually UEV also resets CNT unless configured otherwise + SR &= ~(1U << 0); // Clear UIF if needed, or set it depending on CR1 +} +void TIM_TypeDef::simulate_ticking() { + // Bit definitions for clarity + const uint32_t CR1_CEN = (1U << 0); // Counter Enable + const uint32_t CR1_UDIS = (1U << 1); // Update Disable + const uint32_t CR1_ARPE = (1U << 7); // Auto-Reload Preload Enable + const uint32_t SR_UIF = (1U << 0); // Update Interrupt Flag + + // 1. Check if Counter is Enabled + if (!(CR1 & CR1_CEN)) { + std::cout<<"TIMER IS NOT ENABLED!!\n"; + return; + } + + // 2. Prescaler Logic + // The internal prescaler counts from 0 up to active_PSC. + // We check if we reached the limit *before* incrementing to ensure accurate + // behavior for PSC=0 or PSC=1. + bool main_counter_tick = false; + + if (internal_psc_cnt >= active_PSC) { + internal_psc_cnt = 0; // Rollover + main_counter_tick = true; + } else { + internal_psc_cnt++; // Increment + } + + // If prescaler didn't overflow, the main counter doesn't move. + if (!main_counter_tick) { + return; + } + + // 3. Main Counter Logic + CNT +=1; + + // Determine the current Auto-Reload limit. + // If ARPE is set, use the buffered (shadow) value. + // If ARPE is clear, use the immediate register value. + uint32_t current_limit = (CR1 & CR1_ARPE) ? active_ARR : ARR; + + // Check for Overflow + if (CNT > current_limit) { + std::cout<<"timer overflow\n"; + CNT = 0; // Rollover main counter + + // 4. Repetition Counter & Update Event Logic + // The Update Event (UEV) is generated when the Repetition Counter underflows. + if (internal_rcr_cnt == 0) { + + // --- GENERATE UPDATE EVENT (UEV) --- + + // A. Update Shadow Registers from Preload Registers + active_PSC = PSC; + active_ARR = ARR; + active_RCR = RCR; + + // B. Set Update Interrupt Flag (UIF) + // Only if UDIS (Update Disable) is NOT set + if (!(CR1 & CR1_UDIS)) { + SR |= SR_UIF; + callback(); + } + + // C. Reload Repetition Counter with new value + internal_rcr_cnt = active_RCR; + + } else { + // No UEV yet, just decrement Repetition Counter + internal_rcr_cnt--; + } + } +} \ No newline at end of file From 134f0311828fed728149d4898eaebf19de193732 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:54:44 +0100 Subject: [PATCH 147/281] reduce the number of ugly macros --- Inc/HALAL/Services/Time/Scheduler.hpp | 17 ++----- Src/HALAL/Services/Time/Scheduler.cpp | 64 ++++++++------------------- 2 files changed, 23 insertions(+), 58 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 75d92c99b..5b3a54152 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -8,6 +8,8 @@ #ifndef TESTING_ENV #include "stm32h7xx_ll_tim.h" +#else + #include "MockedDrivers/ll_tim_interface.h" #endif #include #include @@ -20,22 +22,15 @@ # define SCHEDULER_TIMER_IDX 2 #endif -#ifndef TESTING_ENV #define glue_(a,b) a ## b #define glue(a,b) glue_(a,b) #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) // Used to reserve a TimerPeripheral +#ifndef TESTING_ENV #include "stm32h7xx_hal_tim.h" #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; -#else - - struct FakeTimer{ - int64_t CNT; - int64_t ARR; - }; - extern FakeTimer* Scheduler_global_timer; #endif struct Scheduler { using callback_t = void (*)(); @@ -60,11 +55,7 @@ struct Scheduler { // static void global_timer_callback(); // Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise - #ifndef TESTING_ENV - static constexpr uint32_t global_timer_base = SCHEDULER_TIMER_BASE; - #else - static void simulate_ticking(); - #endif + //static const uint32_t global_timer_base = SCHEDULER_TIMER_BASE; static void on_timer_update(); #ifndef TESTING_ENV diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 0c9f55f7f..39079d3a9 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -15,17 +15,16 @@ #include #include -#ifndef TESTING_ENV - /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ - #define SCHEDULER_RCC_TIMER_ENABLE \ - glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) - #define SCHEDULER_GLOBAL_TIMER_IRQn \ - glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) - #define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ - extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) - - #define Scheduler_global_timer ((TIM_TypeDef*)Scheduler::global_timer_base) -#endif + +/* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ +#define SCHEDULER_RCC_TIMER_ENABLE \ + glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) +#define SCHEDULER_GLOBAL_TIMER_IRQn \ + glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) +#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ + extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) + +#define Scheduler_global_timer (SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; @@ -63,31 +62,15 @@ inline void Scheduler::pop_front() { // ---------------------------- inline void Scheduler::global_timer_disable() { -#ifndef TESTING_ENV LL_TIM_DisableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 &= ~TIM_CR1_CEN; -#endif } inline void Scheduler::global_timer_enable() { -#ifndef TESTING_ENV LL_TIM_EnableCounter(Scheduler_global_timer); //Scheduler_global_timer->CR1 |= TIM_CR1_CEN; -#endif } // ---------------------------- -#ifdef TESTING_ENV - FakeTimer* Scheduler_global_timer; - void TimerCallback(); - void Scheduler::simulate_ticking(){ - Scheduler_global_timer->CNT++; - if(Scheduler_global_timer->CNT == Scheduler_global_timer->ARR)[[unlikely]]{ - TimerCallback(); - std::cout<<"overflow\n"; - Scheduler_global_timer->CNT = -1; - } - } -#endif void Scheduler::start() { static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); @@ -101,6 +84,7 @@ void Scheduler::start() { TimerPeripheral perif_reserve(&SCHEDULER_HAL_TIM, std::move(init_data), (std::string)"timer2"); RCC->APB1LENR |= SCHEDULER_RCC_TIMER_ENABLE; +#endif Scheduler_global_timer->PSC = (uint16_t)prescaler; Scheduler_global_timer->ARR = 0; Scheduler_global_timer->DIER |= LL_TIM_DIER_UIE; @@ -111,28 +95,18 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ - NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); + //NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() - // Scheduler::global_timer_enable(); -#else - active_task_count_ = 0; - Scheduler_global_timer = new FakeTimer(); - Scheduler_global_timer->CNT = 0; - Scheduler_global_timer->ARR = 0; -#endif - Scheduler::schedule_next_interval(); + Scheduler::global_timer_enable(); + //Scheduler::schedule_next_interval(); } -#ifndef TESTING_ENV - SCHEDULER_GLOBAL_TIMER_CALLBACK() { - Scheduler_global_timer->SR &= ~TIM_SR_UIF; -#else - void TimerCallback(){ -#endif - - Scheduler::on_timer_update(); - } +SCHEDULER_GLOBAL_TIMER_CALLBACK() { + Scheduler_global_timer->SR &= ~TIM_SR_UIF; + std::cout<<"OVERFLOW\nn"; + Scheduler::on_timer_update(); +} void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); From b98155039615b0260a0a85a7c54bbdc14b0e21ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:55:23 +0100 Subject: [PATCH 148/281] compile the new mock file --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e7054310..30dd4fe9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,6 +224,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$:${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> ) From 9cfb41f76f758b1cddd0f41d8547b34c9f46904d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:55:32 +0100 Subject: [PATCH 149/281] update test --- Tests/Time/scheduler_test.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index e090f3dfd..ab9f91f59 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -21,8 +21,10 @@ TEST(SchedulerTests, TaskExecution) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); constexpr int NUM_TICKS = 1'000'000; + TIM2_BASE->ARR = 500; + TIM2_BASE->generate_update(); for(int i = 0; i <= NUM_TICKS; i++){ - Scheduler::simulate_ticking(); + TIM2_BASE->simulate_ticking(); Scheduler::update(); } // one tick is 1us, and we register a task that executes every 10us From 82298e30ced144ee352d1f9f55bb773b42914fcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 15:56:03 +0100 Subject: [PATCH 150/281] enable debugging of tests with TestMate C++ extension --- .vscode/settings.json | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b2abce05a..f905829d4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,27 @@ "files.associations": { "mem.h": "c", "tinydir.h": "c", - "dirent.h": "c" - } + "dirent.h": "c", + "compare": "cpp", + "cstdint": "cpp", + "iostream": "cpp" + }, + "testMate.cpp.debug.configTemplate": { + "type": "cppdbg", + "MIMode": "gdb", + "program": "${exec}", + "args": "${args}", + "cwd": "${cwd}", + + "externalConsole": false, + // This setupCommands block often fixes generic "pause" issues in GDB + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] +} } \ No newline at end of file From 709863242633b62ea75d11baa24ccc9d5f9bc8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:54:20 +0100 Subject: [PATCH 151/281] feat: add DSB and ISB intructions in x86_64 --- Inc/MockedDrivers/compiler_specific.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index fdad61521..448976082 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -1,5 +1,5 @@ #pragma once - +#include /* This file contains implementatios or altername names for @@ -8,3 +8,6 @@ ARM GCC compiler that don't work in x86_64 */ #define __RBIT #define __CLZ __builtin_clz +#define __COMPILER_BARRIER() asm volatile("" ::: "memory") +#define __DSB() __asm__ volatile ("mfence" ::: "memory"); +#define __ISB() __asm__ volatile ("lfence" ::: "memory"); \ No newline at end of file From 56da93d9da743540d7834c7931b6225a528cfa29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:54:35 +0100 Subject: [PATCH 152/281] feat: add NVIC --- CMakeLists.txt | 2 +- Inc/MockedDrivers/NVIC.hpp | 184 +++++++++++++++++++++++++++++++++++++ Src/MockedDrivers/NVIC.cpp | 38 ++++++++ 3 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 Inc/MockedDrivers/NVIC.hpp create mode 100644 Src/MockedDrivers/NVIC.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 30dd4fe9e..e015bfde2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,7 +225,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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 diff --git a/Inc/MockedDrivers/NVIC.hpp b/Inc/MockedDrivers/NVIC.hpp new file mode 100644 index 000000000..7e8b03234 --- /dev/null +++ b/Inc/MockedDrivers/NVIC.hpp @@ -0,0 +1,184 @@ +#pragma once + + +#include "MockedDrivers/common.hpp" +#include "MockedDrivers/compiler_specific.hpp" + +class NVIC_Type +{ + public: + volatile uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[24U]; + volatile uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RESERVED1[24U]; + volatile uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[24U]; + volatile uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[24U]; + volatile uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ + uint32_t RESERVED4[56U]; + volatile uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ + uint32_t RESERVED5[644U]; + volatile uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ +}; +enum IRQn_Type +{ +/****** Cortex-M Processor Exceptions Numbers *****************************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13, /*!< 3 Cortex-M Hard Fault Interrupt */ + MemoryManagement_IRQn = -12, /*!< 4 Cortex-M Memory Management Interrupt */ + BusFault_IRQn = -11, /*!< 5 Cortex-M Bus Fault Interrupt */ + UsageFault_IRQn = -10, /*!< 6 Cortex-M Usage Fault Interrupt */ + SVCall_IRQn = -5, /*!< 11 Cortex-M SV Call Interrupt */ + DebugMonitor_IRQn = -4, /*!< 12 Cortex-M Debug Monitor Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M System Tick Interrupt */ +/****** STM32 specific Interrupt Numbers **********************************************************************/ + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt ( wwdg1_it, wwdg2_it) */ + PVD_AVD_IRQn = 1, /*!< PVD/AVD through EXTI Line detection Interrupt */ + TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ + RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ + FLASH_IRQn = 4, /*!< FLASH global Interrupt */ + RCC_IRQn = 5, /*!< RCC global Interrupt */ + EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ + EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ + EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ + EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ + EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ + DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ + DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ + DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ + DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ + DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ + DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ + DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ + ADC_IRQn = 18, /*!< ADC1 and ADC2 global Interrupts */ + FDCAN1_IT0_IRQn = 19, /*!< FDCAN1 Interrupt line 0 */ + FDCAN2_IT0_IRQn = 20, /*!< FDCAN2 Interrupt line 0 */ + FDCAN1_IT1_IRQn = 21, /*!< FDCAN1 Interrupt line 1 */ + FDCAN2_IT1_IRQn = 22, /*!< FDCAN2 Interrupt line 1 */ + EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ + TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */ + TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ + TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */ + TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ + TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ + TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ + TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ + I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ + I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ + I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ + I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ + SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ + USART1_IRQn = 37, /*!< USART1 global Interrupt */ + USART2_IRQn = 38, /*!< USART2 global Interrupt */ + USART3_IRQn = 39, /*!< USART3 global Interrupt */ + EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ + RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ + TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ + TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ + TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ + TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ + DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ + FMC_IRQn = 48, /*!< FMC global Interrupt */ + SDMMC1_IRQn = 49, /*!< SDMMC1 global Interrupt */ + TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ + SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ + UART4_IRQn = 52, /*!< UART4 global Interrupt */ + UART5_IRQn = 53, /*!< UART5 global Interrupt */ + TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn = 55, /*!< TIM7 global interrupt */ + DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ + DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ + DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ + DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ + DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ + ETH_IRQn = 61, /*!< Ethernet global Interrupt */ + ETH_WKUP_IRQn = 62, /*!< Ethernet Wakeup through EXTI line Interrupt */ + FDCAN_CAL_IRQn = 63, /*!< FDCAN Calibration unit Interrupt */ + DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ + DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ + DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ + USART6_IRQn = 71, /*!< USART6 global interrupt */ + I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ + I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ + OTG_HS_EP1_OUT_IRQn = 74, /*!< USB OTG HS End Point 1 Out global interrupt */ + OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */ + OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */ + OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */ + DCMI_PSSI_IRQn = 78, /*!< DCMI and PSSI global interrupt */ + RNG_IRQn = 80, /*!< RNG global interrupt */ + FPU_IRQn = 81, /*!< FPU global interrupt */ + UART7_IRQn = 82, /*!< UART7 global interrupt */ + UART8_IRQn = 83, /*!< UART8 global interrupt */ + SPI4_IRQn = 84, /*!< SPI4 global Interrupt */ + SPI5_IRQn = 85, /*!< SPI5 global Interrupt */ + SPI6_IRQn = 86, /*!< SPI6 global Interrupt */ + SAI1_IRQn = 87, /*!< SAI1 global Interrupt */ + LTDC_IRQn = 88, /*!< LTDC global Interrupt */ + LTDC_ER_IRQn = 89, /*!< LTDC Error global Interrupt */ + DMA2D_IRQn = 90, /*!< DMA2D global Interrupt */ + OCTOSPI1_IRQn = 92, /*!< OCTOSPI1 global interrupt */ + LPTIM1_IRQn = 93, /*!< LP TIM1 interrupt */ + CEC_IRQn = 94, /*!< HDMI-CEC global Interrupt */ + I2C4_EV_IRQn = 95, /*!< I2C4 Event Interrupt */ + I2C4_ER_IRQn = 96, /*!< I2C4 Error Interrupt */ + SPDIF_RX_IRQn = 97, /*!< SPDIF-RX global Interrupt */ + DMAMUX1_OVR_IRQn = 102, /*!= 0) + { + __COMPILER_BARRIER(); + NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __COMPILER_BARRIER(); + } +} + +uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); + } + else + { + return(0U); + } +} + +void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + if ((int32_t)(IRQn) >= 0) + { + NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); + __DSB(); + __ISB(); + } +} \ No newline at end of file From d7fa9dcc094589af1bb52928839bda636e48b2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:54:48 +0100 Subject: [PATCH 153/281] add NVIC logic --- Inc/MockedDrivers/mocked_ll_tim.hpp | 10 +++++++--- Src/MockedDrivers/mocked_ll_tim.cpp | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index b3dc95056..c235cd97e 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,11 +1,14 @@ #pragma once #include #include "MockedDrivers/common.hpp" +#include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/tim_register_definitions.hpp" + + class TIM_TypeDef{ public: - TIM_TypeDef(void(* irq_handler)(void)): - callback{irq_handler} + TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): + callback{irq_handler},irq_n{irq_n} {} void simulate_ticking(); void generate_update(); @@ -53,6 +56,7 @@ class TIM_TypeDef{ uint32_t active_ARR = 0; uint32_t active_RCR = 0; void(*callback)(); + IRQn_Type irq_n; }; #define DECLARE_TIMER(TIM_IDX) \ @@ -61,7 +65,7 @@ class TIM_TypeDef{ void TIM_IDX##_IRQHandler(void); \ } #define INSTANTIATE_TIMER(TIM_IDX) \ - TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler}; \ + TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler,TIM_IDX##_IRQn}; \ TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; DECLARE_TIMER(TIM1) diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index f0bf81beb..31f3d95ef 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -71,7 +71,9 @@ void TIM_TypeDef::simulate_ticking() { // Only if UDIS (Update Disable) is NOT set if (!(CR1 & CR1_UDIS)) { SR |= SR_UIF; - callback(); + if(NVIC_GetEnableIRQ(irq_n)){ + callback(); + } } // C. Reload Repetition Counter with new value From 871c41ec5a9da4d5fb62aab6d429e9ad171280c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 16:55:01 +0100 Subject: [PATCH 154/281] feat: use NVIC and remove print --- Src/HALAL/Services/Time/Scheduler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 39079d3a9..b1161ec6f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -95,7 +95,7 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ - //NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); + NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() Scheduler::global_timer_enable(); @@ -104,7 +104,6 @@ void Scheduler::start() { SCHEDULER_GLOBAL_TIMER_CALLBACK() { Scheduler_global_timer->SR &= ~TIM_SR_UIF; - std::cout<<"OVERFLOW\nn"; Scheduler::on_timer_update(); } void Scheduler::update() { From ca2a6ceb5a83feb45b650e128ff504e6306245eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:05:54 +0100 Subject: [PATCH 155/281] fix: move extern"C" block to allow using --- Inc/MockedDrivers/ll_tim_interface.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/ll_tim_interface.h b/Inc/MockedDrivers/ll_tim_interface.h index dfb2587b9..7feab09f3 100644 --- a/Inc/MockedDrivers/ll_tim_interface.h +++ b/Inc/MockedDrivers/ll_tim_interface.h @@ -20,12 +20,13 @@ #ifndef __STM32H7xx_LL_TIM_H #define __STM32H7xx_LL_TIM_H +#include "mocked_ll_tim.hpp" + #ifdef __cplusplus extern "C" { #endif #include -#include "mocked_ll_tim.hpp" #define TIM1 From 0c70d6522ed63fd5263314cd99934972d7e5a46b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:06:49 +0100 Subject: [PATCH 156/281] add Register class to allow for side effects --- Inc/MockedDrivers/Register.hpp | 116 +++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Inc/MockedDrivers/Register.hpp diff --git a/Inc/MockedDrivers/Register.hpp b/Inc/MockedDrivers/Register.hpp new file mode 100644 index 000000000..e133993a7 --- /dev/null +++ b/Inc/MockedDrivers/Register.hpp @@ -0,0 +1,116 @@ +#pragma once +#include +#include + + +template +struct RegisterTraits { + static void write(uint32_t& target, uint32_t val) { + target = val; + } +}; + + +template +class RegisterBase { +public: + uint32_t reg = 0; + + RegisterBase() = default; + RegisterBase(uint32_t val) : reg(val) {} + + RegisterBase& operator=(uint32_t val) { + set(val); + return *this; + } + RegisterBase& operator+=(uint32_t val){ + set(reg+val); + return *this; + } + RegisterBase& operator-=(uint32_t val){ + set(reg-val); + return *this; + } + + RegisterBase& operator&=(uint32_t mask) { + set(reg & mask); + return *this; + } + + RegisterBase& operator|=(uint32_t mask) { + set(reg | mask); + return *this; + } + + RegisterBase& operator^=(uint32_t mask) { + set(reg ^ mask); + return *this; + } + RegisterBase& operator<<=(int shift) { + set(reg << shift); // Triggers Traits + return *this; + } + + RegisterBase& operator>>=(int shift) { + set(reg >> shift); // Triggers Traits + return *this; + } + + // --- Shift Read (Does NOT modify Register) --- + // Usage: uint32_t val = REG >> 4; + uint32_t operator<<(int shift) const { + return reg << shift; + } + + uint32_t operator>>(int shift) const { + return reg >> shift; + } + RegisterBase& operator++() { + set(reg + 1); + return *this; + } + + // --- Postfix Increment (REG++) --- + // int argument is a dummy flag for C++ to distinguish postfix + uint32_t operator++(int) { + uint32_t old_val = reg; + set(reg + 1); + return old_val; + } + + RegisterBase& operator--() { + set(reg - 1); + return *this; + } + + uint32_t operator--(int) { + uint32_t old_val = reg; + set(reg - 1); + return old_val; + } + /** + * COMPARISON + */ + bool operator!=(uint32_t val) const { + return reg != val; + } + bool operator==(uint32_t val) const { + return reg == val; + } + /** + * BITWISE COMPARISONS + */ + operator uint32_t(){ + return reg; + } + operator uint32_t() const volatile { + return reg; + } + operator uint32_t() const { + return reg; + } +private: + void set(uint32_t val) { + RegisterTraits::write(this->reg, val); + } +}; \ No newline at end of file From 401461c15ee40ab402a11ef449d04e972776cd75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:07:26 +0100 Subject: [PATCH 157/281] feat: use newly created Register class for side effects, neat trick in CNT write --- Inc/MockedDrivers/mocked_ll_tim.hpp | 115 +++++++++++++++++++++------- Src/MockedDrivers/mocked_ll_tim.cpp | 58 ++++---------- 2 files changed, 103 insertions(+), 70 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index c235cd97e..ba103f1d4 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -3,6 +3,24 @@ #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/tim_register_definitions.hpp" +#include "MockedDrivers/Register.hpp" +#include +enum class TimRegs { + CR1, CR2, SMCR, DIER, SR, EGR, CCMR1, CCMR2, CCER, CNT, PSC, ARR, RCR, + CCR1, CCR2, CCR3, CCR4, BDTR, DCR, DMAR, CCMR3, CCR5, CCR6, AF1, AF2, TISEL +}; +using enum TimRegs; + + + +template +class TimerRegister : public RegisterBase { +public: + using RegisterBase::RegisterBase; + using RegisterBase::operator=; +}; + +static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); class TIM_TypeDef{ @@ -10,36 +28,34 @@ class TIM_TypeDef{ TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): callback{irq_handler},irq_n{irq_n} {} - void simulate_ticking(); void generate_update(); - volatile uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ - volatile uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ - volatile uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ - volatile uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ - volatile uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ - volatile uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ - volatile uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ - volatile uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ - volatile uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ - volatile uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ - volatile uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ - volatile uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ - volatile uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ - volatile uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ - volatile uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ - volatile uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ - volatile uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ - volatile uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ - volatile uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ - volatile uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ + TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ + TimerRegister SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + TimerRegister DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + TimerRegister SR; /*!< TIM status register, Address offset: 0x10 */ + TimerRegister EGR; /*!< TIM event generation register, Address offset: 0x14 */ + TimerRegister CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ + TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ + TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + TimerRegister CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + TimerRegister CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + TimerRegister CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + TimerRegister BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + TimerRegister DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + TimerRegister DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ uint32_t RESERVED1; /*!< Reserved, 0x50 */ - volatile uint32_t CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ - volatile uint32_t CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ - volatile uint32_t CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ - volatile uint32_t AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ - volatile uint32_t AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ - volatile uint32_t TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ -private: + TimerRegister CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ + TimerRegister CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ + TimerRegister CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ + TimerRegister AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + TimerRegister AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + TimerRegister TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ // ======================================================================== // Internal Hardware State (Shadow Registers & Hidden Counters) // ======================================================================== @@ -55,9 +71,52 @@ class TIM_TypeDef{ uint32_t active_PSC = 0; uint32_t active_ARR = 0; uint32_t active_RCR = 0; + void(*callback)(); IRQn_Type irq_n; + bool check_CNT_increase_preconditions(){ + // Bit definitions for clarity + const uint32_t CR1_CEN = (1U << 0); // Counter Enable + + // 1. Check if Counter is Enabled + if (!(CR1 & CR1_CEN)) { + std::cout<<"TIMER IS NOT ENABLED!!\n"; + return false; + } + // 2. Prescaler Logic + // The internal prescaler counts from 0 up to active_PSC. + // We check if we reached the limit *before* incrementing to ensure accurate + // behavior for PSC=0 or PSC=1. + bool main_counter_tick = false; + + if (internal_psc_cnt >= active_PSC) { + internal_psc_cnt = 0; // Rollover + main_counter_tick = true; + } else { + internal_psc_cnt++; // Increment + } + + // If prescaler didn't overflow, the main counter doesn't move. + if (!main_counter_tick) { + return false; + } + return true; + } }; +static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); +void simulate_ticks(TIM_TypeDef* tim); + +template<> +struct RegisterTraits { + static void write(uint32_t& target, uint32_t val) { + TIM_TypeDef* timer = (TIM_TypeDef*)(((uint8_t*)&target)-offsetof(TIM_TypeDef, CNT)); + target = val; + if(val != 0 && timer->check_CNT_increase_preconditions()){ + simulate_ticks(timer); + } + } +}; + #define DECLARE_TIMER(TIM_IDX) \ extern TIM_TypeDef* TIM_IDX##_BASE; \ diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index 31f3d95ef..4f4ceb413 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -3,6 +3,7 @@ #include INSTANTIATE_TIMER(TIM2) + void TIM_TypeDef::generate_update() { active_PSC = PSC; active_ARR = ARR; @@ -12,76 +13,49 @@ void TIM_TypeDef::generate_update() { CNT = 0; // Usually UEV also resets CNT unless configured otherwise SR &= ~(1U << 0); // Clear UIF if needed, or set it depending on CR1 } -void TIM_TypeDef::simulate_ticking() { +void simulate_ticks(TIM_TypeDef* tim){ + // Bit definitions for clarity - const uint32_t CR1_CEN = (1U << 0); // Counter Enable const uint32_t CR1_UDIS = (1U << 1); // Update Disable const uint32_t CR1_ARPE = (1U << 7); // Auto-Reload Preload Enable const uint32_t SR_UIF = (1U << 0); // Update Interrupt Flag - // 1. Check if Counter is Enabled - if (!(CR1 & CR1_CEN)) { - std::cout<<"TIMER IS NOT ENABLED!!\n"; - return; - } - - // 2. Prescaler Logic - // The internal prescaler counts from 0 up to active_PSC. - // We check if we reached the limit *before* incrementing to ensure accurate - // behavior for PSC=0 or PSC=1. - bool main_counter_tick = false; - - if (internal_psc_cnt >= active_PSC) { - internal_psc_cnt = 0; // Rollover - main_counter_tick = true; - } else { - internal_psc_cnt++; // Increment - } - - // If prescaler didn't overflow, the main counter doesn't move. - if (!main_counter_tick) { - return; - } - - // 3. Main Counter Logic - CNT +=1; - // Determine the current Auto-Reload limit. // If ARPE is set, use the buffered (shadow) value. // If ARPE is clear, use the immediate register value. - uint32_t current_limit = (CR1 & CR1_ARPE) ? active_ARR : ARR; + uint32_t current_limit = (tim->CR1 & CR1_ARPE) ? tim->active_ARR : tim->ARR.reg; // Check for Overflow - if (CNT > current_limit) { + if (tim->CNT > current_limit) { std::cout<<"timer overflow\n"; - CNT = 0; // Rollover main counter + tim->CNT = 0; // Rollover main counter // 4. Repetition Counter & Update Event Logic // The Update Event (UEV) is generated when the Repetition Counter underflows. - if (internal_rcr_cnt == 0) { + if (tim->internal_rcr_cnt == 0) { // --- GENERATE UPDATE EVENT (UEV) --- // A. Update Shadow Registers from Preload Registers - active_PSC = PSC; - active_ARR = ARR; - active_RCR = RCR; + tim->active_PSC = tim->PSC; + tim->active_ARR = tim->ARR; + tim->active_RCR = tim->RCR; // B. Set Update Interrupt Flag (UIF) // Only if UDIS (Update Disable) is NOT set - if (!(CR1 & CR1_UDIS)) { - SR |= SR_UIF; - if(NVIC_GetEnableIRQ(irq_n)){ - callback(); + if (!(tim->CR1 & CR1_UDIS)) { + tim->SR |= SR_UIF; + if(NVIC_GetEnableIRQ(tim->irq_n)){ + tim->callback(); } } // C. Reload Repetition Counter with new value - internal_rcr_cnt = active_RCR; + tim->internal_rcr_cnt = tim->active_RCR; } else { // No UEV yet, just decrement Repetition Counter - internal_rcr_cnt--; + tim->internal_rcr_cnt--; } } } \ No newline at end of file From 8e550035b1715a05609f47b50a37587a355b3eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:07:50 +0100 Subject: [PATCH 158/281] feat: be as realistic as possible in test, by using CNT++ --- Tests/Time/scheduler_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index ab9f91f59..dd61a421e 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -24,7 +24,7 @@ TEST(SchedulerTests, TaskExecution) { TIM2_BASE->ARR = 500; TIM2_BASE->generate_update(); for(int i = 0; i <= NUM_TICKS; i++){ - TIM2_BASE->simulate_ticking(); + TIM2_BASE->CNT++; Scheduler::update(); } // one tick is 1us, and we register a task that executes every 10us From 14140ab179a1fc6b6b68aee1d4590b94e8517bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:09:41 +0100 Subject: [PATCH 159/281] feat: remove unnecessary include --- Src/HALAL/Services/Time/Scheduler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index b1161ec6f..81db99b3d 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -9,8 +9,6 @@ #ifndef TESTING_ENV // This is needed to register a TimerPeripheral #include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" -#else - #include #endif #include #include From 1d78adedfb9157498c1134878748e2e9c2ecab81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:17:39 +0100 Subject: [PATCH 160/281] feat: add an __RBIT impl for x86_64 --- Inc/MockedDrivers/compiler_specific.hpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index 448976082..a1a29cd3c 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -6,7 +6,29 @@ This file contains implementatios or altername names for ARM GCC compiler that don't work in x86_64 */ -#define __RBIT +static inline uint32_t __RBIT(uint32_t val) { + // 1. Hardware Byte Swap (Optimization: handles the large movements) + // MSVC uses _byteswap_ulong, GCC/Clang uses __builtin_bswap32 +#if defined(_MSC_VER) + val = _byteswap_ulong(val); +#else + val = __builtin_bswap32(val); +#endif + + // 2. Swap Nibbles (within bytes) + // 0xF0 = 1111 0000 -> shifts to 0000 1111 + val = ((val & 0xF0F0F0F0) >> 4) | ((val & 0x0F0F0F0F) << 4); + + // 3. Swap Bit-Pairs (within nibbles) + // 0xCC = 1100 1100 -> shifts to 0011 0011 + val = ((val & 0xCCCCCCCC) >> 2) | ((val & 0x33333333) << 2); + + // 4. Swap Single Bits (within pairs) + // 0xAA = 1010 1010 -> shifts to 0101 0101 + val = ((val & 0xAAAAAAAA) >> 1) | ((val & 0x55555555) << 1); + + return val; +} #define __CLZ __builtin_clz #define __COMPILER_BARRIER() asm volatile("" ::: "memory") #define __DSB() __asm__ volatile ("mfence" ::: "memory"); From 615f2ddf1ba9156d1e2c2f9bde031ff66bf056cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Wed, 3 Dec 2025 19:36:39 +0100 Subject: [PATCH 161/281] fix: compilation --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 81db99b3d..4767f6934 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -22,7 +22,7 @@ #define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) -#define Scheduler_global_timer (SCHEDULER_TIMER_BASE) +#define Scheduler_global_timer ((TIM_TypeDef*)SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = static_cast(std::numeric_limits::max()) + 1ULL; From 1d2b392106894e5466f3d0b4363d7545a9364ab2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 17:11:05 +0100 Subject: [PATCH 162/281] Added tests check in CI/CD --- .github/workflows/tests.yml | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..64ae8a43f --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,32 @@ +name: Run tests + +on: + workflow_dispatch: + pull_request: + branches: [ development ] + +jobs: + tests: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake ninja-build build-essential + + - name: Configure (CMake) + run: | + cmake --preset simulator + + - name: Build + run: | + cmake --build build/tests + + - name: Run tests (ctest) + working-directory: build/tests + run: | + ctest --output-on-failure From eab1cc62a6d33a549ea4085ca6054f1651964191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 17:13:59 +0100 Subject: [PATCH 163/281] fix(ci/cd): output folder --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 64ae8a43f..d3150e416 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,9 +24,9 @@ jobs: - name: Build run: | - cmake --build build/tests + cmake --build out/build/simulator - name: Run tests (ctest) - working-directory: build/tests + working-directory: out/build/simulator run: | ctest --output-on-failure From a8894d215d6bfc3f994d45e63b95cc13497c547c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Mon, 8 Dec 2025 18:08:29 +0100 Subject: [PATCH 164/281] Added ARM specific instructions to be able to compile in ARM hosts (Mac) --- Inc/MockedDrivers/compiler_specific.hpp | 44 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index a1a29cd3c..18fd8d437 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -1,11 +1,11 @@ #pragma once #include -/* -This file contains implementatios or altername names for -ARM GCC compiler that don't work in x86_64 +/* + * This file contains implementations or alternate names for + * ARM GCC intrinsics that don't work on x86_64 / host platforms. + */ -*/ static inline uint32_t __RBIT(uint32_t val) { // 1. Hardware Byte Swap (Optimization: handles the large movements) // MSVC uses _byteswap_ulong, GCC/Clang uses __builtin_bswap32 @@ -17,19 +17,39 @@ static inline uint32_t __RBIT(uint32_t val) { // 2. Swap Nibbles (within bytes) // 0xF0 = 1111 0000 -> shifts to 0000 1111 - val = ((val & 0xF0F0F0F0) >> 4) | ((val & 0x0F0F0F0F) << 4); + val = ((val & 0xF0F0F0F0u) >> 4) | ((val & 0x0F0F0F0Fu) << 4); // 3. Swap Bit-Pairs (within nibbles) // 0xCC = 1100 1100 -> shifts to 0011 0011 - val = ((val & 0xCCCCCCCC) >> 2) | ((val & 0x33333333) << 2); + val = ((val & 0xCCCCCCCCu) >> 2) | ((val & 0x33333333u) << 2); // 4. Swap Single Bits (within pairs) // 0xAA = 1010 1010 -> shifts to 0101 0101 - val = ((val & 0xAAAAAAAA) >> 1) | ((val & 0x55555555) << 1); + val = ((val & 0xAAAAAAAAu) >> 1) | ((val & 0x55555555u) << 1); return val; -} -#define __CLZ __builtin_clz -#define __COMPILER_BARRIER() asm volatile("" ::: "memory") -#define __DSB() __asm__ volatile ("mfence" ::: "memory"); -#define __ISB() __asm__ volatile ("lfence" ::: "memory"); \ No newline at end of file +} + +#define __CLZ __builtin_clz +#define __COMPILER_BARRIER() asm volatile("" ::: "memory") + +// Architecture-specific definitions for barrier intrinsics used in mocks +#if defined(__x86_64__) || defined(_M_X64) + +// Host x86_64 +# define __DSB() __asm__ volatile("mfence" ::: "memory") +# define __ISB() __asm__ volatile("lfence" ::: "memory") + +#elif defined(__aarch64__) || defined(_M_ARM64) + +// Host ARM64 +# define __DSB() __asm__ volatile("dmb ish" ::: "memory") +# define __ISB() __asm__ volatile("isb" ::: "memory") + +#else + +// Any other host architecture: compiler barrier only +# define __DSB() __COMPILER_BARRIER() +# define __ISB() __COMPILER_BARRIER() + +#endif \ No newline at end of file From 7b81ce34860ffb869bcaf7099f14b4ccbefafad8 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:07:17 +0100 Subject: [PATCH 165/281] Fix: compiler barrier for msvc, hopefully works --- Inc/MockedDrivers/compiler_specific.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index 18fd8d437..405e03d10 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -31,6 +31,15 @@ static inline uint32_t __RBIT(uint32_t val) { } #define __CLZ __builtin_clz + +#if defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__) +void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) +#define __COMPILER_BARRIER() _ReadWriteBarrier() +#define __DSB() __COMPILER_BARRIER() +#define __ISB() __COMPILER_BARRIER() +#else + #define __COMPILER_BARRIER() asm volatile("" ::: "memory") // Architecture-specific definitions for barrier intrinsics used in mocks @@ -52,4 +61,5 @@ static inline uint32_t __RBIT(uint32_t val) { # define __DSB() __COMPILER_BARRIER() # define __ISB() __COMPILER_BARRIER() +#endif #endif \ No newline at end of file From 03dfb7cb9bbb19b041a917195106746bc339017a Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:13:13 +0100 Subject: [PATCH 166/281] Fix: Try to fix -Wchanges-meaning warning --- Inc/MockedDrivers/mocked_ll_tim.hpp | 74 +++++++++++++++-------------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index ba103f1d4..fffe2d5b6 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -5,22 +5,24 @@ #include "MockedDrivers/tim_register_definitions.hpp" #include "MockedDrivers/Register.hpp" #include -enum class TimRegs { - CR1, CR2, SMCR, DIER, SR, EGR, CCMR1, CCMR2, CCER, CNT, PSC, ARR, RCR, - CCR1, CCR2, CCR3, CCR4, BDTR, DCR, DMAR, CCMR3, CCR5, CCR6, AF1, AF2, TISEL +enum class TimReg { + Reg_CR1, Reg_CR2, Reg_SMCR, Reg_DIER, Reg_SR, Reg_EGR, + Reg_CCMR1, Reg_CCMR2, Reg_CCER, Reg_CNT, Reg_PSC, Reg_ARR, Reg_RCR, + Reg_CCR1, Reg_CCR2, Reg_CCR3, Reg_CCR4, Reg_BDTR, Reg_DCR, + Reg_DMAR, Reg_CCMR3, Reg_CCR5, Reg_CCR6, Reg_AF1, Reg_AF2, Reg_TISEL }; -using enum TimRegs; +using enum TimReg; -template -class TimerRegister : public RegisterBase { +template +class TimerRegister : public RegisterBase { public: - using RegisterBase::RegisterBase; - using RegisterBase::operator=; + using RegisterBase::RegisterBase; + using RegisterBase::operator=; }; -static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); +static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); class TIM_TypeDef{ @@ -29,33 +31,33 @@ class TIM_TypeDef{ callback{irq_handler},irq_n{irq_n} {} void generate_update(); - TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ - TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ - TimerRegister SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ - TimerRegister DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ - TimerRegister SR; /*!< TIM status register, Address offset: 0x10 */ - TimerRegister EGR; /*!< TIM event generation register, Address offset: 0x14 */ - TimerRegister CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ - TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ - TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ - TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ - TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ - TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ - TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ - TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ - TimerRegister CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ - TimerRegister CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ - TimerRegister CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ - TimerRegister BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ - TimerRegister DCR; /*!< TIM DMA control register, Address offset: 0x48 */ - TimerRegister DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ + TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ + TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ + TimerRegister SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ + TimerRegister DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ + TimerRegister SR; /*!< TIM status register, Address offset: 0x10 */ + TimerRegister EGR; /*!< TIM event generation register, Address offset: 0x14 */ + TimerRegister CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ + TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ + TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ + TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ + TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ + TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ + TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ + TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ + TimerRegister CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ + TimerRegister CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ + TimerRegister CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ + TimerRegister BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ + TimerRegister DCR; /*!< TIM DMA control register, Address offset: 0x48 */ + TimerRegister DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ uint32_t RESERVED1; /*!< Reserved, 0x50 */ - TimerRegister CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ - TimerRegister CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ - TimerRegister CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ - TimerRegister AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ - TimerRegister AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ - TimerRegister TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ + TimerRegister CCMR3; /*!< TIM capture/compare mode register 3, Address offset: 0x54 */ + TimerRegister CCR5; /*!< TIM capture/compare register5, Address offset: 0x58 */ + TimerRegister CCR6; /*!< TIM capture/compare register6, Address offset: 0x5C */ + TimerRegister AF1; /*!< TIM alternate function option register 1, Address offset: 0x60 */ + TimerRegister AF2; /*!< TIM alternate function option register 2, Address offset: 0x64 */ + TimerRegister TISEL; /*!< TIM Input Selection register, Address offset: 0x68 */ // ======================================================================== // Internal Hardware State (Shadow Registers & Hidden Counters) // ======================================================================== @@ -103,7 +105,7 @@ class TIM_TypeDef{ return true; } }; -static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); +static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); void simulate_ticks(TIM_TypeDef* tim); template<> From 11de9efc3f46087cdbf1d4c8b6aadd9f1ced95d5 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:16:36 +0100 Subject: [PATCH 167/281] Fix typo --- Inc/MockedDrivers/mocked_ll_tim.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index fffe2d5b6..41897a666 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -109,7 +109,7 @@ static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); void simulate_ticks(TIM_TypeDef* tim); template<> -struct RegisterTraits { +struct RegisterTraits { static void write(uint32_t& target, uint32_t val) { TIM_TypeDef* timer = (TIM_TypeDef*)(((uint8_t*)&target)-offsetof(TIM_TypeDef, CNT)); target = val; From d094a38c75d8d23824e3f8285241a371d0c97edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20L=C3=B3pez?= <120128034+victor-Lopez25@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:25:41 +0100 Subject: [PATCH 168/281] Update Inc/MockedDrivers/common.hpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#discussion_r2599324887 Co-authored-by: Jorge Sáez <125664643+jorgesg82@users.noreply.github.com> --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index b7f33c2bc..da459f1f5 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -41,7 +41,7 @@ typedef enum #define CLEAR_REG(REG) ((REG) = (0x0)) -#define WRITE_REG(REG, VAL) ((REG) = (VAL)) +#define WRITE_REG(REG, VAL) ((REG) = static_cast(VAL)) #define READ_REG(REG) ((REG)) From cb09b56f019f92fe5f037879017cd662b2db2bd4 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:31:31 +0100 Subject: [PATCH 169/281] Actually do the change github didn't do :/ --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index da459f1f5..40fcf626a 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -35,7 +35,7 @@ typedef enum #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) &= = static_cast(static_cast(REG) & ~static_cast(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) From 333f84aacde18def38bf466cbd7c02ed09511052 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:56:07 +0100 Subject: [PATCH 170/281] Fix typo p2 --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 40fcf626a..bde9174fb 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -35,7 +35,7 @@ typedef enum #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) &= = static_cast(static_cast(REG) & ~static_cast(BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT)) #define READ_BIT(REG, BIT) ((REG) & (BIT)) From bde99ea9e12d72bfd576e9f0dc1a0c6287051d3f Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 20:57:26 +0100 Subject: [PATCH 171/281] Fix another typo --- Inc/MockedDrivers/common.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index bde9174fb..e94fd853a 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -35,7 +35,7 @@ typedef enum #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT)) +#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT))) #define READ_BIT(REG, BIT) ((REG) & (BIT)) From c07c00558fafaa9a70d7398992eca2fb8dcf4220 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 8 Dec 2025 21:02:03 +0100 Subject: [PATCH 172/281] Fix unsigned long - 64bit when testing using LL functions --- Src/HALAL/Services/Time/Scheduler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4767f6934..199fa559f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -94,14 +94,15 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); - Scheduler_global_timer->SR &= ~LL_TIM_SR_UIF; /* clear update interrupt flag */ + LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() Scheduler::global_timer_enable(); //Scheduler::schedule_next_interval(); } SCHEDULER_GLOBAL_TIMER_CALLBACK() { - Scheduler_global_timer->SR &= ~TIM_SR_UIF; + /* clear update interrupt flag */ + LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); Scheduler::on_timer_update(); } void Scheduler::update() { From 2785d08a48115febd939839b859d97e9353a39e5 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:45:39 +0100 Subject: [PATCH 173/281] Fix: uint32_t* cast of a word instead of the ptr --- Src/HALAL/Services/Time/Scheduler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 199fa559f..eca2d7b98 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -40,7 +40,7 @@ uint64_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; uint32_t shift = (idx & 7) << 2; - return (((uint32_t*)sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; + return (((uint32_t*)&sorted_task_ids_)[word_idx] & (0x0F << shift)) >> shift; } inline void Scheduler::set_at(uint8_t idx, uint8_t id) { uint32_t shift = idx*4; @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)sorted_task_ids_)[0] & 0xF; + return ((uint32_t*)&sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From 6cc496ce82d90f6c54f81abe3ad0a078181bd386 Mon Sep 17 00:00:00 2001 From: StefanCostea Date: Sun, 7 Dec 2025 00:45:00 +0100 Subject: [PATCH 174/281] Minor fixes to scheduler Rebased from remotes/origin/MockTim --- Inc/MockedDrivers/common.hpp | 10 ++-- Src/HALAL/Services/Time/Scheduler.cpp | 10 ++-- Tests/Time/scheduler_test.cpp | 83 +++++++++++++++++++++++---- 3 files changed, 84 insertions(+), 19 deletions(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index e94fd853a..80f9d3c91 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -45,7 +45,7 @@ typedef enum #define READ_REG(REG) ((REG)) -#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) @@ -65,7 +65,7 @@ typedef enum do { \ uint32_t val; \ do { \ - val = __LDREXW((__IO uint32_t *)&(REG)) & ~(BIT); \ + val = __LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(BIT); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) @@ -74,7 +74,7 @@ typedef enum do { \ uint32_t val; \ do { \ - val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(CLEARMSK)) | (SETMASK); \ } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ } while(0) @@ -92,7 +92,7 @@ typedef enum do { \ uint16_t val; \ do { \ - val = __LDREXH((__IO uint16_t *)&(REG)) & ~(BIT); \ + val = __LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(BIT); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) @@ -101,6 +101,6 @@ typedef enum do { \ uint16_t val; \ do { \ - val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(CLEARMSK)) | (SETMASK); \ + val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(CLEARMSK)) | (SETMASK); \ } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ } while(0) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index eca2d7b98..eb90bdb2f 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -94,17 +94,17 @@ void Scheduler::start() { Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); - LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); + CLEAR_BIT(Scheduler_global_timer->SR, LL_TIM_SR_UIF); /* clear update interrupt flag */ // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() Scheduler::global_timer_enable(); //Scheduler::schedule_next_interval(); } -SCHEDULER_GLOBAL_TIMER_CALLBACK() { - /* clear update interrupt flag */ - LL_TIM_ClearFlag_UPDATE(Scheduler_global_timer); +SCHEDULER_GLOBAL_TIMER_CALLBACK() { + CLEAR_BIT(Scheduler_global_timer->SR, TIM_SR_UIF); Scheduler::on_timer_update(); } + void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); @@ -183,6 +183,7 @@ void Scheduler::insert_sorted(uint8_t id) { } sorted_task_ids_ = ((uint64_t)hi << 32) | lo; + active_task_count_++; } void Scheduler::remove_sorted(uint8_t id) { @@ -215,6 +216,7 @@ void Scheduler::remove_sorted(uint8_t id) { // Remove element (lower part | higher pushing nibble out of mask) Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); + active_task_count_--; } void Scheduler::schedule_next_interval() { diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index dd61a421e..76d21e778 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -2,32 +2,95 @@ #include #include #include "HALAL/Services/Time/Scheduler.hpp" + int count = 0; void fake_workload(){ count++; } -TEST(SchedulerTests, UsedBitmap) { +class SchedulerTests : public ::testing::Test { +protected: + void SetUp() override { + Scheduler::active_task_count_ = 0; + Scheduler::used_bitmap_ = 0; + Scheduler::ready_bitmap_ = 0; + Scheduler::sorted_task_ids_ = 0; + Scheduler::global_tick_us_ = 0; + Scheduler::current_interval_us_ = 0; + + // Reset global callback task count + count = 0; + + // Reset Timer + TIM2_BASE->CNT = 0; + TIM2_BASE->ARR = 0; + TIM2_BASE->SR = 0; + TIM2_BASE->CR1 = 0; + TIM2_BASE->DIER = 0; + } +}; + +TEST_F(SchedulerTests, UsedBitmap) { Scheduler::register_task(10,&fake_workload); EXPECT_EQ(Scheduler::used_bitmap_,1); } -TEST(SchedulerTests, TaskRegistration) { +TEST_F(SchedulerTests, TaskRegistration) { Scheduler::register_task(10,&fake_workload); EXPECT_EQ(Scheduler::tasks_[0].callback,fake_workload); } -TEST(SchedulerTests, TaskExecution) { +TEST_F(SchedulerTests, TaskExecutionShort) { + Scheduler::register_task(10,&fake_workload); + Scheduler::start(); + // TIM2_BASE->ARR = 500; + // TIM2_BASE->generate_update(); + + constexpr int NUM_TICKS = 1'000; + for(int i = 0; i < NUM_TICKS; i++){ + TIM2_BASE->CNT++; + Scheduler::update(); + } + // 1000 ticks / 10 ticks/task = 100 executions. + EXPECT_EQ(count, 100); +} + +TEST_F(SchedulerTests, TaskExecutionLong) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); + // TIM2_BASE->ARR = 500; + // TIM2_BASE->generate_update(); + constexpr int NUM_TICKS = 1'000'000; - TIM2_BASE->ARR = 500; - TIM2_BASE->generate_update(); - for(int i = 0; i <= NUM_TICKS; i++){ + for(int i = 0; i < NUM_TICKS; i++){ TIM2_BASE->CNT++; Scheduler::update(); } - // one tick is 1us, and we register a task that executes every 10us - // thus it should execute NUM_TICKS/10 - EXPECT_EQ(count,100'000); -} \ No newline at end of file + EXPECT_EQ(count, 100'000); +} + +TEST_F(SchedulerTests, SetTimeout) { + Scheduler::set_timeout(10, &fake_workload); + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++){ + TIM2_BASE->CNT++; + Scheduler::update(); + } + EXPECT_EQ(count, 1); +} + +TEST_F(SchedulerTests, GlobalTickOverflow) { + Scheduler::global_tick_us_ = 0xFFFFFFF0ULL; // Near 32-bit max + Scheduler::register_task(20, &fake_workload); + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++){ + TIM2_BASE->CNT++; + Scheduler::update(); + } + // 100 ticks /20 ticks/task = 5 executions. + EXPECT_EQ(count, 5); +} From 4620c38e2f0fdaadc8df967ddcd77d254bedc1ff Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:48:14 +0100 Subject: [PATCH 175/281] Fix: remove active_task_count_ decrement in pop_front() https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#discussion_r2601565840 --- Src/HALAL/Services/Time/Scheduler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index eb90bdb2f..fb7f809ce 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -53,7 +53,6 @@ inline uint8_t Scheduler::front_id() { } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 - Scheduler::active_task_count_--; Scheduler::sorted_task_ids_ >>= 4; } From ae9f8bbd64630808f1a05ea4b29bc10a2c55ab37 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:53:15 +0100 Subject: [PATCH 176/281] Try fix Wstrict-aliasing in front_id --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index fb7f809ce..af2e12a8b 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)&sorted_task_ids_)[0] & 0xF; + return ((uint32_t*)(void*)&sorted_task_ids_)[0] & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From 2741625c379bc30f4ec5d138d480eedbe1c80dff Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 12:57:24 +0100 Subject: [PATCH 177/281] Try fix Wstrict-aliasing again --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index af2e12a8b..ea23e5e59 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -49,7 +49,7 @@ inline void Scheduler::set_at(uint8_t idx, uint8_t id) { // sorted_task_ids_ |= ((id & 0x0F) << shift); // This is also an option in case id is incorrect, I don't think it's necessary though } inline uint8_t Scheduler::front_id() { - return ((uint32_t*)(void*)&sorted_task_ids_)[0] & 0xF; + return *((uint8_t*)&sorted_task_ids_) & 0xF; } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 From 53cb52f2e1be3430a6844b1cd642b32c01708de1 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 14:43:59 +0100 Subject: [PATCH 178/281] Fix typo in allocate_slot --- Src/HALAL/Services/Time/Scheduler.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index ea23e5e59..4aead65f8 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -121,11 +121,7 @@ inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } // void Scheduler::global_timer_callback() { on_timer_update(); } inline uint8_t Scheduler::allocate_slot() { - /* https://developer.arm.com/documentation/dui0204/j/arm-and-thumb-instructions/general-data-processing-instructions/clz - * clz(0) = 32 -> 32 - clz(0) = 0 - * clz(0xFFFF'FFFF) = 0 -> 32 - clz(0xFFFF'FFFF) > kMaxTasks - */ - uint32_t idx = __builtin_ffs(~Scheduler::free_bitmap_) - 1; + uint32_t idx = __builtin_ffs(Scheduler::free_bitmap_) - 1; if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); Scheduler::active_task_count_++; From 5015af0399af196c557a7f4b978d1951812cb8ea Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 14:47:37 +0100 Subject: [PATCH 179/281] fix: test UsedBitmap -> FreeBitmap --- Tests/Time/scheduler_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 76d21e778..4b4fbddfb 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -30,9 +30,9 @@ class SchedulerTests : public ::testing::Test { } }; -TEST_F(SchedulerTests, UsedBitmap) { +TEST_F(SchedulerTests, FreeBitmap) { Scheduler::register_task(10,&fake_workload); - EXPECT_EQ(Scheduler::used_bitmap_,1); + EXPECT_EQ(Scheduler::free_bitmap_, 0xFFFF'FFFE); } TEST_F(SchedulerTests, TaskRegistration) { From 7865a121e3943ba6fbbd67345cfab92e41dd50b6 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 14:53:24 +0100 Subject: [PATCH 180/281] used_bitmap_ -> free_bitmap_ in test part 2 --- Tests/Time/scheduler_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 4b4fbddfb..5062311d4 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -12,7 +12,7 @@ class SchedulerTests : public ::testing::Test { protected: void SetUp() override { Scheduler::active_task_count_ = 0; - Scheduler::used_bitmap_ = 0; + Scheduler::free_bitmap_ = 0xFFFF'FFFF; Scheduler::ready_bitmap_ = 0; Scheduler::sorted_task_ids_ = 0; Scheduler::global_tick_us_ = 0; From 0108c8aade18605bcfd702997282ca817e23d40e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20S=C3=A1ez?= Date: Tue, 9 Dec 2025 19:35:21 +0100 Subject: [PATCH 181/281] fixed tests discovery --- Tests/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 5f2759919..979dead33 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -1,4 +1,3 @@ -cmake_minimum_required(VERSION 3.14) if(DEFINED STLIB_NAME_SUFFIX) set(STLIB_TEST_EXECUTABLE st-lib-${STLIB_NAME_SUFFIX}-test) else() @@ -31,8 +30,8 @@ target_link_libraries( GTest::gtest_main ${STLIB_LIBRARY} ) + if(MINGW OR CYGWIN) - # Force static linking of libgcc and libstdc++ to avoid DLL version mismatches target_link_options(${STLIB_TEST_EXECUTABLE} PRIVATE -static) endif() From 78db63c8b15b1d00c5c2f011aae9276f32bf8438 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 9 Dec 2025 23:04:15 +0100 Subject: [PATCH 182/281] fix: set_timeout() test --- Src/HALAL/Services/Time/Scheduler.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4aead65f8..92402ac54 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -53,6 +53,7 @@ inline uint8_t Scheduler::front_id() { } inline void Scheduler::pop_front() { // O(1) remove of logical index 0 + Scheduler::active_task_count_--; Scheduler::sorted_task_ids_ >>= 4; } @@ -124,7 +125,6 @@ inline uint8_t Scheduler::allocate_slot() { uint32_t idx = __builtin_ffs(Scheduler::free_bitmap_) - 1; if(idx > static_cast(Scheduler::kMaxTasks)) [[unlikely]] return static_cast(Scheduler::INVALID_ID); - Scheduler::active_task_count_++; Scheduler::free_bitmap_ &= ~(1UL << idx); return static_cast(idx); } @@ -134,7 +134,6 @@ inline void Scheduler::release_slot(uint8_t id) { if(id >= kMaxTasks) [[unlikely]] return; ready_bitmap_ &= ~(1u << id); free_bitmap_ |= (1u << id); - Scheduler::active_task_count_--; } void Scheduler::insert_sorted(uint8_t id) { From eac056adb592e1f08476823260c1c42f52d1d4bf Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 22:53:59 +0100 Subject: [PATCH 183/281] Add a test, fix the error (kind of) --- Inc/HALAL/Services/Time/Scheduler.hpp | 11 ++++++++++- Tests/Time/scheduler_test.cpp | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 5b3a54152..47c3cb3f3 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -50,7 +50,16 @@ struct Scheduler { if(microseconds == 0) [[unlikely]] microseconds = 1; return register_task(microseconds, func, false); } - static inline void cancel_timeout(uint8_t id) { unregister_task(id); } + static inline void cancel_timeout(uint8_t id) { + /* NOTE: This does not fix this case: + 1. id = set_timeout(x, func) + 2. timeout ends, func gets called and removed internally + 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 + 4. clear_timeout(id) -> will remove the second timeout + */ + if(!tasks_[id].repeating) return; + unregister_task(id); + } // static void global_timer_callback(); diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 5062311d4..7dc8f9fb7 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -94,3 +94,22 @@ TEST_F(SchedulerTests, GlobalTickOverflow) { // 100 ticks /20 ticks/task = 5 executions. EXPECT_EQ(count, 5); } + +TEST_F(SchedulerTests, TimeoutClearAddTask) { + uint8_t timeout_id = Scheduler::set_timeout(10, &fake_workload); + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++) { + TIM2_BASE->CNT++; + Scheduler::update(); + } + + // timeout is already done here + uint8_t task_id = Scheduler::register_task(20, &fake_workload); + + // after timeout, cancel task + Scheduler::cancel_timeout(timeout_id); + + EXPECT_EQ(Scheduler::active_task_count_, 1); +} From 1c6d871a8ab450cb4d64cd2c41e081cbe516c980 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 23:19:47 +0100 Subject: [PATCH 184/281] Fix: underflow in schedule_next_interval --- Src/HALAL/Services/Time/Scheduler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 92402ac54..f2d1bf89b 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -223,7 +223,7 @@ void Scheduler::schedule_next_interval() { Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; - uint64_t delta = (next_task.next_fire_us > (global_tick_us_ - 1ULL)) + uint64_t delta = ((next_task.next_fire_us + 1ULL) > global_tick_us_) ? (next_task.next_fire_us - global_tick_us_) : 1ULL; if (delta > kMaxIntervalUs) [[unlikely]] { From 62a2da7b1ee614f938cf8b6d7180439528b0fd35 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 23:51:16 +0100 Subject: [PATCH 185/281] Fix: call schedule_next_interval() in start() --- Src/HALAL/Services/Time/Scheduler.cpp | 5 ++--- Tests/Time/scheduler_test.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index f2d1bf89b..9dff58465 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -95,9 +95,8 @@ void Scheduler::start() { NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); CLEAR_BIT(Scheduler_global_timer->SR, LL_TIM_SR_UIF); /* clear update interrupt flag */ - // NOTE(vic): We don't need to set the flag since there won't be any tasks at the start/it will get set in schedule_next_interval() - Scheduler::global_timer_enable(); - //Scheduler::schedule_next_interval(); + + Scheduler::schedule_next_interval(); } SCHEDULER_GLOBAL_TIMER_CALLBACK() { diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 7dc8f9fb7..e3278f26f 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -59,7 +59,7 @@ TEST_F(SchedulerTests, TaskExecutionLong) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); // TIM2_BASE->ARR = 500; - // TIM2_BASE->generate_update(); + TIM2_BASE->generate_update(); constexpr int NUM_TICKS = 1'000'000; for(int i = 0; i < NUM_TICKS; i++){ From faa596800310a520fbd209771be1857788cb6618 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 10 Dec 2025 23:56:20 +0100 Subject: [PATCH 186/281] Fix: invert condition, that was stupid --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 47c3cb3f3..fa8573923 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -57,7 +57,7 @@ struct Scheduler { 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 4. clear_timeout(id) -> will remove the second timeout */ - if(!tasks_[id].repeating) return; + if(tasks_[id].repeating) return; unregister_task(id); } From 099f54373fada0dd656bd34019d8d33cd34cfe5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gonzalo=20S=C3=A1nchez?= Date: Fri, 12 Dec 2025 01:05:54 +0100 Subject: [PATCH 187/281] feat: add test showcasing possible usage within StateMachine logic --- Tests/Time/scheduler_test.cpp | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index e3278f26f..1d2674cd3 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -113,3 +113,43 @@ TEST_F(SchedulerTests, TimeoutClearAddTask) { EXPECT_EQ(Scheduler::active_task_count_, 1); } + +static volatile int connecting_execs{0}; +static volatile int operational_execs{0}; +static volatile int fault_execs{0}; +void connecting_cyclic(){ + connecting_execs++; +} +void operational_cyclic(){ + operational_execs++; +} +void fault_cyclic(){ + fault_execs++; +} +TEST_F(SchedulerTests, TaskDe_ReRegistration) { + uint8_t connecting_task = Scheduler::register_task(10, &connecting_cyclic); + uint8_t operational_task = 0; + uint8_t fault_task = 0; + Scheduler::start(); + + constexpr int NUM_TICKS = 100; + for(int i = 0; i < NUM_TICKS; i++) { + TIM2_BASE->CNT++; + if(i == 21){ + Scheduler::unregister_task(connecting_task); + operational_task = Scheduler::register_task(10,operational_cyclic); + } + if(i == 45){ + Scheduler::unregister_task(operational_task); + fault_task = Scheduler::register_task(10,fault_cyclic); + } + if( i == 70){ + Scheduler::unregister_task(fault_task); + i = 100; // finish test + } + Scheduler::update(); + } + EXPECT_EQ(connecting_execs, 2); + EXPECT_EQ(operational_execs, 2); + EXPECT_EQ(fault_execs, 2); +} From 4233fc746b4e17f44f3f2f68fdb5cd3945b788db Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 13 Dec 2025 22:37:31 +0100 Subject: [PATCH 188/281] fix: Calculate correct prescaler & add to HALAL.hpp --- Inc/HALAL/HALAL.hpp | 1 + Inc/HALAL/Services/Time/Scheduler.hpp | 17 ++++---- Src/HALAL/Services/Time/Scheduler.cpp | 61 +++++++++++++++++++++++---- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index 316c9605a..bc896cce3 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -21,6 +21,7 @@ #include "HALAL/Services/PWM/DualPhasedPWM/DualPhasedPWM.hpp" #include "HALAL/Services/Time/Time.hpp" +#include "HALAL/Services/Time/Scheduler.hpp" #include "HALAL/Services/Time/RTC.hpp" #include "HALAL/Services/InputCapture/InputCapture.hpp" diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index fa8573923..5e7bde703 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -22,16 +22,17 @@ # define SCHEDULER_TIMER_IDX 2 #endif - #define glue_(a,b) a ## b - #define glue(a,b) glue_(a,b) - #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) +#define glue_(a,b) a ## b +#define glue(a,b) glue_(a,b) +#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) // Used to reserve a TimerPeripheral #ifndef TESTING_ENV - #include "stm32h7xx_hal_tim.h" - #define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) - extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; +#include "stm32h7xx_hal_tim.h" +#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX) +extern TIM_HandleTypeDef SCHEDULER_HAL_TIM; #endif + struct Scheduler { using callback_t = void (*)(); static constexpr uint32_t INVALID_ID = 0xFFu; @@ -79,14 +80,14 @@ struct Scheduler { static constexpr std::size_t kMaxTasks = 16; static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); - static constexpr uint32_t kBaseClockHz = 1'000'000u; + static constexpr uint32_t FREQUENCY = 1'000'000u; // 1 MHz -> 1us precision static std::array tasks_; static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change"); /* sorted_task_ids_ is a sorted queue with 4bits for each id in the scheduler's current ids */ static uint64_t sorted_task_ids_; - static std::size_t active_task_count_; + static uint32_t active_task_count_; static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change"); static uint32_t ready_bitmap_; static uint32_t free_bitmap_; diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9dff58465..bd4b840b2 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -30,7 +30,7 @@ constexpr uint64_t kMaxIntervalUs = std::array Scheduler::tasks_{}; uint64_t Scheduler::sorted_task_ids_ = 0; -std::size_t Scheduler::active_task_count_{0}; +uint32_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; @@ -70,10 +70,54 @@ inline void Scheduler::global_timer_enable() { // ---------------------------- void Scheduler::start() { - static_assert(kBaseClockHz % 1'000'000u == 0u, "Base clock must be a multiple of 1MHz"); + static_assert((Scheduler::FREQUENCY % 1'000'000) == 0u, "frequenct must be a multiple of 1MHz"); + + + uint32_t prescaler = (SystemCoreClock / Scheduler::FREQUENCY); + // setup prescaler + { + // ref manual: section 8.7.7 RCC domain 1 clock configuration register + uint32_t ahb_prescaler = RCC->D1CFGR & RCC_D1CFGR_HPRE_Msk; + if((ahb_prescaler & 0b1000) != 0) { + switch(ahb_prescaler) { + case 0b1000: prescaler /= 2; break; + case 0b1001: prescaler /= 4; break; + case 0b1010: prescaler /= 8; break; + case 0b1011: prescaler /= 16; break; + case 0b1100: prescaler /= 64; break; + case 0b1101: prescaler /= 128; break; + case 0b1110: prescaler /= 256; break; + case 0b1111: prescaler /= 512; break; + } + } + + // ref manual: section 8.7.8: RCC domain 2 clock configuration register + uint32_t apb1_prescaler = (RCC->D2CFGR & RCC_D2CFGR_D2PPRE1_Msk) >> RCC_D2CFGR_D2PPRE1_Pos; + if((apb1_prescaler & 0b100) != 0) { + switch(apb1_prescaler) { + case 0b100: prescaler /= 2; break; + case 0b101: prescaler /= 4; break; + case 0b110: prescaler /= 8; break; + case 0b111: prescaler /= 16; break; + } + } + // tim2clk = 2 x pclk1 when apb1_prescaler != 1 + if(apb1_prescaler != 1) { + prescaler *= 2; + } + + if(prescaler > 1) { + prescaler--; + } + } - const uint32_t prescaler = (kBaseClockHz / 1'000'000u) - 1u; - static_assert(prescaler < 0xFFFF'FFFF, "Prescaler is 16 bit, so it must be in that range"); + // TODO: Fault when any of the next 2 static asserts happen (needs to be runtime bcos of SystemCoreClock) + if(prescaler == 0 || prescaler > 0xFFFF) { + // error here + } + + //static_assert(prescaler < 0xFFFF, "Prescaler is 16 bit, so it must be in that range"); + //static_assert(prescaler != 0, "Prescaler must be in the range [1, 65535]"); #ifndef TESTING_ENV // Register a TimerPeripheral so it's not used anywhere else @@ -140,7 +184,7 @@ void Scheduler::insert_sorted(uint8_t id) { // binary search on logical range [0, active_task_count_) std::size_t left = 0; - std::size_t right = active_task_count_; + std::size_t right = Scheduler::active_task_count_; while (left < right) { std::size_t mid = left + ((right - left) / 2); const Task& mid_task = tasks_[Scheduler::get_at(mid)]; @@ -155,6 +199,7 @@ void Scheduler::insert_sorted(uint8_t id) { uint32_t lo = (uint32_t)sorted_task_ids_; uint32_t hi = (uint32_t)(sorted_task_ids_ >> 32); + // take the shift for only high or low 32 bits uint32_t shift = (pos & 7) << 2; uint32_t id_shifted = id << shift; @@ -167,7 +212,7 @@ void Scheduler::insert_sorted(uint8_t id) { uint32_t hi_spilled = (hi << 4) | (lo >> 28); - if (pos >= 8) { //this can be done without branching + if (pos >= 8) { hi = hi_modified; // lo remains unchanged } else { @@ -176,7 +221,7 @@ void Scheduler::insert_sorted(uint8_t id) { } sorted_task_ids_ = ((uint64_t)hi << 32) | lo; - active_task_count_++; + Scheduler::active_task_count_++; } void Scheduler::remove_sorted(uint8_t id) { @@ -209,7 +254,7 @@ void Scheduler::remove_sorted(uint8_t id) { // Remove element (lower part | higher pushing nibble out of mask) Scheduler::sorted_task_ids_ = (Scheduler::sorted_task_ids_ & mask) | ((Scheduler::sorted_task_ids_ >> 4) & ~mask); - active_task_count_--; + Scheduler::active_task_count_--; } void Scheduler::schedule_next_interval() { From 60f20bd215a9e44adf21a6a476db1710c9dae533 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 13 Dec 2025 23:19:12 +0100 Subject: [PATCH 189/281] Try to fix tests --- CMakeLists.txt | 1 + Inc/MockedDrivers/stm32h723xx_wrapper.h | 11 +++++++++++ Src/MockedDrivers/mocked_system_stm32h7xx.c | 3 +++ Tests/Time/scheduler_test.cpp | 3 +++ 4 files changed, 18 insertions(+) create mode 100644 Inc/MockedDrivers/stm32h723xx_wrapper.h create mode 100644 Src/MockedDrivers/mocked_system_stm32h7xx.c diff --git a/CMakeLists.txt b/CMakeLists.txt index e015bfde2..c132f4b97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -225,6 +225,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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/mocked_system_stm32h7xx.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h new file mode 100644 index 000000000..5b4e5de63 --- /dev/null +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -0,0 +1,11 @@ +#ifndef STM32H723xx_WRAPPER_H +#define STM32H723xx_WRAPPER_H + +#include "stm32h723xx.h" + +#undef RCC + +RCC_TypeDef RCC_struct; +RCC_TypeDef *RCC = &RCC_struct; + +#endif // STM32H723xx_WRAPPER_H diff --git a/Src/MockedDrivers/mocked_system_stm32h7xx.c b/Src/MockedDrivers/mocked_system_stm32h7xx.c new file mode 100644 index 000000000..869e20d3c --- /dev/null +++ b/Src/MockedDrivers/mocked_system_stm32h7xx.c @@ -0,0 +1,3 @@ +#include + +uint32_t SystemCoreClock = 64000000; diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 1d2674cd3..9988ca927 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -1,6 +1,9 @@ #include #include #include + +#include "stm32h723xx_wrapper.h" + #include "HALAL/Services/Time/Scheduler.hpp" int count = 0; From ed7db139e439dc9ea026474ea8ed4722996725f2 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 13 Dec 2025 23:25:14 +0100 Subject: [PATCH 190/281] try to fix tests part 2 --- Tests/Time/scheduler_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 9988ca927..cda8586b3 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -2,7 +2,7 @@ #include #include -#include "stm32h723xx_wrapper.h" +#include "Inc/MockedDrivers/stm32h723xx_wrapper.h" #include "HALAL/Services/Time/Scheduler.hpp" From a32be3fec77b5dd9a80c8306d49eab6e3beae22e Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 00:34:04 +0100 Subject: [PATCH 191/281] Try to fix tests part 3 --- Inc/MockedDrivers/stm32h723xx_wrapper.h | 3 +-- Src/MockedDrivers/stm32h723xx_wrapper.c | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 Src/MockedDrivers/stm32h723xx_wrapper.c diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index 5b4e5de63..a7cf435f3 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -5,7 +5,6 @@ #undef RCC -RCC_TypeDef RCC_struct; -RCC_TypeDef *RCC = &RCC_struct; +extern RCC_TypeDef *RCC; #endif // STM32H723xx_WRAPPER_H diff --git a/Src/MockedDrivers/stm32h723xx_wrapper.c b/Src/MockedDrivers/stm32h723xx_wrapper.c new file mode 100644 index 000000000..cdb9e487a --- /dev/null +++ b/Src/MockedDrivers/stm32h723xx_wrapper.c @@ -0,0 +1,4 @@ +#include "stm32h7xx_wrapper.h" + +static RCC_TypeDef RCC_struct; +RCC_TypeDef *RCC = &RCC_struct; From 3fc8ad35c782c4a38f36f5045514ab7cca7a74fe Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 00:35:12 +0100 Subject: [PATCH 192/281] part 4 - add the wrapper.c to cmake, will this work? --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c132f4b97..62a07eeb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,6 +226,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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/mocked_system_stm32h7xx.c> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h7xx_wrapper.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) From d75885320a55ccde38e6c1f52c11b0bb4a28202a Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 00:44:10 +0100 Subject: [PATCH 193/281] part 5 - fix cmake stm32h723xx_wrapper.c path --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62a07eeb9..232354bb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,7 +226,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$>:${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/mocked_system_stm32h7xx.c> - $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h7xx_wrapper.c> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h723xx_wrapper.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp> ) From 4a39519f3b379a285bbe89f6efcece2410f0092c Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 11:56:59 +0100 Subject: [PATCH 194/281] fix: try to fix tests part 6 --- CMakeLists.txt | 6 +- Inc/MockedDrivers/NVIC.hpp | 154 +----------------------- Inc/MockedDrivers/compiler_specific.hpp | 8 ++ Inc/MockedDrivers/ll_tim_interface.h | 3 +- Inc/MockedDrivers/mocked_ll_tim.hpp | 3 + Inc/MockedDrivers/stm32h723xx_wrapper.h | 21 ++++ Src/MockedDrivers/stm32h723xx_wrapper.c | 2 +- Tests/Time/scheduler_test.cpp | 2 - 8 files changed, 41 insertions(+), 158 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 232354bb2..9c9f88bc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -274,8 +274,10 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE target_include_directories(${STLIB_LIBRARY} PUBLIC # CMSIS + HAL - $<$:${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include> - $<$:${STM32CUBEH7}/Drivers/CMSIS/Include> + #$<$:${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include> + #$<$:${STM32CUBEH7}/Drivers/CMSIS/Include> + ${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include + ${STM32CUBEH7}/Drivers/CMSIS/Include $<$:${STM32CUBEH7}/Drivers/CMSIS/Core_A/Include> $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc> $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy> diff --git a/Inc/MockedDrivers/NVIC.hpp b/Inc/MockedDrivers/NVIC.hpp index 7e8b03234..4694f9011 100644 --- a/Inc/MockedDrivers/NVIC.hpp +++ b/Inc/MockedDrivers/NVIC.hpp @@ -1,6 +1,6 @@ #pragma once - +#include "stm32h723xx_wrapper.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/compiler_specific.hpp" @@ -21,157 +21,7 @@ class NVIC_Type uint32_t RESERVED5[644U]; volatile uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ }; -enum IRQn_Type -{ -/****** Cortex-M Processor Exceptions Numbers *****************************************************************/ - NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ - HardFault_IRQn = -13, /*!< 3 Cortex-M Hard Fault Interrupt */ - MemoryManagement_IRQn = -12, /*!< 4 Cortex-M Memory Management Interrupt */ - BusFault_IRQn = -11, /*!< 5 Cortex-M Bus Fault Interrupt */ - UsageFault_IRQn = -10, /*!< 6 Cortex-M Usage Fault Interrupt */ - SVCall_IRQn = -5, /*!< 11 Cortex-M SV Call Interrupt */ - DebugMonitor_IRQn = -4, /*!< 12 Cortex-M Debug Monitor Interrupt */ - PendSV_IRQn = -2, /*!< 14 Cortex-M Pend SV Interrupt */ - SysTick_IRQn = -1, /*!< 15 Cortex-M System Tick Interrupt */ -/****** STM32 specific Interrupt Numbers **********************************************************************/ - WWDG_IRQn = 0, /*!< Window WatchDog Interrupt ( wwdg1_it, wwdg2_it) */ - PVD_AVD_IRQn = 1, /*!< PVD/AVD through EXTI Line detection Interrupt */ - TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ - RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ - FLASH_IRQn = 4, /*!< FLASH global Interrupt */ - RCC_IRQn = 5, /*!< RCC global Interrupt */ - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ - EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ - EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ - EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ - DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ - DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ - DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ - DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ - DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ - DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ - DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ - ADC_IRQn = 18, /*!< ADC1 and ADC2 global Interrupts */ - FDCAN1_IT0_IRQn = 19, /*!< FDCAN1 Interrupt line 0 */ - FDCAN2_IT0_IRQn = 20, /*!< FDCAN2 Interrupt line 0 */ - FDCAN1_IT1_IRQn = 21, /*!< FDCAN1 Interrupt line 1 */ - FDCAN2_IT1_IRQn = 22, /*!< FDCAN2 Interrupt line 1 */ - EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ - TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */ - TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ - TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */ - TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ - TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ - TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ - TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ - I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ - I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ - I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ - I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ - SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ - SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ - USART1_IRQn = 37, /*!< USART1 global Interrupt */ - USART2_IRQn = 38, /*!< USART2 global Interrupt */ - USART3_IRQn = 39, /*!< USART3 global Interrupt */ - EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ - RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ - TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ - TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ - TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ - TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ - DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ - FMC_IRQn = 48, /*!< FMC global Interrupt */ - SDMMC1_IRQn = 49, /*!< SDMMC1 global Interrupt */ - TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ - SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ - UART4_IRQn = 52, /*!< UART4 global Interrupt */ - UART5_IRQn = 53, /*!< UART5 global Interrupt */ - TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ - TIM7_IRQn = 55, /*!< TIM7 global interrupt */ - DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ - DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ - DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ - DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ - DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ - ETH_IRQn = 61, /*!< Ethernet global Interrupt */ - ETH_WKUP_IRQn = 62, /*!< Ethernet Wakeup through EXTI line Interrupt */ - FDCAN_CAL_IRQn = 63, /*!< FDCAN Calibration unit Interrupt */ - DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ - DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ - DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ - USART6_IRQn = 71, /*!< USART6 global interrupt */ - I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ - I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ - OTG_HS_EP1_OUT_IRQn = 74, /*!< USB OTG HS End Point 1 Out global interrupt */ - OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */ - OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */ - OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */ - DCMI_PSSI_IRQn = 78, /*!< DCMI and PSSI global interrupt */ - RNG_IRQn = 80, /*!< RNG global interrupt */ - FPU_IRQn = 81, /*!< FPU global interrupt */ - UART7_IRQn = 82, /*!< UART7 global interrupt */ - UART8_IRQn = 83, /*!< UART8 global interrupt */ - SPI4_IRQn = 84, /*!< SPI4 global Interrupt */ - SPI5_IRQn = 85, /*!< SPI5 global Interrupt */ - SPI6_IRQn = 86, /*!< SPI6 global Interrupt */ - SAI1_IRQn = 87, /*!< SAI1 global Interrupt */ - LTDC_IRQn = 88, /*!< LTDC global Interrupt */ - LTDC_ER_IRQn = 89, /*!< LTDC Error global Interrupt */ - DMA2D_IRQn = 90, /*!< DMA2D global Interrupt */ - OCTOSPI1_IRQn = 92, /*!< OCTOSPI1 global interrupt */ - LPTIM1_IRQn = 93, /*!< LP TIM1 interrupt */ - CEC_IRQn = 94, /*!< HDMI-CEC global Interrupt */ - I2C4_EV_IRQn = 95, /*!< I2C4 Event Interrupt */ - I2C4_ER_IRQn = 96, /*!< I2C4 Error Interrupt */ - SPDIF_RX_IRQn = 97, /*!< SPDIF-RX global Interrupt */ - DMAMUX1_OVR_IRQn = 102, /*! -#define TIM1 +//#define TIM1 /** @addtogroup STM32H7xx_LL_Driver * @{ diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 41897a666..091d8b435 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include "MockedDrivers/stm32h723xx_wrapper.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/tim_register_definitions.hpp" @@ -129,5 +130,7 @@ struct RegisterTraits { TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler,TIM_IDX##_IRQn}; \ TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; +#undef TIM1_BASE DECLARE_TIMER(TIM1) +#undef TIM2_BASE DECLARE_TIMER(TIM2) diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index a7cf435f3..543ccc993 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -1,8 +1,29 @@ #ifndef STM32H723xx_WRAPPER_H #define STM32H723xx_WRAPPER_H +#include +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __IO volatile + +// necessary remove of some warnings due to cmsis made for 32 bit arch and not 64 bit arch +#define __RBIT __RBIT__CMSIS +#define TIM_TypeDef TIM_TypeDef__CMSIS +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" + +// don't do anything in "core_cm7.h" +#define __CORE_CM7_H_GENERIC +#define __CORE_CM7_H_DEPENDANT #include "stm32h723xx.h" +#pragma GCC diagnostic pop +#undef __RBIT +#undef TIM_TypeDef + #undef RCC extern RCC_TypeDef *RCC; diff --git a/Src/MockedDrivers/stm32h723xx_wrapper.c b/Src/MockedDrivers/stm32h723xx_wrapper.c index cdb9e487a..f8da31ebb 100644 --- a/Src/MockedDrivers/stm32h723xx_wrapper.c +++ b/Src/MockedDrivers/stm32h723xx_wrapper.c @@ -1,4 +1,4 @@ -#include "stm32h7xx_wrapper.h" +#include "MockedDrivers/stm32h723xx_wrapper.h" static RCC_TypeDef RCC_struct; RCC_TypeDef *RCC = &RCC_struct; diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index cda8586b3..8ef34f56f 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -2,8 +2,6 @@ #include #include -#include "Inc/MockedDrivers/stm32h723xx_wrapper.h" - #include "HALAL/Services/Time/Scheduler.hpp" int count = 0; From 0fcf86ed90ee57eaa9bc1b23df73c92dc65acdbf Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 12:00:36 +0100 Subject: [PATCH 195/281] fix: volatile warnings --- Tests/Time/scheduler_test.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 8ef34f56f..6a57b9374 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -119,13 +119,16 @@ static volatile int connecting_execs{0}; static volatile int operational_execs{0}; static volatile int fault_execs{0}; void connecting_cyclic(){ - connecting_execs++; + auto next_connecting_execs = connecting_execs + 1; + connecting_execs = next_connecting_execs; } void operational_cyclic(){ - operational_execs++; + auto next_operational_execs = operational_execs + 1; + operational_execs = next_operational_execs; } void fault_cyclic(){ - fault_execs++; + auto next_fault_execs = fault_execs + 1; + fault_execs = next_fault_execs; } TEST_F(SchedulerTests, TaskDe_ReRegistration) { uint8_t connecting_task = Scheduler::register_task(10, &connecting_cyclic); From 355a790fcf904dd65cfbcd5f462addf11ee9a1b4 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 12:42:26 +0100 Subject: [PATCH 196/281] fix: active_PSC is now set when PSC is set --- Inc/MockedDrivers/Register.hpp | 3 ++- Inc/MockedDrivers/mocked_ll_tim.hpp | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Inc/MockedDrivers/Register.hpp b/Inc/MockedDrivers/Register.hpp index e133993a7..bce0d5dba 100644 --- a/Inc/MockedDrivers/Register.hpp +++ b/Inc/MockedDrivers/Register.hpp @@ -109,7 +109,8 @@ class RegisterBase { operator uint32_t() const { return reg; } -private: + +protected: void set(uint32_t val) { RegisterTraits::write(this->reg, val); } diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 091d8b435..9ecc3c473 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -23,14 +23,29 @@ class TimerRegister : public RegisterBase { using RegisterBase::operator=; }; + static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); class TIM_TypeDef{ public: TIM_TypeDef(void(* irq_handler)(void),IRQn_Type irq_n): - callback{irq_handler},irq_n{irq_n} +// PSC(*this), callback{irq_handler}, irq_n{irq_n} + callback{irq_handler}, irq_n{irq_n} {} + + // NOTE: This ruins the address offsets but I couldn't get it to work any other way + template + struct PrescalerRegister : public RegisterBase { + PrescalerRegister& operator=(uint32_t val) { + this->set(val); + // esto es lo más feo que he hecho en mucho tiempo pero no he conseguido otra cosa + TIM_TypeDef *parent = (TIM_TypeDef*)((uint8_t*)&this->reg - offsetof(TIM_TypeDef, PSC)); + parent->active_PSC = val; + return *this; + } + }; + void generate_update(); TimerRegister CR1; /*!< TIM control register 1, Address offset: 0x00 */ TimerRegister CR2; /*!< TIM control register 2, Address offset: 0x04 */ @@ -42,7 +57,7 @@ class TIM_TypeDef{ TimerRegister CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ TimerRegister CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ TimerRegister CNT; /*!< TIM counter register, Address offset: 0x24 */ - TimerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ + PrescalerRegister PSC; /*!< TIM prescaler, Address offset: 0x28 */ TimerRegister ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ TimerRegister RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ TimerRegister CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ From 1dce251de26018416b538377abfc902bc09350f0 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 12:50:12 +0100 Subject: [PATCH 197/281] fix: remove outdated comment --- Inc/MockedDrivers/mocked_ll_tim.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 9ecc3c473..118b6e8cb 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -34,7 +34,6 @@ class TIM_TypeDef{ callback{irq_handler}, irq_n{irq_n} {} - // NOTE: This ruins the address offsets but I couldn't get it to work any other way template struct PrescalerRegister : public RegisterBase { PrescalerRegister& operator=(uint32_t val) { From beb2e20e8535980959b27b7a182304f2d1c1a4e9 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 16:04:46 +0100 Subject: [PATCH 198/281] fix: tests part 7, should work now --- Inc/MockedDrivers/mocked_ll_tim.hpp | 5 ++++- Src/MockedDrivers/mocked_ll_tim.cpp | 9 ++++++++- Tests/Time/scheduler_test.cpp | 25 +++++++++++++++---------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 118b6e8cb..032656be5 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -119,10 +119,13 @@ class TIM_TypeDef{ } return true; } + + void inc_cnt_and_check(uint32_t val); }; static_assert(sizeof(TimerRegister) == sizeof(uint32_t)); void simulate_ticks(TIM_TypeDef* tim); +/* template<> struct RegisterTraits { static void write(uint32_t& target, uint32_t val) { @@ -133,7 +136,7 @@ struct RegisterTraits { } } }; - +*/ #define DECLARE_TIMER(TIM_IDX) \ extern TIM_TypeDef* TIM_IDX##_BASE; \ diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index 4f4ceb413..2d1dd0edb 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -10,7 +10,7 @@ void TIM_TypeDef::generate_update() { active_RCR = RCR; internal_rcr_cnt = active_RCR; internal_psc_cnt = 0; - CNT = 0; // Usually UEV also resets CNT unless configured otherwise + *((uint32_t*)&CNT) = 0; // Usually UEV also resets CNT unless configured otherwise SR &= ~(1U << 0); // Clear UIF if needed, or set it depending on CR1 } void simulate_ticks(TIM_TypeDef* tim){ @@ -58,4 +58,11 @@ void simulate_ticks(TIM_TypeDef* tim){ tim->internal_rcr_cnt--; } } +} + +void TIM_TypeDef::inc_cnt_and_check(uint32_t val) { + if(val != 0 && this->check_CNT_increase_preconditions()){ + this->CNT += val; + simulate_ticks(this); + } } \ No newline at end of file diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 6a57b9374..e111dc3e8 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -44,12 +44,11 @@ TEST_F(SchedulerTests, TaskRegistration) { TEST_F(SchedulerTests, TaskExecutionShort) { Scheduler::register_task(10,&fake_workload); Scheduler::start(); - // TIM2_BASE->ARR = 500; - // TIM2_BASE->generate_update(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 1'000; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } // 1000 ticks / 10 ticks/task = 100 executions. @@ -61,10 +60,11 @@ TEST_F(SchedulerTests, TaskExecutionLong) { Scheduler::start(); // TIM2_BASE->ARR = 500; TIM2_BASE->generate_update(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 1'000'000; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } EXPECT_EQ(count, 100'000); @@ -73,10 +73,11 @@ TEST_F(SchedulerTests, TaskExecutionLong) { TEST_F(SchedulerTests, SetTimeout) { Scheduler::set_timeout(10, &fake_workload); Scheduler::start(); - + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } EXPECT_EQ(count, 1); @@ -86,10 +87,12 @@ TEST_F(SchedulerTests, GlobalTickOverflow) { Scheduler::global_tick_us_ = 0xFFFFFFF0ULL; // Near 32-bit max Scheduler::register_task(20, &fake_workload); Scheduler::start(); - + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++){ - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); + Scheduler::update(); } // 100 ticks /20 ticks/task = 5 executions. @@ -99,10 +102,11 @@ TEST_F(SchedulerTests, GlobalTickOverflow) { TEST_F(SchedulerTests, TimeoutClearAddTask) { uint8_t timeout_id = Scheduler::set_timeout(10, &fake_workload); Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++) { - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } @@ -135,10 +139,11 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { uint8_t operational_task = 0; uint8_t fault_task = 0; Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 100; for(int i = 0; i < NUM_TICKS; i++) { - TIM2_BASE->CNT++; + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); if(i == 21){ Scheduler::unregister_task(connecting_task); operational_task = Scheduler::register_task(10,operational_cyclic); From d55ab65c032120c62e2ef9d386ac7c63224f3f34 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 14 Dec 2025 16:07:04 +0100 Subject: [PATCH 199/281] fix: remove unecessary if, return if cancelled in cancel_timeout --- Inc/HALAL/Services/Time/Scheduler.hpp | 6 +++--- Src/HALAL/Services/Time/Scheduler.cpp | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 5e7bde703..66602aac7 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -51,15 +51,15 @@ struct Scheduler { if(microseconds == 0) [[unlikely]] microseconds = 1; return register_task(microseconds, func, false); } - static inline void cancel_timeout(uint8_t id) { + static inline bool cancel_timeout(uint8_t id) { /* NOTE: This does not fix this case: 1. id = set_timeout(x, func) 2. timeout ends, func gets called and removed internally 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 4. clear_timeout(id) -> will remove the second timeout */ - if(tasks_[id].repeating) return; - unregister_task(id); + if(tasks_[id].repeating) return false; + return unregister_task(id); } // static void global_timer_callback(); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index bd4b840b2..4a671ca5e 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -173,8 +173,6 @@ inline uint8_t Scheduler::allocate_slot() { } inline void Scheduler::release_slot(uint8_t id) { - // NOTE: This condition shouldn't be here since it's an internal function but it could be an assert - if(id >= kMaxTasks) [[unlikely]] return; ready_bitmap_ &= ~(1u << id); free_bitmap_ |= (1u << id); } From f87675e5bee0d85a61a48f293f5e12f08721f4f3 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 12:11:31 +0100 Subject: [PATCH 200/281] Pop all due tasks, several might be due in the same tick --- Src/HALAL/Services/Time/Scheduler.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 4a671ca5e..3cb0fd0ea 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -288,14 +288,20 @@ inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { void Scheduler::on_timer_update() { global_tick_us_ += current_interval_us_; - uint8_t candidate_id = Scheduler::front_id(); - Task& task = tasks_[candidate_id]; - pop_front(); - ready_bitmap_ |= (1u << candidate_id); // mark task as ready - - if (task.repeating) [[likely]] { - task.next_fire_us = global_tick_us_ + task.period_us; - insert_sorted(candidate_id); + // pop all due tasks, several might be due in the same tick + while(active_task_count_ > 0) { + uint8_t candidate_id = Scheduler::front_id(); + Task& task = tasks_[candidate_id]; + if(task.next_fire_us > Scheduler::global_tick_us_) [[likely]] { + break; // task is in the future, stop processing + } + pop_front(); + ready_bitmap_ |= (1u << candidate_id); // mark task as ready + + if (task.repeating) [[likely]] { + task.next_fire_us = global_tick_us_ + task.period_us; + insert_sorted(candidate_id); + } } schedule_next_interval(); From d2d9f8c91b31b8166dcf12b0fa0d0f7349405c05 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 12:58:50 +0100 Subject: [PATCH 201/281] Revert force-push --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 34 +++++++++++++-------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 66602aac7..fe513682b 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -92,7 +92,7 @@ struct Scheduler { static uint32_t ready_bitmap_; static uint32_t free_bitmap_; static uint64_t global_tick_us_; - static uint64_t current_interval_us_; + static uint32_t current_interval_us_; static inline uint8_t allocate_slot(); static inline void release_slot(uint8_t id); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 3cb0fd0ea..24b7aa3fa 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -25,7 +25,7 @@ #define Scheduler_global_timer ((TIM_TypeDef*)SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = - static_cast(std::numeric_limits::max()) + 1ULL; + static_cast(std::numeric_limits::max())/2 + 1ULL; } std::array Scheduler::tasks_{}; @@ -35,7 +35,7 @@ uint32_t Scheduler::active_task_count_{0}; uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; -uint64_t Scheduler::current_interval_us_{0}; +uint32_t Scheduler::current_interval_us_{0}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; @@ -160,8 +160,6 @@ void Scheduler::update() { } } -inline uint64_t Scheduler::get_global_tick() { return global_tick_us_; } - // void Scheduler::global_timer_callback() { on_timer_update(); } inline uint8_t Scheduler::allocate_slot() { @@ -186,7 +184,7 @@ void Scheduler::insert_sorted(uint8_t id) { while (left < right) { std::size_t mid = left + ((right - left) / 2); const Task& mid_task = tasks_[Scheduler::get_at(mid)]; - if (mid_task.next_fire_us <= task.next_fire_us) { + if ((int32_t)(task.next_fire_us - mid_task.next_fire_us) >= 0) { left = mid + 1; } else { right = mid; @@ -265,14 +263,14 @@ void Scheduler::schedule_next_interval() { Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; - uint64_t delta = ((next_task.next_fire_us + 1ULL) > global_tick_us_) - ? (next_task.next_fire_us - global_tick_us_) : 1ULL; - - if (delta > kMaxIntervalUs) [[unlikely]] { - current_interval_us_ = kMaxIntervalUs; + int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); + uint32_t delta; + if (diff <= 0) [[unlikely]]{ + delta = 1; // Task is due or overdue } else { - current_interval_us_ = delta; + delta = static_cast(diff); } + current_interval_us_ = delta; configure_timer_for_interval(current_interval_us_); } @@ -288,18 +286,18 @@ inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { void Scheduler::on_timer_update() { global_tick_us_ += current_interval_us_; - // pop all due tasks, several might be due in the same tick - while(active_task_count_ > 0) { + while (active_task_count_ > 0) { //Pop all due tasks, several might be due in the same tick uint8_t candidate_id = Scheduler::front_id(); Task& task = tasks_[candidate_id]; - if(task.next_fire_us > Scheduler::global_tick_us_) [[likely]] { - break; // task is in the future, stop processing + int32_t diff = (int32_t)(task.next_fire_us - static_cast(global_tick_us_)); + if (diff > 0) [[likely]]{ + break; // Task is in the future, stop processing } pop_front(); ready_bitmap_ |= (1u << candidate_id); // mark task as ready if (task.repeating) [[likely]] { - task.next_fire_us = global_tick_us_ + task.period_us; + task.next_fire_us = static_cast(global_tick_us_ + task.period_us); insert_sorted(candidate_id); } } @@ -309,6 +307,7 @@ void Scheduler::on_timer_update() { uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repeating) { if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + if(period_us >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); uint8_t slot = allocate_slot(); if(slot == Scheduler::INVALID_ID) return slot; @@ -317,8 +316,7 @@ uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repea task.callback = func; task.period_us = period_us; task.repeating = repeating; - task.next_fire_us = global_tick_us_ + period_us; - + task.next_fire_us = static_cast(global_tick_us_ + period_us); insert_sorted(slot); schedule_next_interval(); return slot; From 09c20487d2abdd90100578e1b3ee8c7d82fd2d30 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 13:10:57 +0100 Subject: [PATCH 202/281] fix: off by one error + configure_timer_for_interval should use uint32_t --- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Src/HALAL/Services/Time/Scheduler.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index fe513682b..140382a49 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -99,7 +99,7 @@ struct Scheduler { static void insert_sorted(uint8_t id); static void remove_sorted(uint8_t id); static void schedule_next_interval(); - static inline void configure_timer_for_interval(uint64_t microseconds); + static inline void configure_timer_for_interval(uint32_t microseconds); static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); // helpers diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 24b7aa3fa..e77d74d02 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -265,8 +265,8 @@ void Scheduler::schedule_next_interval() { Task& next_task = tasks_[next_id]; int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); uint32_t delta; - if (diff <= 0) [[unlikely]]{ - delta = 1; // Task is due or overdue + if (diff <= 1) [[unlikely]]{ + delta = 2; // Task is due or overdue } else { delta = static_cast(diff); } @@ -275,7 +275,7 @@ void Scheduler::schedule_next_interval() { configure_timer_for_interval(current_interval_us_); } -inline void Scheduler::configure_timer_for_interval(uint64_t microseconds) { +inline void Scheduler::configure_timer_for_interval(uint32_t microseconds) { // NOTE(vic): disabling the timer _might_ be necessary to prevent the timer from firing in the middle of configuring it, highly unlikely since it has a period of at least 1 microsecond // TODO(vic): Validation: check arr is set correctly here: https://github.com/HyperloopUPV-H8/ST-LIB/pull/534#pullrequestreview-3529132356 Scheduler_global_timer->ARR = static_cast(microseconds - 1u); From 51e71e9ab3eaeface8a0ff856695d5ca3c128dd3 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 15:53:20 +0100 Subject: [PATCH 203/281] fix: off by one error in schedule_next_interval() --- Inc/MockedDrivers/mocked_ll_tim.hpp | 5 +---- Src/HALAL/Services/Time/Scheduler.cpp | 12 ++++++------ Tests/Time/scheduler_test.cpp | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 032656be5..2132cfb78 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -114,10 +114,7 @@ class TIM_TypeDef{ } // If prescaler didn't overflow, the main counter doesn't move. - if (!main_counter_tick) { - return false; - } - return true; + return main_counter_tick; } void inc_cnt_and_check(uint32_t val); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index e77d74d02..9124e3476 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -264,15 +264,15 @@ void Scheduler::schedule_next_interval() { uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); - uint32_t delta; if (diff <= 1) [[unlikely]]{ - delta = 2; // Task is due or overdue + current_interval_us_ = 1; + Scheduler_global_timer->ARR = 1; + Scheduler_global_timer->CNT = 1; + Scheduler::global_timer_enable(); } else { - delta = static_cast(diff); + current_interval_us_ = static_cast(diff); + configure_timer_for_interval(current_interval_us_); } - current_interval_us_ = delta; - - configure_timer_for_interval(current_interval_us_); } inline void Scheduler::configure_timer_for_interval(uint32_t microseconds) { diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index e111dc3e8..c635f9452 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -162,3 +162,26 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { EXPECT_EQ(operational_execs, 2); EXPECT_EQ(fault_execs, 2); } + +int multiple_task1count = 0; +void multiple_task_1(void) { + multiple_task1count++; +} +int multiple_task2count = 0; +void multiple_task_2(void) { + multiple_task2count++; +} +TEST_F(SchedulerTests, MultipleTasks) { + uint8_t taskid1 = Scheduler::register_task(2, &multiple_task_1); + uint8_t taskid2 = Scheduler::register_task(3, &multiple_task_2); + + Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 30; + for(int i = 0; i < NUM_TICKS; i++) { + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); + Scheduler::update(); + } + EXPECT_EQ(multiple_task1count, 15); + EXPECT_EQ(multiple_task2count, 10); +} From eecd764d8e967ec0d0a6f78154a055f902265ad5 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 16:44:59 +0100 Subject: [PATCH 204/281] All 15 tasks in MultipleTasks test, and it works --- Tests/Time/scheduler_test.cpp | 45 +++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index c635f9452..41b390c88 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -163,17 +163,35 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { EXPECT_EQ(fault_execs, 2); } -int multiple_task1count = 0; -void multiple_task_1(void) { - multiple_task1count++; -} -int multiple_task2count = 0; -void multiple_task_2(void) { - multiple_task2count++; -} +#define multiple_tasks \ + X(1) \ + X(2) \ + X(3) \ + X(4) \ + X(5) \ + X(6) \ + X(7) \ + X(8) \ + X(9) \ + X(10) \ + X(11) \ + X(12) \ + X(13) \ + X(14) \ + X(15) + +#define X(n) \ + int multiple_task##n##count = 0; \ + void multiple_task_##n(void) { \ + multiple_task##n##count++; \ + } +multiple_tasks +#undef X TEST_F(SchedulerTests, MultipleTasks) { - uint8_t taskid1 = Scheduler::register_task(2, &multiple_task_1); - uint8_t taskid2 = Scheduler::register_task(3, &multiple_task_2); +#define X(n) uint8_t taskid##n = Scheduler::register_task(n, &multiple_task_##n); \ + (void) taskid##n; + multiple_tasks +#undef X Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test @@ -182,6 +200,9 @@ TEST_F(SchedulerTests, MultipleTasks) { for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); } - EXPECT_EQ(multiple_task1count, 15); - EXPECT_EQ(multiple_task2count, 10); + +#define X(n) EXPECT_EQ(multiple_task##n##count, NUM_TICKS / n); + multiple_tasks +#undef X } + From 205c4c77999e68c1a46faa557c744adc4def6701 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 16:51:18 +0100 Subject: [PATCH 205/281] Add SameTaskMultipleTimes test, does all 16 tasks too --- Tests/Time/scheduler_test.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 41b390c88..cc9d26335 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -178,7 +178,8 @@ TEST_F(SchedulerTests, TaskDe_ReRegistration) { X(12) \ X(13) \ X(14) \ - X(15) + X(15) \ + X(16) #define X(n) \ int multiple_task##n##count = 0; \ @@ -189,7 +190,7 @@ multiple_tasks #undef X TEST_F(SchedulerTests, MultipleTasks) { #define X(n) uint8_t taskid##n = Scheduler::register_task(n, &multiple_task_##n); \ - (void) taskid##n; + (void)taskid##n; multiple_tasks #undef X @@ -206,3 +207,21 @@ TEST_F(SchedulerTests, MultipleTasks) { #undef X } + +TEST_F(SchedulerTests, SameTaskMultipleTimes) { +#define X(n) uint8_t taskid_##n = Scheduler::register_task(n, &multiple_task_1); \ + (void)taskid_##n; + multiple_tasks +#undef X + + Scheduler::start(); + TIM2_BASE->PSC = 2; // quicker test + constexpr int NUM_TICKS = 30; + for(int i = 0; i < NUM_TICKS; i++) { + for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); + Scheduler::update(); + } + +#define X(n) NUM_TICKS / n + + EXPECT_EQ(multiple_task1count, multiple_tasks 0); +} From a352c555c53d2330d3ab9d598c45cb9e516e2119 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 16:52:09 +0100 Subject: [PATCH 206/281] larger NUM_TICKS just in case --- Tests/Time/scheduler_test.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index cc9d26335..00e6f6db5 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -196,7 +196,7 @@ TEST_F(SchedulerTests, MultipleTasks) { Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test - constexpr int NUM_TICKS = 30; + constexpr int NUM_TICKS = 300; for(int i = 0; i < NUM_TICKS; i++) { for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); @@ -207,7 +207,6 @@ TEST_F(SchedulerTests, MultipleTasks) { #undef X } - TEST_F(SchedulerTests, SameTaskMultipleTimes) { #define X(n) uint8_t taskid_##n = Scheduler::register_task(n, &multiple_task_1); \ (void)taskid_##n; @@ -216,7 +215,7 @@ TEST_F(SchedulerTests, SameTaskMultipleTimes) { Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test - constexpr int NUM_TICKS = 30; + constexpr int NUM_TICKS = 300; for(int i = 0; i < NUM_TICKS; i++) { for(int j = 0; j <= TIM2_BASE->PSC; j++) TIM2_BASE->inc_cnt_and_check(1); Scheduler::update(); From 7d79c4b5746df2581034a4a54dde97031b96c994 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 15 Dec 2025 23:17:39 +0100 Subject: [PATCH 207/281] fix bug mentioned in previous cancel_timeout() --- Inc/HALAL/Services/Time/Scheduler.hpp | 30 ++++----------- Src/HALAL/Services/Time/Scheduler.cpp | 54 +++++++++++++++++++++++---- Tests/Time/scheduler_test.cpp | 2 +- 3 files changed, 56 insertions(+), 30 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 140382a49..4be680084 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -41,26 +41,11 @@ struct Scheduler { static void update(); static inline uint64_t get_global_tick(); - static inline uint8_t register_task(uint32_t period_us, callback_t func) { - if(period_us == 0) [[unlikely]] period_us = 1; - return register_task(period_us, func, true); - } - static bool unregister_task(uint8_t id); - - static inline uint8_t set_timeout(uint32_t microseconds, callback_t func) { - if(microseconds == 0) [[unlikely]] microseconds = 1; - return register_task(microseconds, func, false); - } - static inline bool cancel_timeout(uint8_t id) { - /* NOTE: This does not fix this case: - 1. id = set_timeout(x, func) - 2. timeout ends, func gets called and removed internally - 3. id_2 = set_timeout(y, func_2) // id will be equal to id_2 - 4. clear_timeout(id) -> will remove the second timeout - */ - if(tasks_[id].repeating) return false; - return unregister_task(id); - } + static uint32_t register_task(uint32_t period_us, callback_t func); + static bool unregister_task(uint32_t id); + + static uint32_t set_timeout(uint32_t microseconds, callback_t func); + static bool cancel_timeout(uint32_t id); // static void global_timer_callback(); @@ -72,9 +57,10 @@ struct Scheduler { private: #endif struct Task { - uint64_t next_fire_us{0}; + uint32_t next_fire_us{0}; callback_t callback{}; uint32_t period_us{0}; + uint32_t id; bool repeating{false}; }; @@ -93,6 +79,7 @@ struct Scheduler { static uint32_t free_bitmap_; static uint64_t global_tick_us_; static uint32_t current_interval_us_; + static uint32_t timeout_idx_; static inline uint8_t allocate_slot(); static inline void release_slot(uint8_t id); @@ -100,7 +87,6 @@ struct Scheduler { static void remove_sorted(uint8_t id); static void schedule_next_interval(); static inline void configure_timer_for_interval(uint32_t microseconds); - static uint8_t register_task(uint32_t period_us, callback_t func, bool repeating); // helpers static inline uint8_t get_at(uint8_t idx); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 9124e3476..0883a1289 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -36,6 +36,7 @@ uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; uint32_t Scheduler::current_interval_us_{0}; +uint32_t Scheduler::timeout_idx_{1}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; @@ -305,8 +306,9 @@ void Scheduler::on_timer_update() { schedule_next_interval(); } -uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repeating) { - if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); +uint32_t Scheduler::register_task(uint32_t period_us, callback_t func) { + if(func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + if(period_us == 0) [[unlikely]] period_us = 1; if(period_us >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); uint8_t slot = allocate_slot(); @@ -315,16 +317,54 @@ uint8_t Scheduler::register_task(uint32_t period_us, callback_t func, bool repea Task& task = tasks_[slot]; task.callback = func; task.period_us = period_us; - task.repeating = repeating; + task.repeating = true; task.next_fire_us = static_cast(global_tick_us_ + period_us); + task.id = static_cast(slot); insert_sorted(slot); schedule_next_interval(); - return slot; + return task.id; +} + +uint32_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { + if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + if(microseconds == 0) [[unlikely]] microseconds = 1; + if(microseconds >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); + + uint8_t slot = allocate_slot(); + if(slot == Scheduler::INVALID_ID) return slot; + + Task& task = tasks_[slot]; + task.callback = func; + task.period_us = microseconds; + task.repeating = false; + task.next_fire_us = static_cast(global_tick_us_ + microseconds); + task.id = slot + Scheduler::timeout_idx_ * Scheduler::kMaxTasks; + + // Add 2 instead of 1 so overflow doesn't make timeout_idx == 0, + // we need it to never be 0 + Scheduler::timeout_idx_ += 2; + + insert_sorted(slot); + schedule_next_interval(); + return task.id; +} + +bool Scheduler::unregister_task(uint32_t id) { + if(id >= kMaxTasks) return false; + if(free_bitmap_ & (1UL << id)) return false; + + remove_sorted(id); + release_slot(id); + schedule_next_interval(); + return true; } -bool Scheduler::unregister_task(uint8_t id) { - if (id >= kMaxTasks) return false; - if (free_bitmap_ & (1UL << id)) return false; +bool Scheduler::cancel_timeout(uint32_t id) { + static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); + uint32_t idx = id & Scheduler::kMaxTasks; + if(tasks_[idx].repeating) return false; + if(tasks_[idx].id != id) return false; + if(free_bitmap_ & (1UL << id)) return false; remove_sorted(id); release_slot(id); diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index 00e6f6db5..f32f13639 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -111,7 +111,7 @@ TEST_F(SchedulerTests, TimeoutClearAddTask) { } // timeout is already done here - uint8_t task_id = Scheduler::register_task(20, &fake_workload); + uint8_t timeout_id_2 = Scheduler::set_timeout(20, &fake_workload); // after timeout, cancel task Scheduler::cancel_timeout(timeout_id); From 708aca6bc7c07e86442f525be17625ac4a217cd9 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 16 Dec 2025 08:47:14 +0100 Subject: [PATCH 208/281] fix: id uint32_t -> uint16_t + bug fix --- Inc/HALAL/Services/Time/Scheduler.hpp | 12 ++++++------ Src/HALAL/Services/Time/Scheduler.cpp | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 4be680084..1d246b45c 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -41,11 +41,11 @@ struct Scheduler { static void update(); static inline uint64_t get_global_tick(); - static uint32_t register_task(uint32_t period_us, callback_t func); - static bool unregister_task(uint32_t id); + static uint16_t register_task(uint32_t period_us, callback_t func); + static bool unregister_task(uint16_t id); - static uint32_t set_timeout(uint32_t microseconds, callback_t func); - static bool cancel_timeout(uint32_t id); + static uint16_t set_timeout(uint32_t microseconds, callback_t func); + static bool cancel_timeout(uint16_t id); // static void global_timer_callback(); @@ -60,7 +60,7 @@ struct Scheduler { uint32_t next_fire_us{0}; callback_t callback{}; uint32_t period_us{0}; - uint32_t id; + uint16_t id; bool repeating{false}; }; @@ -79,7 +79,7 @@ struct Scheduler { static uint32_t free_bitmap_; static uint64_t global_tick_us_; static uint32_t current_interval_us_; - static uint32_t timeout_idx_; + static uint16_t timeout_idx_; static inline uint8_t allocate_slot(); static inline void release_slot(uint8_t id); diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index 0883a1289..f6d3cf9fb 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -36,7 +36,7 @@ uint32_t Scheduler::ready_bitmap_{0}; uint32_t Scheduler::free_bitmap_{0xFFFF'FFFF}; uint64_t Scheduler::global_tick_us_{0}; uint32_t Scheduler::current_interval_us_{0}; -uint32_t Scheduler::timeout_idx_{1}; +uint16_t Scheduler::timeout_idx_{1}; inline uint8_t Scheduler::get_at(uint8_t idx) { int word_idx = idx > 7; @@ -306,7 +306,7 @@ void Scheduler::on_timer_update() { schedule_next_interval(); } -uint32_t Scheduler::register_task(uint32_t period_us, callback_t func) { +uint16_t Scheduler::register_task(uint32_t period_us, callback_t func) { if(func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); if(period_us == 0) [[unlikely]] period_us = 1; if(period_us >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); @@ -325,7 +325,7 @@ uint32_t Scheduler::register_task(uint32_t period_us, callback_t func) { return task.id; } -uint32_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { +uint16_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { if (func == nullptr) [[unlikely]] return static_cast(Scheduler::INVALID_ID); if(microseconds == 0) [[unlikely]] microseconds = 1; if(microseconds >= kMaxIntervalUs) [[unlikely]] return static_cast(Scheduler::INVALID_ID); @@ -349,7 +349,7 @@ uint32_t Scheduler::set_timeout(uint32_t microseconds, callback_t func) { return task.id; } -bool Scheduler::unregister_task(uint32_t id) { +bool Scheduler::unregister_task(uint16_t id) { if(id >= kMaxTasks) return false; if(free_bitmap_ & (1UL << id)) return false; @@ -359,15 +359,15 @@ bool Scheduler::unregister_task(uint32_t id) { return true; } -bool Scheduler::cancel_timeout(uint32_t id) { +bool Scheduler::cancel_timeout(uint16_t id) { static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two"); - uint32_t idx = id & Scheduler::kMaxTasks; + uint32_t idx = id & (Scheduler::kMaxTasks - 1UL); if(tasks_[idx].repeating) return false; if(tasks_[idx].id != id) return false; - if(free_bitmap_ & (1UL << id)) return false; + if(free_bitmap_ & (1UL << idx)) return false; - remove_sorted(id); - release_slot(id); + remove_sorted(idx); + release_slot(idx); schedule_next_interval(); return true; } From 2dbc08957fb4cde77223e85ca1340d40a3d0bb4e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 16 Dec 2025 19:17:56 +0100 Subject: [PATCH 209/281] fix: remove TimerPeripheral::start and Time::start from HALAL::start --- Src/HALAL/HALAL.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/HALAL.cpp b/Src/HALAL/HALAL.cpp index 2ee470ed9..3a309fb2d 100644 --- a/Src/HALAL/HALAL.cpp +++ b/Src/HALAL/HALAL.cpp @@ -72,8 +72,8 @@ static void common_start(UART::Peripheral &printf_peripheral) { #ifdef HAL_TIM_MODULE_ENABLED Encoder::start(); Global_RTC::start_rtc(); - TimerPeripheral::start(); - Time::start(); + //TimerPeripheral::start(); + //Time::start(); #endif #ifdef HAL_EXTI_MODULE_ENABLED From cebea22e8ef27e545abea152e05b657d12b44560 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 12:59:08 +0100 Subject: [PATCH 210/281] try to fix ci/cd --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c9f88bc4..bb7ae0a22 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,14 @@ message(STATUS "${PROJECT_NAME} Ethernet: ${USE_ETHERNET}") message(STATUS "${PROJECT_NAME} Nucleo: ${TARGET_NUCLEO}") message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) + execute_process( + COMMAND git submodule update --init + ) + execute_process( + COMMAND git submodule update --init --depth 1 STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx + ) +endif() if(NOT CMAKE_CROSSCOMPILING) message(STATUS "Compiling for simulator") From 1426d458a45a62f160dfddce68fbe54127891d73 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 13:04:21 +0100 Subject: [PATCH 211/281] try to fix ci/cd part 2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb7ae0a22..2a6ce7206 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM3 COMMAND git submodule update --init ) execute_process( - COMMAND git submodule update --init --depth 1 STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx + COMMAND git submodule update --init --depth 1 ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx ) endif() From d7a91a62c41a577522b024aa059bbe038ef16684 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 13:09:38 +0100 Subject: [PATCH 212/281] try to fix ci/cd part 3 --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a6ce7206..9d0033860 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,10 +23,11 @@ message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) execute_process( - COMMAND git submodule update --init + COMMAND git submodule update --init --depth 1 ) execute_process( - COMMAND git submodule update --init --depth 1 ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx + COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 ) endif() From 521c5d96adc90a0187b3699a91b297e534397537 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 13:12:47 +0100 Subject: [PATCH 213/281] clean up ci/cd fix --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d0033860..e390832cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,10 +21,14 @@ message(STATUS "${PROJECT_NAME} Ethernet: ${USE_ETHERNET}") message(STATUS "${PROJECT_NAME} Nucleo: ${TARGET_NUCLEO}") message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}") -if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers) execute_process( COMMAND git submodule update --init --depth 1 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} ) +endif() + +if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) execute_process( COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 From 4ab5b5396ade0d4976f8bac76dba9a63db0cbf32 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 17 Dec 2025 17:10:32 +0100 Subject: [PATCH 214/281] Remove unnecessary warning ignore --- Inc/MockedDrivers/stm32h723xx_wrapper.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index 543ccc993..f363cee7f 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -9,18 +9,14 @@ #endif #define __IO volatile -// necessary remove of some warnings due to cmsis made for 32 bit arch and not 64 bit arch #define __RBIT __RBIT__CMSIS #define TIM_TypeDef TIM_TypeDef__CMSIS -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // don't do anything in "core_cm7.h" #define __CORE_CM7_H_GENERIC #define __CORE_CM7_H_DEPENDANT #include "stm32h723xx.h" -#pragma GCC diagnostic pop #undef __RBIT #undef TIM_TypeDef From 5ae2b87dc692d0a3c01b240e173e8f2ef6a2115b Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:29:22 +0100 Subject: [PATCH 215/281] fix: use wrapper instead of interface for stm32h7xx_ll_tim.h --- CMakeLists.txt | 3 +- Inc/HALAL/Services/Time/Scheduler.hpp | 2 +- Inc/MockedDrivers/common.hpp | 85 +- Inc/MockedDrivers/ll_tim_interface.h | 5217 ----------------------- Inc/MockedDrivers/mocked_ll_tim.hpp | 3 +- Inc/MockedDrivers/stm32h723xx_wrapper.h | 13 +- 6 files changed, 26 insertions(+), 5297 deletions(-) delete mode 100644 Inc/MockedDrivers/ll_tim_interface.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e390832cf..dfb2cfe6e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -292,7 +292,8 @@ target_include_directories(${STLIB_LIBRARY} PUBLIC ${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include ${STM32CUBEH7}/Drivers/CMSIS/Include $<$:${STM32CUBEH7}/Drivers/CMSIS/Core_A/Include> - $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc> + #$<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc> + ${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc $<$:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy> # LWIP includes diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 1d246b45c..256afe309 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -9,7 +9,7 @@ #ifndef TESTING_ENV #include "stm32h7xx_ll_tim.h" #else - #include "MockedDrivers/ll_tim_interface.h" + #include "MockedDrivers/stm32h7xx_ll_tim_wrapper.h" #endif #include #include diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 80f9d3c91..76326dc42 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -13,25 +13,20 @@ #define __OM volatile /*! Defines 'write only' structure member permissions */ #define __IOM volatile /*! Defines 'read / write' structure member permissions */ -typedef enum -{ - RESET = 0, - SET = !RESET -} FlagStatus, ITStatus; - -typedef enum -{ - DISABLE = 0, - ENABLE = !DISABLE -} FunctionalState; #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) -typedef enum -{ - SUCCESS = 0, - ERROR = !SUCCESS -} ErrorStatus; - +#ifdef SET_BIT +# undef SET_BIT +#endif +#ifdef CLEAR_BIT +# undef CLEAR_BIT +#endif +#ifdef WRITE_REG +# undef WRITE_REG +#endif +#ifdef MODIFY_REG +# undef MODIFY_REG +#endif #define SET_BIT(REG, BIT) ((REG) |= (BIT)) @@ -48,59 +43,3 @@ typedef enum #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) - - -/* Use of CMSIS compiler intrinsics for register exclusive access */ -/* Atomic 32-bit register access macro to set one or several bits */ -#define ATOMIC_SET_BIT(REG, BIT) \ - do { \ - uint32_t val; \ - do { \ - val = __LDREXW((__IO uint32_t *)&(REG)) | (BIT); \ - } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 32-bit register access macro to clear one or several bits */ -#define ATOMIC_CLEAR_BIT(REG, BIT) \ - do { \ - uint32_t val; \ - do { \ - val = __LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(BIT); \ - } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 32-bit register access macro to clear and set one or several bits */ -#define ATOMIC_MODIFY_REG(REG, CLEARMSK, SETMASK) \ - do { \ - uint32_t val; \ - do { \ - val = (__LDREXW((__IO uint32_t *)&(REG)) & ~(uint32_t)(CLEARMSK)) | (SETMASK); \ - } while ((__STREXW(val,(__IO uint32_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 16-bit register access macro to set one or several bits */ -#define ATOMIC_SETH_BIT(REG, BIT) \ - do { \ - uint16_t val; \ - do { \ - val = __LDREXH((__IO uint16_t *)&(REG)) | (BIT); \ - } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 16-bit register access macro to clear one or several bits */ -#define ATOMIC_CLEARH_BIT(REG, BIT) \ - do { \ - uint16_t val; \ - do { \ - val = __LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(BIT); \ - } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ - } while(0) - -/* Atomic 16-bit register access macro to clear and set one or several bits */ -#define ATOMIC_MODIFYH_REG(REG, CLEARMSK, SETMASK) \ - do { \ - uint16_t val; \ - do { \ - val = (__LDREXH((__IO uint16_t *)&(REG)) & ~(uint16_t)(CLEARMSK)) | (SETMASK); \ - } while ((__STREXH(val,(__IO uint16_t *)&(REG))) != 0U); \ - } while(0) diff --git a/Inc/MockedDrivers/ll_tim_interface.h b/Inc/MockedDrivers/ll_tim_interface.h deleted file mode 100644 index 60d63a387..000000000 --- a/Inc/MockedDrivers/ll_tim_interface.h +++ /dev/null @@ -1,5217 +0,0 @@ -/** - ****************************************************************************** - * @file stm32h7xx_ll_tim.h - * @author MCD Application Team - * @brief Header file of TIM LL 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_LL_TIM_H -#define __STM32H7xx_LL_TIM_H - -#include "stm32h723xx_wrapper.h" -#include "mocked_ll_tim.hpp" - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -//#define TIM1 - -/** @addtogroup STM32H7xx_LL_Driver - * @{ - */ - -#if defined (TIM1) || defined (TIM2) || defined (TIM3) || defined (TIM4) || defined (TIM5) || defined (TIM6) || defined (TIM7) || defined (TIM8) || defined (TIM12) || defined (TIM13) || defined (TIM14) || defined (TIM15) || defined (TIM16) || defined (TIM17) || defined (TIM23) || defined (TIM24) - -/** @defgroup TIM_LL TIM - * @{ - */ - -/* Private types -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/** @defgroup TIM_LL_Private_Variables TIM Private Variables - * @{ - */ -static const uint8_t OFFSET_TAB_CCMRx[] = -{ - 0x00U, /* 0: TIMx_CH1 */ - 0x00U, /* 1: TIMx_CH1N */ - 0x00U, /* 2: TIMx_CH2 */ - 0x00U, /* 3: TIMx_CH2N */ - 0x04U, /* 4: TIMx_CH3 */ - 0x04U, /* 5: TIMx_CH3N */ - 0x04U, /* 6: TIMx_CH4 */ - 0x3CU, /* 7: TIMx_CH5 */ - 0x3CU /* 8: TIMx_CH6 */ -}; - -static const uint8_t SHIFT_TAB_OCxx[] = -{ - 0U, /* 0: OC1M, OC1FE, OC1PE */ - 0U, /* 1: - NA */ - 8U, /* 2: OC2M, OC2FE, OC2PE */ - 0U, /* 3: - NA */ - 0U, /* 4: OC3M, OC3FE, OC3PE */ - 0U, /* 5: - NA */ - 8U, /* 6: OC4M, OC4FE, OC4PE */ - 0U, /* 7: OC5M, OC5FE, OC5PE */ - 8U /* 8: OC6M, OC6FE, OC6PE */ -}; - -static const uint8_t SHIFT_TAB_ICxx[] = -{ - 0U, /* 0: CC1S, IC1PSC, IC1F */ - 0U, /* 1: - NA */ - 8U, /* 2: CC2S, IC2PSC, IC2F */ - 0U, /* 3: - NA */ - 0U, /* 4: CC3S, IC3PSC, IC3F */ - 0U, /* 5: - NA */ - 8U, /* 6: CC4S, IC4PSC, IC4F */ - 0U, /* 7: - NA */ - 0U /* 8: - NA */ -}; - -static const uint8_t SHIFT_TAB_CCxP[] = -{ - 0U, /* 0: CC1P */ - 2U, /* 1: CC1NP */ - 4U, /* 2: CC2P */ - 6U, /* 3: CC2NP */ - 8U, /* 4: CC3P */ - 10U, /* 5: CC3NP */ - 12U, /* 6: CC4P */ - 16U, /* 7: CC5P */ - 20U /* 8: CC6P */ -}; - -static const uint8_t SHIFT_TAB_OISx[] = -{ - 0U, /* 0: OIS1 */ - 1U, /* 1: OIS1N */ - 2U, /* 2: OIS2 */ - 3U, /* 3: OIS2N */ - 4U, /* 4: OIS3 */ - 5U, /* 5: OIS3N */ - 6U, /* 6: OIS4 */ - 8U, /* 7: OIS5 */ - 10U /* 8: OIS6 */ -}; -/** - * @} - */ - -/* Private constants ---------------------------------------------------------*/ -/** @defgroup TIM_LL_Private_Constants TIM Private Constants - * @{ - */ - -#if defined(TIM_BREAK_INPUT_SUPPORT) -/* Defines used for the bit position in the register and perform offsets */ -#define TIM_POSITION_BRK_SOURCE (POSITION_VAL(Source) & 0x1FUL) - -/* Generic bit definitions for TIMx_AF1 register */ -#define TIMx_AF1_BKINP TIM1_AF1_BKINP /*!< BRK BKIN input polarity */ -#define TIMx_AF1_ETRSEL TIM1_AF1_ETRSEL /*!< TIMx ETR source selection */ -#endif /* TIM_BREAK_INPUT_SUPPORT */ - - -/* Mask used to set the TDG[x:0] of the DTG bits of the TIMx_BDTR register */ -#define DT_DELAY_1 ((uint8_t)0x7F) -#define DT_DELAY_2 ((uint8_t)0x3F) -#define DT_DELAY_3 ((uint8_t)0x1F) -#define DT_DELAY_4 ((uint8_t)0x1F) - -/* Mask used to set the DTG[7:5] bits of the DTG bits of the TIMx_BDTR register */ -#define DT_RANGE_1 ((uint8_t)0x00) -#define DT_RANGE_2 ((uint8_t)0x80) -#define DT_RANGE_3 ((uint8_t)0xC0) -#define DT_RANGE_4 ((uint8_t)0xE0) - - -/** - * @} - */ - -/* Private macros ------------------------------------------------------------*/ -/** @defgroup TIM_LL_Private_Macros TIM Private Macros - * @{ - */ -/** @brief Convert channel id into channel index. - * @param __CHANNEL__ This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval none - */ -#define TIM_GET_CHANNEL_INDEX( __CHANNEL__) \ - (((__CHANNEL__) == LL_TIM_CHANNEL_CH1) ? 0U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH1N) ? 1U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH2) ? 2U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH2N) ? 3U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH3) ? 4U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH3N) ? 5U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH4) ? 6U :\ - ((__CHANNEL__) == LL_TIM_CHANNEL_CH5) ? 7U : 8U) - -/** @brief Calculate the deadtime sampling period(in ps). - * @param __TIMCLK__ timer input clock frequency (in Hz). - * @param __CKD__ This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - * @retval none - */ -#define TIM_CALC_DTS(__TIMCLK__, __CKD__) \ - (((__CKD__) == LL_TIM_CLOCKDIVISION_DIV1) ? ((uint64_t)1000000000000U/(__TIMCLK__)) : \ - ((__CKD__) == LL_TIM_CLOCKDIVISION_DIV2) ? ((uint64_t)1000000000000U/((__TIMCLK__) >> 1U)) : \ - ((uint64_t)1000000000000U/((__TIMCLK__) >> 2U))) -/** - * @} - */ - - -/* Exported types ------------------------------------------------------------*/ -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_ES_INIT TIM Exported Init structure - * @{ - */ - -/** - * @brief TIM Time Base configuration structure definition. - */ -typedef struct -{ - uint16_t Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock. - This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetPrescaler().*/ - - uint32_t CounterMode; /*!< Specifies the counter mode. - This parameter can be a value of @ref TIM_LL_EC_COUNTERMODE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetCounterMode().*/ - - uint32_t Autoreload; /*!< Specifies the auto reload value to be loaded into the active - Auto-Reload Register at the next update event. - This parameter must be a number between Min_Data=0x0000 and Max_Data=0xFFFF. - Some timer instances may support 32 bits counters. In that case this parameter must - be a number between 0x0000 and 0xFFFFFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetAutoReload().*/ - - uint32_t ClockDivision; /*!< Specifies the clock division. - This parameter can be a value of @ref TIM_LL_EC_CLOCKDIVISION. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetClockDivision().*/ - - uint32_t RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter - reaches zero, an update event is generated and counting restarts - from the RCR value (N). - This means in PWM mode that (N+1) corresponds to: - - the number of PWM periods in edge-aligned mode - - the number of half PWM period in center-aligned mode - GP timers: this parameter must be a number between Min_Data = 0x00 and - Max_Data = 0xFF. - Advanced timers: this parameter must be a number between Min_Data = 0x0000 and - Max_Data = 0xFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetRepetitionCounter().*/ -} LL_TIM_InitTypeDef; - -/** - * @brief TIM Output Compare configuration structure definition. - */ -typedef struct -{ - uint32_t OCMode; /*!< Specifies the output mode. - This parameter can be a value of @ref TIM_LL_EC_OCMODE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetMode().*/ - - uint32_t OCState; /*!< Specifies the TIM Output Compare state. - This parameter can be a value of @ref TIM_LL_EC_OCSTATE. - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ - - uint32_t OCNState; /*!< Specifies the TIM complementary Output Compare state. - This parameter can be a value of @ref TIM_LL_EC_OCSTATE. - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_CC_EnableChannel() or @ref LL_TIM_CC_DisableChannel().*/ - - uint32_t CompareValue; /*!< Specifies the Compare value to be loaded into the Capture Compare Register. - This parameter can be a number between Min_Data=0x0000 and Max_Data=0xFFFF. - - This feature can be modified afterwards using unitary function - LL_TIM_OC_SetCompareCHx (x=1..6).*/ - - uint32_t OCPolarity; /*!< Specifies the output polarity. - This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetPolarity().*/ - - uint32_t OCNPolarity; /*!< Specifies the complementary output polarity. - This parameter can be a value of @ref TIM_LL_EC_OCPOLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetPolarity().*/ - - - uint32_t OCIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. - This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetIdleState().*/ - - uint32_t OCNIdleState; /*!< Specifies the TIM Output Compare pin state during Idle state. - This parameter can be a value of @ref TIM_LL_EC_OCIDLESTATE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetIdleState().*/ -} LL_TIM_OC_InitTypeDef; - -/** - * @brief TIM Input Capture configuration structure definition. - */ - -typedef struct -{ - - uint32_t ICPolarity; /*!< Specifies the active edge of the input signal. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t ICActiveInput; /*!< Specifies the input. - This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetActiveInput().*/ - - uint32_t ICPrescaler; /*!< Specifies the Input Capture Prescaler. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t ICFilter; /*!< Specifies the input capture filter. - This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ -} LL_TIM_IC_InitTypeDef; - - -/** - * @brief TIM Encoder interface configuration structure definition. - */ -typedef struct -{ - uint32_t EncoderMode; /*!< Specifies the encoder resolution (x2 or x4). - This parameter can be a value of @ref TIM_LL_EC_ENCODERMODE. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetEncoderMode().*/ - - uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t IC1ActiveInput; /*!< Specifies the TI1 input source - This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetActiveInput().*/ - - uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t IC1Filter; /*!< Specifies the TI1 input filter. - This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ - - uint32_t IC2Polarity; /*!< Specifies the active edge of TI2 input. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t IC2ActiveInput; /*!< Specifies the TI2 input source - This parameter can be a value of @ref TIM_LL_EC_ACTIVEINPUT. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetActiveInput().*/ - - uint32_t IC2Prescaler; /*!< Specifies the TI2 input prescaler value. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t IC2Filter; /*!< Specifies the TI2 input filter. - This parameter can be a value of @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ - -} LL_TIM_ENCODER_InitTypeDef; - -/** - * @brief TIM Hall sensor interface configuration structure definition. - */ -typedef struct -{ - - uint32_t IC1Polarity; /*!< Specifies the active edge of TI1 input. - This parameter can be a value of @ref TIM_LL_EC_IC_POLARITY. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPolarity().*/ - - uint32_t IC1Prescaler; /*!< Specifies the TI1 input prescaler value. - Prescaler must be set to get a maximum counter period longer than the - time interval between 2 consecutive changes on the Hall inputs. - This parameter can be a value of @ref TIM_LL_EC_ICPSC. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetPrescaler().*/ - - uint32_t IC1Filter; /*!< Specifies the TI1 input filter. - This parameter can be a value of - @ref TIM_LL_EC_IC_FILTER. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_IC_SetFilter().*/ - - uint32_t CommutationDelay; /*!< Specifies the compare value to be loaded into the Capture Compare Register. - A positive pulse (TRGO event) is generated with a programmable delay every time - a change occurs on the Hall inputs. - This parameter can be a number between Min_Data = 0x0000 and Max_Data = 0xFFFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetCompareCH2().*/ -} LL_TIM_HALLSENSOR_InitTypeDef; - -/** - * @brief BDTR (Break and Dead Time) structure definition - */ -typedef struct -{ - uint32_t OSSRState; /*!< Specifies the Off-State selection used in Run mode. - This parameter can be a value of @ref TIM_LL_EC_OSSR - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetOffStates() - - @note This bit-field cannot be modified as long as LOCK level 2 has been - programmed. */ - - uint32_t OSSIState; /*!< Specifies the Off-State used in Idle state. - This parameter can be a value of @ref TIM_LL_EC_OSSI - - This feature can be modified afterwards using unitary function - @ref LL_TIM_SetOffStates() - - @note This bit-field cannot be modified as long as LOCK level 2 has been - programmed. */ - - uint32_t LockLevel; /*!< Specifies the LOCK level parameters. - This parameter can be a value of @ref TIM_LL_EC_LOCKLEVEL - - @note The LOCK bits can be written only once after the reset. Once the TIMx_BDTR - register has been written, their content is frozen until the next reset.*/ - - uint8_t DeadTime; /*!< Specifies the delay time between the switching-off and the - switching-on of the outputs. - This parameter can be a number between Min_Data = 0x00 and Max_Data = 0xFF. - - This feature can be modified afterwards using unitary function - @ref LL_TIM_OC_SetDeadTime() - - @note This bit-field can not be modified as long as LOCK level 1, 2 or 3 has been - programmed. */ - - uint16_t BreakState; /*!< Specifies whether the TIM Break input is enabled or not. - This parameter can be a value of @ref TIM_LL_EC_BREAK_ENABLE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_EnableBRK() or @ref LL_TIM_DisableBRK() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t BreakPolarity; /*!< Specifies the TIM Break Input pin polarity. - This parameter can be a value of @ref TIM_LL_EC_BREAK_POLARITY - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t BreakFilter; /*!< Specifies the TIM Break Filter. - This parameter can be a value of @ref TIM_LL_EC_BREAK_FILTER - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#if defined(TIM_BDTR_BKBID) - uint32_t BreakAFMode; /*!< Specifies the alternate function mode of the break input. - This parameter can be a value of @ref TIM_LL_EC_BREAK_AFMODE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_ConfigBRK() - - @note Bidirectional break input is only supported by advanced timers instances. - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#endif /*TIM_BDTR_BKBID */ - uint32_t Break2State; /*!< Specifies whether the TIM Break2 input is enabled or not. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_ENABLE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_EnableBRK2() or @ref LL_TIM_DisableBRK2() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t Break2Polarity; /*!< Specifies the TIM Break2 Input pin polarity. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_POLARITY - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK2() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - - uint32_t Break2Filter; /*!< Specifies the TIM Break2 Filter. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_FILTER - - This feature can be modified afterwards using unitary function - @ref LL_TIM_ConfigBRK2() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#if defined(TIM_BDTR_BKBID) - uint32_t Break2AFMode; /*!< Specifies the alternate function mode of the break2 input. - This parameter can be a value of @ref TIM_LL_EC_BREAK2_AFMODE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_ConfigBRK2() - - @note Bidirectional break input is only supported by advanced timers instances. - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ - -#endif /*TIM_BDTR_BKBID */ - uint32_t AutomaticOutput; /*!< Specifies whether the TIM Automatic Output feature is enabled or not. - This parameter can be a value of @ref TIM_LL_EC_AUTOMATICOUTPUT_ENABLE - - This feature can be modified afterwards using unitary functions - @ref LL_TIM_EnableAutomaticOutput() or @ref LL_TIM_DisableAutomaticOutput() - - @note This bit-field can not be modified as long as LOCK level 1 has been - programmed. */ -} LL_TIM_BDTR_InitTypeDef; - -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/* Exported constants --------------------------------------------------------*/ -/** @defgroup TIM_LL_Exported_Constants TIM Exported Constants - * @{ - */ - -/** @defgroup TIM_LL_EC_GET_FLAG Get Flags Defines - * @brief Flags defines which can be used with LL_TIM_ReadReg function. - * @{ - */ -#define LL_TIM_SR_UIF TIM_SR_UIF /*!< Update interrupt flag */ -#define LL_TIM_SR_CC1IF TIM_SR_CC1IF /*!< Capture/compare 1 interrupt flag */ -#define LL_TIM_SR_CC2IF TIM_SR_CC2IF /*!< Capture/compare 2 interrupt flag */ -#define LL_TIM_SR_CC3IF TIM_SR_CC3IF /*!< Capture/compare 3 interrupt flag */ -#define LL_TIM_SR_CC4IF TIM_SR_CC4IF /*!< Capture/compare 4 interrupt flag */ -#define LL_TIM_SR_CC5IF TIM_SR_CC5IF /*!< Capture/compare 5 interrupt flag */ -#define LL_TIM_SR_CC6IF TIM_SR_CC6IF /*!< Capture/compare 6 interrupt flag */ -#define LL_TIM_SR_COMIF TIM_SR_COMIF /*!< COM interrupt flag */ -#define LL_TIM_SR_TIF TIM_SR_TIF /*!< Trigger interrupt flag */ -#define LL_TIM_SR_BIF TIM_SR_BIF /*!< Break interrupt flag */ -#define LL_TIM_SR_B2IF TIM_SR_B2IF /*!< Second break interrupt flag */ -#define LL_TIM_SR_CC1OF TIM_SR_CC1OF /*!< Capture/Compare 1 overcapture flag */ -#define LL_TIM_SR_CC2OF TIM_SR_CC2OF /*!< Capture/Compare 2 overcapture flag */ -#define LL_TIM_SR_CC3OF TIM_SR_CC3OF /*!< Capture/Compare 3 overcapture flag */ -#define LL_TIM_SR_CC4OF TIM_SR_CC4OF /*!< Capture/Compare 4 overcapture flag */ -#define LL_TIM_SR_SBIF TIM_SR_SBIF /*!< System Break interrupt flag */ -/** - * @} - */ - -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_EC_BREAK_ENABLE Break Enable - * @{ - */ -#define LL_TIM_BREAK_DISABLE 0x00000000U /*!< Break function disabled */ -#define LL_TIM_BREAK_ENABLE TIM_BDTR_BKE /*!< Break function enabled */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_BREAK2_ENABLE Break2 Enable - * @{ - */ -#define LL_TIM_BREAK2_DISABLE 0x00000000U /*!< Break2 function disabled */ -#define LL_TIM_BREAK2_ENABLE TIM_BDTR_BK2E /*!< Break2 function enabled */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_AUTOMATICOUTPUT_ENABLE Automatic output enable - * @{ - */ -#define LL_TIM_AUTOMATICOUTPUT_DISABLE 0x00000000U /*!< MOE can be set only by software */ -#define LL_TIM_AUTOMATICOUTPUT_ENABLE TIM_BDTR_AOE /*!< MOE can be set by software or automatically at the next update event */ -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/** @defgroup TIM_LL_EC_IT IT Defines - * @brief IT defines which can be used with LL_TIM_ReadReg and LL_TIM_WriteReg functions. - * @{ - */ -#define LL_TIM_DIER_UIE TIM_DIER_UIE /*!< Update interrupt enable */ -#define LL_TIM_DIER_CC1IE TIM_DIER_CC1IE /*!< Capture/compare 1 interrupt enable */ -#define LL_TIM_DIER_CC2IE TIM_DIER_CC2IE /*!< Capture/compare 2 interrupt enable */ -#define LL_TIM_DIER_CC3IE TIM_DIER_CC3IE /*!< Capture/compare 3 interrupt enable */ -#define LL_TIM_DIER_CC4IE TIM_DIER_CC4IE /*!< Capture/compare 4 interrupt enable */ -#define LL_TIM_DIER_COMIE TIM_DIER_COMIE /*!< COM interrupt enable */ -#define LL_TIM_DIER_TIE TIM_DIER_TIE /*!< Trigger interrupt enable */ -#define LL_TIM_DIER_BIE TIM_DIER_BIE /*!< Break interrupt enable */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_UPDATESOURCE Update Source - * @{ - */ -#define LL_TIM_UPDATESOURCE_REGULAR 0x00000000U /*!< Counter overflow/underflow, Setting the UG bit or Update generation through the slave mode controller generates an update request */ -#define LL_TIM_UPDATESOURCE_COUNTER TIM_CR1_URS /*!< Only counter overflow/underflow generates an update request */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_ONEPULSEMODE One Pulse Mode - * @{ - */ -#define LL_TIM_ONEPULSEMODE_SINGLE TIM_CR1_OPM /*!< Counter stops counting at the next update event */ -#define LL_TIM_ONEPULSEMODE_REPETITIVE 0x00000000U /*!< Counter is not stopped at update event */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_COUNTERMODE Counter Mode - * @{ - */ -#define LL_TIM_COUNTERMODE_UP 0x00000000U /*!< Counter used as upcounter */ -#define LL_TIM_COUNTERMODE_DOWN TIM_CR1_DIR /*!< Counter used as downcounter */ -#define LL_TIM_COUNTERMODE_CENTER_DOWN TIM_CR1_CMS_0 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting down. */ -#define LL_TIM_COUNTERMODE_CENTER_UP TIM_CR1_CMS_1 /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up */ -#define LL_TIM_COUNTERMODE_CENTER_UP_DOWN TIM_CR1_CMS /*!< The counter counts up and down alternatively. Output compare interrupt flags of output channels are set only when the counter is counting up or down. */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CLOCKDIVISION Clock Division - * @{ - */ -#define LL_TIM_CLOCKDIVISION_DIV1 0x00000000U /*!< tDTS=tCK_INT */ -#define LL_TIM_CLOCKDIVISION_DIV2 TIM_CR1_CKD_0 /*!< tDTS=2*tCK_INT */ -#define LL_TIM_CLOCKDIVISION_DIV4 TIM_CR1_CKD_1 /*!< tDTS=4*tCK_INT */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_COUNTERDIRECTION Counter Direction - * @{ - */ -#define LL_TIM_COUNTERDIRECTION_UP 0x00000000U /*!< Timer counter counts up */ -#define LL_TIM_COUNTERDIRECTION_DOWN TIM_CR1_DIR /*!< Timer counter counts down */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CCUPDATESOURCE Capture Compare Update Source - * @{ - */ -#define LL_TIM_CCUPDATESOURCE_COMG_ONLY 0x00000000U /*!< Capture/compare control bits are updated by setting the COMG bit only */ -#define LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI TIM_CR2_CCUS /*!< Capture/compare control bits are updated by setting the COMG bit or when a rising edge occurs on trigger input (TRGI) */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CCDMAREQUEST Capture Compare DMA Request - * @{ - */ -#define LL_TIM_CCDMAREQUEST_CC 0x00000000U /*!< CCx DMA request sent when CCx event occurs */ -#define LL_TIM_CCDMAREQUEST_UPDATE TIM_CR2_CCDS /*!< CCx DMA requests sent when update event occurs */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_LOCKLEVEL Lock Level - * @{ - */ -#define LL_TIM_LOCKLEVEL_OFF 0x00000000U /*!< LOCK OFF - No bit is write protected */ -#define LL_TIM_LOCKLEVEL_1 TIM_BDTR_LOCK_0 /*!< LOCK Level 1 */ -#define LL_TIM_LOCKLEVEL_2 TIM_BDTR_LOCK_1 /*!< LOCK Level 2 */ -#define LL_TIM_LOCKLEVEL_3 TIM_BDTR_LOCK /*!< LOCK Level 3 */ -/** - * @} - */ - -/** @defgroup TIM_LL_EC_CHANNEL Channel - * @{ - */ -#define LL_TIM_CHANNEL_CH1 TIM_CCER_CC1E /*!< Timer input/output channel 1 */ -#define LL_TIM_CHANNEL_CH1N TIM_CCER_CC1NE /*!< Timer complementary output channel 1 */ -#define LL_TIM_CHANNEL_CH2 TIM_CCER_CC2E /*!< Timer input/output channel 2 */ -#define LL_TIM_CHANNEL_CH2N TIM_CCER_CC2NE /*!< Timer complementary output channel 2 */ -#define LL_TIM_CHANNEL_CH3 TIM_CCER_CC3E /*!< Timer input/output channel 3 */ -#define LL_TIM_CHANNEL_CH3N TIM_CCER_CC3NE /*!< Timer complementary output channel 3 */ -#define LL_TIM_CHANNEL_CH4 TIM_CCER_CC4E /*!< Timer input/output channel 4 */ -#define LL_TIM_CHANNEL_CH5 TIM_CCER_CC5E /*!< Timer output channel 5 */ -#define LL_TIM_CHANNEL_CH6 TIM_CCER_CC6E /*!< Timer output channel 6 */ -/** - * @} - */ - -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_EC_OCSTATE Output Configuration State - * @{ - */ -#define LL_TIM_OCSTATE_DISABLE 0x00000000U /*!< OCx is not active */ -#define LL_TIM_OCSTATE_ENABLE TIM_CCER_CC1E /*!< OCx signal is output on the corresponding output pin */ -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/** Legacy definitions for compatibility purpose -@cond 0 - */ -#define LL_TIM_OCMODE_ASSYMETRIC_PWM1 LL_TIM_OCMODE_ASYMMETRIC_PWM1 -#define LL_TIM_OCMODE_ASSYMETRIC_PWM2 LL_TIM_OCMODE_ASYMMETRIC_PWM2 -/** -@endcond - */ - -/** @defgroup TIM_LL_EC_OCMODE Output Configuration Mode - * @{ - */ -#define LL_TIM_OCMODE_FROZEN 0x00000000U /*!TIMx_CCRy else active.*/ -#define LL_TIM_OCMODE_PWM2 (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0) /*!TIMx_CCRy else inactive*/ -#define LL_TIM_OCMODE_RETRIG_OPM1 TIM_CCMR1_OC1M_3 /*!__REG__, (__VALUE__)) - -/** - * @brief Read a value in TIM register. - * @param __INSTANCE__ TIM Instance - * @param __REG__ Register to be read - * @retval Register value - */ -#define LL_TIM_ReadReg(__INSTANCE__, __REG__) READ_REG((__INSTANCE__)->__REG__) -/** - * @} - */ - -/** - * @brief HELPER macro retrieving the UIFCPY flag from the counter value. - * @note ex: @ref __LL_TIM_GETFLAG_UIFCPY (@ref LL_TIM_GetCounter ()); - * @note Relevant only if UIF flag remapping has been enabled (UIF status bit is copied - * to TIMx_CNT register bit 31) - * @param __CNT__ Counter value - * @retval UIF status bit - */ -#define __LL_TIM_GETFLAG_UIFCPY(__CNT__) \ - (READ_BIT((__CNT__), TIM_CNT_UIFCPY) >> TIM_CNT_UIFCPY_Pos) - -/** - * @brief HELPER macro calculating DTG[0:7] in the TIMx_BDTR register to achieve the requested dead time duration. - * @note ex: @ref __LL_TIM_CALC_DEADTIME (80000000, @ref LL_TIM_GetClockDivision (), 120); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __CKD__ This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - * @param __DT__ deadtime duration (in ns) - * @retval DTG[0:7] - */ -#define __LL_TIM_CALC_DEADTIME(__TIMCLK__, __CKD__, __DT__) \ - ( (((uint64_t)((__DT__)*1000U)) < ((DT_DELAY_1+1U) * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(((uint64_t)((__DT__)*1000U) / TIM_CALC_DTS((__TIMCLK__), (__CKD__))) & DT_DELAY_1) : \ - (((uint64_t)((__DT__)*1000U)) < ((64U + (DT_DELAY_2+1U)) * 2U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(DT_RANGE_2 | ((uint8_t)((uint8_t)((((uint64_t)((__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ - (__CKD__))) >> 1U) - (uint8_t) 64) & DT_DELAY_2)) :\ - (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_3+1U)) * 8U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(DT_RANGE_3 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ - (__CKD__))) >> 3U) - (uint8_t) 32) & DT_DELAY_3)) :\ - (((uint64_t)((__DT__)*1000U)) < ((32U + (DT_DELAY_4+1U)) * 16U * TIM_CALC_DTS((__TIMCLK__), (__CKD__)))) ? \ - (uint8_t)(DT_RANGE_4 | ((uint8_t)((uint8_t)(((((uint64_t)(__DT__)*1000U))/ TIM_CALC_DTS((__TIMCLK__), \ - (__CKD__))) >> 4U) - (uint8_t) 32) & DT_DELAY_4)) :\ - 0U) - -/** - * @brief HELPER macro calculating the prescaler value to achieve the required counter clock frequency. - * @note ex: @ref __LL_TIM_CALC_PSC (80000000, 1000000); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __CNTCLK__ counter clock frequency (in Hz) - * @retval Prescaler value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_PSC(__TIMCLK__, __CNTCLK__) \ - (((__TIMCLK__) >= (__CNTCLK__)) ? (uint32_t)((((__TIMCLK__) + (__CNTCLK__)/2U)/(__CNTCLK__)) - 1U) : 0U) - -/** - * @brief HELPER macro calculating the auto-reload value to achieve the required output signal frequency. - * @note ex: @ref __LL_TIM_CALC_ARR (1000000, @ref LL_TIM_GetPrescaler (), 10000); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __PSC__ prescaler - * @param __FREQ__ output signal frequency (in Hz) - * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_ARR(__TIMCLK__, __PSC__, __FREQ__) \ - ((((__TIMCLK__)/((__PSC__) + 1U)) >= (__FREQ__)) ? (((__TIMCLK__)/((__FREQ__) * ((__PSC__) + 1U))) - 1U) : 0U) - -/** - * @brief HELPER macro calculating the compare value required to achieve the required timer output compare - * active/inactive delay. - * @note ex: @ref __LL_TIM_CALC_DELAY (1000000, @ref LL_TIM_GetPrescaler (), 10); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __PSC__ prescaler - * @param __DELAY__ timer output compare active/inactive delay (in us) - * @retval Compare value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_DELAY(__TIMCLK__, __PSC__, __DELAY__) \ - ((uint32_t)(((uint64_t)(__TIMCLK__) * (uint64_t)(__DELAY__)) \ - / ((uint64_t)1000000U * (uint64_t)((__PSC__) + 1U)))) - -/** - * @brief HELPER macro calculating the auto-reload value to achieve the required pulse duration - * (when the timer operates in one pulse mode). - * @note ex: @ref __LL_TIM_CALC_PULSE (1000000, @ref LL_TIM_GetPrescaler (), 10, 20); - * @param __TIMCLK__ timer input clock frequency (in Hz) - * @param __PSC__ prescaler - * @param __DELAY__ timer output compare active/inactive delay (in us) - * @param __PULSE__ pulse duration (in us) - * @retval Auto-reload value (between Min_Data=0 and Max_Data=65535) - */ -#define __LL_TIM_CALC_PULSE(__TIMCLK__, __PSC__, __DELAY__, __PULSE__) \ - ((uint32_t)(__LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__PULSE__)) \ - + __LL_TIM_CALC_DELAY((__TIMCLK__), (__PSC__), (__DELAY__)))) - -/** - * @brief HELPER macro retrieving the ratio of the input capture prescaler - * @note ex: @ref __LL_TIM_GET_ICPSC_RATIO (@ref LL_TIM_IC_GetPrescaler ()); - * @param __ICPSC__ This parameter can be one of the following values: - * @arg @ref LL_TIM_ICPSC_DIV1 - * @arg @ref LL_TIM_ICPSC_DIV2 - * @arg @ref LL_TIM_ICPSC_DIV4 - * @arg @ref LL_TIM_ICPSC_DIV8 - * @retval Input capture prescaler ratio (1, 2, 4 or 8) - */ -#define __LL_TIM_GET_ICPSC_RATIO(__ICPSC__) \ - ((uint32_t)(0x01U << (((__ICPSC__) >> 16U) >> TIM_CCMR1_IC1PSC_Pos))) - - -/** - * @} - */ - -/* Exported functions --------------------------------------------------------*/ -/** @defgroup TIM_LL_Exported_Functions TIM Exported Functions - * @{ - */ - -/** @defgroup TIM_LL_EF_Time_Base Time Base configuration - * @{ - */ -/** - * @brief Enable timer counter. - * @rmtoll CR1 CEN LL_TIM_EnableCounter - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableCounter(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_CEN); -} - -/** - * @brief Disable timer counter. - * @rmtoll CR1 CEN LL_TIM_DisableCounter - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableCounter(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_CEN); -} - -/** - * @brief Indicates whether the timer counter is enabled. - * @rmtoll CR1 CEN LL_TIM_IsEnabledCounter - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledCounter(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR1, TIM_CR1_CEN) == (TIM_CR1_CEN)) ? 1UL : 0UL); -} - -/** - * @brief Enable update event generation. - * @rmtoll CR1 UDIS LL_TIM_EnableUpdateEvent - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableUpdateEvent(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_UDIS); -} - -/** - * @brief Disable update event generation. - * @rmtoll CR1 UDIS LL_TIM_DisableUpdateEvent - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableUpdateEvent(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_UDIS); -} - -/** - * @brief Indicates whether update event generation is enabled. - * @rmtoll CR1 UDIS LL_TIM_IsEnabledUpdateEvent - * @param TIMx Timer instance - * @retval Inverted state of bit (0 or 1). - */ -static inline uint32_t LL_TIM_IsEnabledUpdateEvent(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR1, TIM_CR1_UDIS) == (uint32_t)RESET) ? 1UL : 0UL); -} - -/** - * @brief Set update event source - * @note Update event source set to LL_TIM_UPDATESOURCE_REGULAR: any of the following events - * generate an update interrupt or DMA request if enabled: - * - Counter overflow/underflow - * - Setting the UG bit - * - Update generation through the slave mode controller - * @note Update event source set to LL_TIM_UPDATESOURCE_COUNTER: only counter - * overflow/underflow generates an update interrupt or DMA request if enabled. - * @rmtoll CR1 URS LL_TIM_SetUpdateSource - * @param TIMx Timer instance - * @param UpdateSource This parameter can be one of the following values: - * @arg @ref LL_TIM_UPDATESOURCE_REGULAR - * @arg @ref LL_TIM_UPDATESOURCE_COUNTER - * @retval None - */ -static inline void LL_TIM_SetUpdateSource(TIM_TypeDef *TIMx, uint32_t UpdateSource) -{ - MODIFY_REG(TIMx->CR1, TIM_CR1_URS, UpdateSource); -} - -/** - * @brief Get actual event update source - * @rmtoll CR1 URS LL_TIM_GetUpdateSource - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_UPDATESOURCE_REGULAR - * @arg @ref LL_TIM_UPDATESOURCE_COUNTER - */ -static inline uint32_t LL_TIM_GetUpdateSource(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_URS)); -} - -/** - * @brief Set one pulse mode (one shot v.s. repetitive). - * @rmtoll CR1 OPM LL_TIM_SetOnePulseMode - * @param TIMx Timer instance - * @param OnePulseMode This parameter can be one of the following values: - * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE - * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE - * @retval None - */ -static inline void LL_TIM_SetOnePulseMode(TIM_TypeDef *TIMx, uint32_t OnePulseMode) -{ - MODIFY_REG(TIMx->CR1, TIM_CR1_OPM, OnePulseMode); -} - -/** - * @brief Get actual one pulse mode. - * @rmtoll CR1 OPM LL_TIM_GetOnePulseMode - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_ONEPULSEMODE_SINGLE - * @arg @ref LL_TIM_ONEPULSEMODE_REPETITIVE - */ -static inline uint32_t LL_TIM_GetOnePulseMode(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_OPM)); -} - -/** - * @brief Set the timer counter counting mode. - * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to - * check whether or not the counter mode selection feature is supported - * by a timer instance. - * @note Switching from Center Aligned counter mode to Edge counter mode (or reverse) - * requires a timer reset to avoid unexpected direction - * due to DIR bit readonly in center aligned mode. - * @rmtoll CR1 DIR LL_TIM_SetCounterMode\n - * CR1 CMS LL_TIM_SetCounterMode - * @param TIMx Timer instance - * @param CounterMode This parameter can be one of the following values: - * @arg @ref LL_TIM_COUNTERMODE_UP - * @arg @ref LL_TIM_COUNTERMODE_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP - * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN - * @retval None - */ -static inline void LL_TIM_SetCounterMode(TIM_TypeDef *TIMx, uint32_t CounterMode) -{ - MODIFY_REG(TIMx->CR1, (TIM_CR1_DIR | TIM_CR1_CMS), CounterMode); -} - -/** - * @brief Get actual counter mode. - * @note Macro IS_TIM_COUNTER_MODE_SELECT_INSTANCE(TIMx) can be used to - * check whether or not the counter mode selection feature is supported - * by a timer instance. - * @rmtoll CR1 DIR LL_TIM_GetCounterMode\n - * CR1 CMS LL_TIM_GetCounterMode - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_COUNTERMODE_UP - * @arg @ref LL_TIM_COUNTERMODE_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP - * @arg @ref LL_TIM_COUNTERMODE_CENTER_DOWN - * @arg @ref LL_TIM_COUNTERMODE_CENTER_UP_DOWN - */ -static inline uint32_t LL_TIM_GetCounterMode(const TIM_TypeDef *TIMx) -{ - uint32_t counter_mode; - - counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CMS)); - - if (counter_mode == 0U) - { - counter_mode = (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); - } - - return counter_mode; -} - -/** - * @brief Enable auto-reload (ARR) preload. - * @rmtoll CR1 ARPE LL_TIM_EnableARRPreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableARRPreload(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_ARPE); -} - -/** - * @brief Disable auto-reload (ARR) preload. - * @rmtoll CR1 ARPE LL_TIM_DisableARRPreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableARRPreload(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_ARPE); -} - -/** - * @brief Indicates whether auto-reload (ARR) preload is enabled. - * @rmtoll CR1 ARPE LL_TIM_IsEnabledARRPreload - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledARRPreload(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR1, TIM_CR1_ARPE) == (TIM_CR1_ARPE)) ? 1UL : 0UL); -} - -/** - * @brief Set the division ratio between the timer clock and the sampling clock used by the dead-time generators - * (when supported) and the digital filters. - * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check - * whether or not the clock division feature is supported by the timer - * instance. - * @rmtoll CR1 CKD LL_TIM_SetClockDivision - * @param TIMx Timer instance - * @param ClockDivision This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - * @retval None - */ -static inline void LL_TIM_SetClockDivision(TIM_TypeDef *TIMx, uint32_t ClockDivision) -{ - MODIFY_REG(TIMx->CR1, TIM_CR1_CKD, ClockDivision); -} - -/** - * @brief Get the actual division ratio between the timer clock and the sampling clock used by the dead-time - * generators (when supported) and the digital filters. - * @note Macro IS_TIM_CLOCK_DIVISION_INSTANCE(TIMx) can be used to check - * whether or not the clock division feature is supported by the timer - * instance. - * @rmtoll CR1 CKD LL_TIM_GetClockDivision - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_CLOCKDIVISION_DIV1 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV2 - * @arg @ref LL_TIM_CLOCKDIVISION_DIV4 - */ -static inline uint32_t LL_TIM_GetClockDivision(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_CKD)); -} - -/** - * @brief Set the counter value. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @rmtoll CNT CNT LL_TIM_SetCounter - * @param TIMx Timer instance - * @param Counter Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) - * @retval None - */ -static inline void LL_TIM_SetCounter(TIM_TypeDef *TIMx, uint32_t Counter) -{ - WRITE_REG(TIMx->CNT, Counter); -} - -/** - * @brief Get the counter value. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @rmtoll CNT CNT LL_TIM_GetCounter - * @param TIMx Timer instance - * @retval Counter value (between Min_Data=0 and Max_Data=0xFFFF or 0xFFFFFFFF) - */ -static inline uint32_t LL_TIM_GetCounter(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CNT)); -} - -/** - * @brief Get the current direction of the counter - * @rmtoll CR1 DIR LL_TIM_GetDirection - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_COUNTERDIRECTION_UP - * @arg @ref LL_TIM_COUNTERDIRECTION_DOWN - */ -static inline uint32_t LL_TIM_GetDirection(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR1, TIM_CR1_DIR)); -} - -/** - * @brief Set the prescaler value. - * @note The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1). - * @note The prescaler can be changed on the fly as this control register is buffered. The new - * prescaler ratio is taken into account at the next update event. - * @note Helper macro @ref __LL_TIM_CALC_PSC can be used to calculate the Prescaler parameter - * @rmtoll PSC PSC LL_TIM_SetPrescaler - * @param TIMx Timer instance - * @param Prescaler between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Prescaler) -{ - WRITE_REG(TIMx->PSC, Prescaler); -} - -/** - * @brief Get the prescaler value. - * @rmtoll PSC PSC LL_TIM_GetPrescaler - * @param TIMx Timer instance - * @retval Prescaler value between Min_Data=0 and Max_Data=65535 - */ -static inline uint32_t LL_TIM_GetPrescaler(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->PSC)); -} - -/** - * @brief Set the auto-reload value. - * @note The counter is blocked while the auto-reload value is null. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Helper macro @ref __LL_TIM_CALC_ARR can be used to calculate the AutoReload parameter - * @rmtoll ARR ARR LL_TIM_SetAutoReload - * @param TIMx Timer instance - * @param AutoReload between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_SetAutoReload(TIM_TypeDef *TIMx, uint32_t AutoReload) -{ - WRITE_REG(TIMx->ARR, AutoReload); -} - -/** - * @brief Get the auto-reload value. - * @rmtoll ARR ARR LL_TIM_GetAutoReload - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @param TIMx Timer instance - * @retval Auto-reload value - */ -static inline uint32_t LL_TIM_GetAutoReload(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->ARR)); -} - -/** - * @brief Set the repetition counter value. - * @note For advanced timer instances RepetitionCounter can be up to 65535. - * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a repetition counter. - * @rmtoll RCR REP LL_TIM_SetRepetitionCounter - * @param TIMx Timer instance - * @param RepetitionCounter between Min_Data=0 and Max_Data=255 or 65535 for advanced timer. - * @retval None - */ -static inline void LL_TIM_SetRepetitionCounter(TIM_TypeDef *TIMx, uint32_t RepetitionCounter) -{ - WRITE_REG(TIMx->RCR, RepetitionCounter); -} - -/** - * @brief Get the repetition counter value. - * @note Macro IS_TIM_REPETITION_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a repetition counter. - * @rmtoll RCR REP LL_TIM_GetRepetitionCounter - * @param TIMx Timer instance - * @retval Repetition counter value - */ -static inline uint32_t LL_TIM_GetRepetitionCounter(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->RCR)); -} - -/** - * @brief Force a continuous copy of the update interrupt flag (UIF) into the timer counter register (bit 31). - * @note This allows both the counter value and a potential roll-over condition signalled by the UIFCPY flag to be read - * in an atomic way. - * @rmtoll CR1 UIFREMAP LL_TIM_EnableUIFRemap - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableUIFRemap(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); -} - -/** - * @brief Disable update interrupt flag (UIF) remapping. - * @rmtoll CR1 UIFREMAP LL_TIM_DisableUIFRemap - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableUIFRemap(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR1, TIM_CR1_UIFREMAP); -} - -/** - * @brief Indicate whether update interrupt flag (UIF) copy is set. - * @param Counter Counter value - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveUIFCPY(const uint32_t Counter) -{ - return (((Counter & TIM_CNT_UIFCPY) == (TIM_CNT_UIFCPY)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Capture_Compare Capture Compare configuration - * @{ - */ -/** - * @brief Enable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. - * @note CCxE, CCxNE and OCxM bits are preloaded, after having been written, - * they are updated only when a commutation event (COM) occurs. - * @note Only on channels that have a complementary output. - * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check - * whether or not a timer instance is able to generate a commutation event. - * @rmtoll CR2 CCPC LL_TIM_CC_EnablePreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_CC_EnablePreload(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR2, TIM_CR2_CCPC); -} - -/** - * @brief Disable the capture/compare control bits (CCxE, CCxNE and OCxM) preload. - * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check - * whether or not a timer instance is able to generate a commutation event. - * @rmtoll CR2 CCPC LL_TIM_CC_DisablePreload - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_CC_DisablePreload(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR2, TIM_CR2_CCPC); -} - -/** - * @brief Indicates whether the capture/compare control bits (CCxE, CCxNE and OCxM) preload is enabled. - * @rmtoll CR2 CCPC LL_TIM_CC_IsEnabledPreload - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_CC_IsEnabledPreload(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR2, TIM_CR2_CCPC) == (TIM_CR2_CCPC)) ? 1UL : 0UL); -} - -/** - * @brief Set the updated source of the capture/compare control bits (CCxE, CCxNE and OCxM). - * @note Macro IS_TIM_COMMUTATION_EVENT_INSTANCE(TIMx) can be used to check - * whether or not a timer instance is able to generate a commutation event. - * @rmtoll CR2 CCUS LL_TIM_CC_SetUpdate - * @param TIMx Timer instance - * @param CCUpdateSource This parameter can be one of the following values: - * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_ONLY - * @arg @ref LL_TIM_CCUPDATESOURCE_COMG_AND_TRGI - * @retval None - */ -static inline void LL_TIM_CC_SetUpdate(TIM_TypeDef *TIMx, uint32_t CCUpdateSource) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_CCUS, CCUpdateSource); -} - -/** - * @brief Set the trigger of the capture/compare DMA request. - * @rmtoll CR2 CCDS LL_TIM_CC_SetDMAReqTrigger - * @param TIMx Timer instance - * @param DMAReqTrigger This parameter can be one of the following values: - * @arg @ref LL_TIM_CCDMAREQUEST_CC - * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE - * @retval None - */ -static inline void LL_TIM_CC_SetDMAReqTrigger(TIM_TypeDef *TIMx, uint32_t DMAReqTrigger) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_CCDS, DMAReqTrigger); -} - -/** - * @brief Get actual trigger of the capture/compare DMA request. - * @rmtoll CR2 CCDS LL_TIM_CC_GetDMAReqTrigger - * @param TIMx Timer instance - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_CCDMAREQUEST_CC - * @arg @ref LL_TIM_CCDMAREQUEST_UPDATE - */ -static inline uint32_t LL_TIM_CC_GetDMAReqTrigger(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CR2, TIM_CR2_CCDS)); -} - -/** - * @brief Set the lock level to freeze the - * configuration of several capture/compare parameters. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * the lock mechanism is supported by a timer instance. - * @rmtoll BDTR LOCK LL_TIM_CC_SetLockLevel - * @param TIMx Timer instance - * @param LockLevel This parameter can be one of the following values: - * @arg @ref LL_TIM_LOCKLEVEL_OFF - * @arg @ref LL_TIM_LOCKLEVEL_1 - * @arg @ref LL_TIM_LOCKLEVEL_2 - * @arg @ref LL_TIM_LOCKLEVEL_3 - * @retval None - */ -static inline void LL_TIM_CC_SetLockLevel(TIM_TypeDef *TIMx, uint32_t LockLevel) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_LOCK, LockLevel); -} - -/** - * @brief Enable capture/compare channels. - * @rmtoll CCER CC1E LL_TIM_CC_EnableChannel\n - * CCER CC1NE LL_TIM_CC_EnableChannel\n - * CCER CC2E LL_TIM_CC_EnableChannel\n - * CCER CC2NE LL_TIM_CC_EnableChannel\n - * CCER CC3E LL_TIM_CC_EnableChannel\n - * CCER CC3NE LL_TIM_CC_EnableChannel\n - * CCER CC4E LL_TIM_CC_EnableChannel\n - * CCER CC5E LL_TIM_CC_EnableChannel\n - * CCER CC6E LL_TIM_CC_EnableChannel - * @param TIMx Timer instance - * @param Channels This parameter can be a combination of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_CC_EnableChannel(TIM_TypeDef *TIMx, uint32_t Channels) -{ - SET_BIT(TIMx->CCER, Channels); -} - -/** - * @brief Disable capture/compare channels. - * @rmtoll CCER CC1E LL_TIM_CC_DisableChannel\n - * CCER CC1NE LL_TIM_CC_DisableChannel\n - * CCER CC2E LL_TIM_CC_DisableChannel\n - * CCER CC2NE LL_TIM_CC_DisableChannel\n - * CCER CC3E LL_TIM_CC_DisableChannel\n - * CCER CC3NE LL_TIM_CC_DisableChannel\n - * CCER CC4E LL_TIM_CC_DisableChannel\n - * CCER CC5E LL_TIM_CC_DisableChannel\n - * CCER CC6E LL_TIM_CC_DisableChannel - * @param TIMx Timer instance - * @param Channels This parameter can be a combination of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_CC_DisableChannel(TIM_TypeDef *TIMx, uint32_t Channels) -{ - CLEAR_BIT(TIMx->CCER, Channels); -} - -/** - * @brief Indicate whether channel(s) is(are) enabled. - * @rmtoll CCER CC1E LL_TIM_CC_IsEnabledChannel\n - * CCER CC1NE LL_TIM_CC_IsEnabledChannel\n - * CCER CC2E LL_TIM_CC_IsEnabledChannel\n - * CCER CC2NE LL_TIM_CC_IsEnabledChannel\n - * CCER CC3E LL_TIM_CC_IsEnabledChannel\n - * CCER CC3NE LL_TIM_CC_IsEnabledChannel\n - * CCER CC4E LL_TIM_CC_IsEnabledChannel\n - * CCER CC5E LL_TIM_CC_IsEnabledChannel\n - * CCER CC6E LL_TIM_CC_IsEnabledChannel - * @param TIMx Timer instance - * @param Channels This parameter can be a combination of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_CC_IsEnabledChannel(const TIM_TypeDef *TIMx, uint32_t Channels) -{ - return ((READ_BIT(TIMx->CCER, Channels) == (Channels)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Output_Channel Output channel configuration - * @{ - */ -/** - * @brief Configure an output channel. - * @rmtoll CCMR1 CC1S LL_TIM_OC_ConfigOutput\n - * CCMR1 CC2S LL_TIM_OC_ConfigOutput\n - * CCMR2 CC3S LL_TIM_OC_ConfigOutput\n - * CCMR2 CC4S LL_TIM_OC_ConfigOutput\n - * CCMR3 CC5S LL_TIM_OC_ConfigOutput\n - * CCMR3 CC6S LL_TIM_OC_ConfigOutput\n - * CCER CC1P LL_TIM_OC_ConfigOutput\n - * CCER CC2P LL_TIM_OC_ConfigOutput\n - * CCER CC3P LL_TIM_OC_ConfigOutput\n - * CCER CC4P LL_TIM_OC_ConfigOutput\n - * CCER CC5P LL_TIM_OC_ConfigOutput\n - * CCER CC6P LL_TIM_OC_ConfigOutput\n - * CR2 OIS1 LL_TIM_OC_ConfigOutput\n - * CR2 OIS2 LL_TIM_OC_ConfigOutput\n - * CR2 OIS3 LL_TIM_OC_ConfigOutput\n - * CR2 OIS4 LL_TIM_OC_ConfigOutput\n - * CR2 OIS5 LL_TIM_OC_ConfigOutput\n - * CR2 OIS6 LL_TIM_OC_ConfigOutput - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param Configuration This parameter must be a combination of all the following values: - * @arg @ref LL_TIM_OCPOLARITY_HIGH or @ref LL_TIM_OCPOLARITY_LOW - * @arg @ref LL_TIM_OCIDLESTATE_LOW or @ref LL_TIM_OCIDLESTATE_HIGH - * @retval None - */ -static inline void LL_TIM_OC_ConfigOutput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_CC1S << SHIFT_TAB_OCxx[iChannel])); - MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), - (Configuration & TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]); - MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), - (Configuration & TIM_CR2_OIS1) << SHIFT_TAB_OISx[iChannel]); -} - -/** - * @brief Define the behavior of the output reference signal OCxREF from which - * OCx and OCxN (when relevant) are derived. - * @rmtoll CCMR1 OC1M LL_TIM_OC_SetMode\n - * CCMR1 OC2M LL_TIM_OC_SetMode\n - * CCMR2 OC3M LL_TIM_OC_SetMode\n - * CCMR2 OC4M LL_TIM_OC_SetMode\n - * CCMR3 OC5M LL_TIM_OC_SetMode\n - * CCMR3 OC6M LL_TIM_OC_SetMode - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param Mode This parameter can be one of the following values: - * @arg @ref LL_TIM_OCMODE_FROZEN - * @arg @ref LL_TIM_OCMODE_ACTIVE - * @arg @ref LL_TIM_OCMODE_INACTIVE - * @arg @ref LL_TIM_OCMODE_TOGGLE - * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE - * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE - * @arg @ref LL_TIM_OCMODE_PWM1 - * @arg @ref LL_TIM_OCMODE_PWM2 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 - * @retval None - */ -static inline void LL_TIM_OC_SetMode(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Mode) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel]), Mode << SHIFT_TAB_OCxx[iChannel]); -} - -/** - * @brief Get the output compare mode of an output channel. - * @rmtoll CCMR1 OC1M LL_TIM_OC_GetMode\n - * CCMR1 OC2M LL_TIM_OC_GetMode\n - * CCMR2 OC3M LL_TIM_OC_GetMode\n - * CCMR2 OC4M LL_TIM_OC_GetMode\n - * CCMR3 OC5M LL_TIM_OC_GetMode\n - * CCMR3 OC6M LL_TIM_OC_GetMode - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_OCMODE_FROZEN - * @arg @ref LL_TIM_OCMODE_ACTIVE - * @arg @ref LL_TIM_OCMODE_INACTIVE - * @arg @ref LL_TIM_OCMODE_TOGGLE - * @arg @ref LL_TIM_OCMODE_FORCED_INACTIVE - * @arg @ref LL_TIM_OCMODE_FORCED_ACTIVE - * @arg @ref LL_TIM_OCMODE_PWM1 - * @arg @ref LL_TIM_OCMODE_PWM2 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM1 - * @arg @ref LL_TIM_OCMODE_RETRIG_OPM2 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM1 - * @arg @ref LL_TIM_OCMODE_COMBINED_PWM2 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM1 - * @arg @ref LL_TIM_OCMODE_ASYMMETRIC_PWM2 - */ -static inline uint32_t LL_TIM_OC_GetMode(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return (READ_BIT(*pReg, ((TIM_CCMR1_OC1M | TIM_CCMR1_CC1S) << SHIFT_TAB_OCxx[iChannel])) >> SHIFT_TAB_OCxx[iChannel]); -} - -/** - * @brief Set the polarity of an output channel. - * @rmtoll CCER CC1P LL_TIM_OC_SetPolarity\n - * CCER CC1NP LL_TIM_OC_SetPolarity\n - * CCER CC2P LL_TIM_OC_SetPolarity\n - * CCER CC2NP LL_TIM_OC_SetPolarity\n - * CCER CC3P LL_TIM_OC_SetPolarity\n - * CCER CC3NP LL_TIM_OC_SetPolarity\n - * CCER CC4P LL_TIM_OC_SetPolarity\n - * CCER CC5P LL_TIM_OC_SetPolarity\n - * CCER CC6P LL_TIM_OC_SetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_OCPOLARITY_HIGH - * @arg @ref LL_TIM_OCPOLARITY_LOW - * @retval None - */ -static inline void LL_TIM_OC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Polarity) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - MODIFY_REG(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel]), Polarity << SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Get the polarity of an output channel. - * @rmtoll CCER CC1P LL_TIM_OC_GetPolarity\n - * CCER CC1NP LL_TIM_OC_GetPolarity\n - * CCER CC2P LL_TIM_OC_GetPolarity\n - * CCER CC2NP LL_TIM_OC_GetPolarity\n - * CCER CC3P LL_TIM_OC_GetPolarity\n - * CCER CC3NP LL_TIM_OC_GetPolarity\n - * CCER CC4P LL_TIM_OC_GetPolarity\n - * CCER CC5P LL_TIM_OC_GetPolarity\n - * CCER CC6P LL_TIM_OC_GetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_OCPOLARITY_HIGH - * @arg @ref LL_TIM_OCPOLARITY_LOW - */ -static inline uint32_t LL_TIM_OC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - return (READ_BIT(TIMx->CCER, (TIM_CCER_CC1P << SHIFT_TAB_CCxP[iChannel])) >> SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Set the IDLE state of an output channel - * @note This function is significant only for the timer instances - * supporting the break feature. Macro IS_TIM_BREAK_INSTANCE(TIMx) - * can be used to check whether or not a timer instance provides - * a break input. - * @rmtoll CR2 OIS1 LL_TIM_OC_SetIdleState\n - * CR2 OIS2N LL_TIM_OC_SetIdleState\n - * CR2 OIS2 LL_TIM_OC_SetIdleState\n - * CR2 OIS2N LL_TIM_OC_SetIdleState\n - * CR2 OIS3 LL_TIM_OC_SetIdleState\n - * CR2 OIS3N LL_TIM_OC_SetIdleState\n - * CR2 OIS4 LL_TIM_OC_SetIdleState\n - * CR2 OIS5 LL_TIM_OC_SetIdleState\n - * CR2 OIS6 LL_TIM_OC_SetIdleState - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @param IdleState This parameter can be one of the following values: - * @arg @ref LL_TIM_OCIDLESTATE_LOW - * @arg @ref LL_TIM_OCIDLESTATE_HIGH - * @retval None - */ -static inline void LL_TIM_OC_SetIdleState(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t IdleState) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - MODIFY_REG(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel]), IdleState << SHIFT_TAB_OISx[iChannel]); -} - -/** - * @brief Get the IDLE state of an output channel - * @rmtoll CR2 OIS1 LL_TIM_OC_GetIdleState\n - * CR2 OIS2N LL_TIM_OC_GetIdleState\n - * CR2 OIS2 LL_TIM_OC_GetIdleState\n - * CR2 OIS2N LL_TIM_OC_GetIdleState\n - * CR2 OIS3 LL_TIM_OC_GetIdleState\n - * CR2 OIS3N LL_TIM_OC_GetIdleState\n - * CR2 OIS4 LL_TIM_OC_GetIdleState\n - * CR2 OIS5 LL_TIM_OC_GetIdleState\n - * CR2 OIS6 LL_TIM_OC_GetIdleState - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH1N - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH2N - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH3N - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_OCIDLESTATE_LOW - * @arg @ref LL_TIM_OCIDLESTATE_HIGH - */ -static inline uint32_t LL_TIM_OC_GetIdleState(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - return (READ_BIT(TIMx->CR2, (TIM_CR2_OIS1 << SHIFT_TAB_OISx[iChannel])) >> SHIFT_TAB_OISx[iChannel]); -} - -/** - * @brief Enable fast mode for the output channel. - * @note Acts only if the channel is configured in PWM1 or PWM2 mode. - * @rmtoll CCMR1 OC1FE LL_TIM_OC_EnableFast\n - * CCMR1 OC2FE LL_TIM_OC_EnableFast\n - * CCMR2 OC3FE LL_TIM_OC_EnableFast\n - * CCMR2 OC4FE LL_TIM_OC_EnableFast\n - * CCMR3 OC5FE LL_TIM_OC_EnableFast\n - * CCMR3 OC6FE LL_TIM_OC_EnableFast - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_EnableFast(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - SET_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); - -} - -/** - * @brief Disable fast mode for the output channel. - * @rmtoll CCMR1 OC1FE LL_TIM_OC_DisableFast\n - * CCMR1 OC2FE LL_TIM_OC_DisableFast\n - * CCMR2 OC3FE LL_TIM_OC_DisableFast\n - * CCMR2 OC4FE LL_TIM_OC_DisableFast\n - * CCMR3 OC5FE LL_TIM_OC_DisableFast\n - * CCMR3 OC6FE LL_TIM_OC_DisableFast - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_DisableFast(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel])); - -} - -/** - * @brief Indicates whether fast mode is enabled for the output channel. - * @rmtoll CCMR1 OC1FE LL_TIM_OC_IsEnabledFast\n - * CCMR1 OC2FE LL_TIM_OC_IsEnabledFast\n - * CCMR2 OC3FE LL_TIM_OC_IsEnabledFast\n - * CCMR2 OC4FE LL_TIM_OC_IsEnabledFast\n - * CCMR3 OC5FE LL_TIM_OC_IsEnabledFast\n - * CCMR3 OC6FE LL_TIM_OC_IsEnabledFast - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_OC_IsEnabledFast(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - uint32_t bitfield = TIM_CCMR1_OC1FE << SHIFT_TAB_OCxx[iChannel]; - return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); -} - -/** - * @brief Enable compare register (TIMx_CCRx) preload for the output channel. - * @rmtoll CCMR1 OC1PE LL_TIM_OC_EnablePreload\n - * CCMR1 OC2PE LL_TIM_OC_EnablePreload\n - * CCMR2 OC3PE LL_TIM_OC_EnablePreload\n - * CCMR2 OC4PE LL_TIM_OC_EnablePreload\n - * CCMR3 OC5PE LL_TIM_OC_EnablePreload\n - * CCMR3 OC6PE LL_TIM_OC_EnablePreload - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_EnablePreload(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - SET_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Disable compare register (TIMx_CCRx) preload for the output channel. - * @rmtoll CCMR1 OC1PE LL_TIM_OC_DisablePreload\n - * CCMR1 OC2PE LL_TIM_OC_DisablePreload\n - * CCMR2 OC3PE LL_TIM_OC_DisablePreload\n - * CCMR2 OC4PE LL_TIM_OC_DisablePreload\n - * CCMR3 OC5PE LL_TIM_OC_DisablePreload\n - * CCMR3 OC6PE LL_TIM_OC_DisablePreload - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_DisablePreload(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Indicates whether compare register (TIMx_CCRx) preload is enabled for the output channel. - * @rmtoll CCMR1 OC1PE LL_TIM_OC_IsEnabledPreload\n - * CCMR1 OC2PE LL_TIM_OC_IsEnabledPreload\n - * CCMR2 OC3PE LL_TIM_OC_IsEnabledPreload\n - * CCMR2 OC4PE LL_TIM_OC_IsEnabledPreload\n - * CCMR3 OC5PE LL_TIM_OC_IsEnabledPreload\n - * CCMR3 OC6PE LL_TIM_OC_IsEnabledPreload - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_OC_IsEnabledPreload(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - uint32_t bitfield = TIM_CCMR1_OC1PE << SHIFT_TAB_OCxx[iChannel]; - return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); -} - -/** - * @brief Enable clearing the output channel on an external event. - * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. - * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether - * or not a timer instance can clear the OCxREF signal on an external event. - * @rmtoll CCMR1 OC1CE LL_TIM_OC_EnableClear\n - * CCMR1 OC2CE LL_TIM_OC_EnableClear\n - * CCMR2 OC3CE LL_TIM_OC_EnableClear\n - * CCMR2 OC4CE LL_TIM_OC_EnableClear\n - * CCMR3 OC5CE LL_TIM_OC_EnableClear\n - * CCMR3 OC6CE LL_TIM_OC_EnableClear - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_EnableClear(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - SET_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Disable clearing the output channel on an external event. - * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether - * or not a timer instance can clear the OCxREF signal on an external event. - * @rmtoll CCMR1 OC1CE LL_TIM_OC_DisableClear\n - * CCMR1 OC2CE LL_TIM_OC_DisableClear\n - * CCMR2 OC3CE LL_TIM_OC_DisableClear\n - * CCMR2 OC4CE LL_TIM_OC_DisableClear\n - * CCMR3 OC5CE LL_TIM_OC_DisableClear\n - * CCMR3 OC6CE LL_TIM_OC_DisableClear - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval None - */ -static inline void LL_TIM_OC_DisableClear(TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - CLEAR_BIT(*pReg, (TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel])); -} - -/** - * @brief Indicates clearing the output channel on an external event is enabled for the output channel. - * @note This function enables clearing the output channel on an external event. - * @note This function can only be used in Output compare and PWM modes. It does not work in Forced mode. - * @note Macro IS_TIM_OCXREF_CLEAR_INSTANCE(TIMx) can be used to check whether - * or not a timer instance can clear the OCxREF signal on an external event. - * @rmtoll CCMR1 OC1CE LL_TIM_OC_IsEnabledClear\n - * CCMR1 OC2CE LL_TIM_OC_IsEnabledClear\n - * CCMR2 OC3CE LL_TIM_OC_IsEnabledClear\n - * CCMR2 OC4CE LL_TIM_OC_IsEnabledClear\n - * CCMR3 OC5CE LL_TIM_OC_IsEnabledClear\n - * CCMR3 OC6CE LL_TIM_OC_IsEnabledClear - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @arg @ref LL_TIM_CHANNEL_CH5 - * @arg @ref LL_TIM_CHANNEL_CH6 - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_OC_IsEnabledClear(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - uint32_t bitfield = TIM_CCMR1_OC1CE << SHIFT_TAB_OCxx[iChannel]; - return ((READ_BIT(*pReg, bitfield) == bitfield) ? 1UL : 0UL); -} - -/** - * @brief Set the dead-time delay (delay inserted between the rising edge of the OCxREF signal and the rising edge of - * the Ocx and OCxN signals). - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * dead-time insertion feature is supported by a timer instance. - * @note Helper macro @ref __LL_TIM_CALC_DEADTIME can be used to calculate the DeadTime parameter - * @rmtoll BDTR DTG LL_TIM_OC_SetDeadTime - * @param TIMx Timer instance - * @param DeadTime between Min_Data=0 and Max_Data=255 - * @retval None - */ -static inline void LL_TIM_OC_SetDeadTime(TIM_TypeDef *TIMx, uint32_t DeadTime) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_DTG, DeadTime); -} - -/** - * @brief Set compare value for output channel 1 (TIMx_CCR1). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not - * output channel 1 is supported by a timer instance. - * @rmtoll CCR1 CCR1 LL_TIM_OC_SetCompareCH1 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH1(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR1, CompareValue); -} - -/** - * @brief Set compare value for output channel 2 (TIMx_CCR2). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not - * output channel 2 is supported by a timer instance. - * @rmtoll CCR2 CCR2 LL_TIM_OC_SetCompareCH2 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH2(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR2, CompareValue); -} - -/** - * @brief Set compare value for output channel 3 (TIMx_CCR3). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not - * output channel is supported by a timer instance. - * @rmtoll CCR3 CCR3 LL_TIM_OC_SetCompareCH3 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH3(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR3, CompareValue); -} - -/** - * @brief Set compare value for output channel 4 (TIMx_CCR4). - * @note In 32-bit timer implementations compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not - * output channel 4 is supported by a timer instance. - * @rmtoll CCR4 CCR4 LL_TIM_OC_SetCompareCH4 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH4(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR4, CompareValue); -} - -/** - * @brief Set compare value for output channel 5 (TIMx_CCR5). - * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not - * output channel 5 is supported by a timer instance. - * @rmtoll CCR5 CCR5 LL_TIM_OC_SetCompareCH5 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH5(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - MODIFY_REG(TIMx->CCR5, TIM_CCR5_CCR5, CompareValue); -} - -/** - * @brief Set compare value for output channel 6 (TIMx_CCR6). - * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not - * output channel 6 is supported by a timer instance. - * @rmtoll CCR6 CCR6 LL_TIM_OC_SetCompareCH6 - * @param TIMx Timer instance - * @param CompareValue between Min_Data=0 and Max_Data=65535 - * @retval None - */ -static inline void LL_TIM_OC_SetCompareCH6(TIM_TypeDef *TIMx, uint32_t CompareValue) -{ - WRITE_REG(TIMx->CCR6, CompareValue); -} - -/** - * @brief Get compare value (TIMx_CCR1) set for output channel 1. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not - * output channel 1 is supported by a timer instance. - * @rmtoll CCR1 CCR1 LL_TIM_OC_GetCompareCH1 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH1(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR1)); -} - -/** - * @brief Get compare value (TIMx_CCR2) set for output channel 2. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not - * output channel 2 is supported by a timer instance. - * @rmtoll CCR2 CCR2 LL_TIM_OC_GetCompareCH2 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH2(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR2)); -} - -/** - * @brief Get compare value (TIMx_CCR3) set for output channel 3. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not - * output channel 3 is supported by a timer instance. - * @rmtoll CCR3 CCR3 LL_TIM_OC_GetCompareCH3 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH3(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR3)); -} - -/** - * @brief Get compare value (TIMx_CCR4) set for output channel 4. - * @note In 32-bit timer implementations returned compare value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not - * output channel 4 is supported by a timer instance. - * @rmtoll CCR4 CCR4 LL_TIM_OC_GetCompareCH4 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH4(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR4)); -} - -/** - * @brief Get compare value (TIMx_CCR5) set for output channel 5. - * @note Macro IS_TIM_CC5_INSTANCE(TIMx) can be used to check whether or not - * output channel 5 is supported by a timer instance. - * @rmtoll CCR5 CCR5 LL_TIM_OC_GetCompareCH5 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH5(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_BIT(TIMx->CCR5, TIM_CCR5_CCR5)); -} - -/** - * @brief Get compare value (TIMx_CCR6) set for output channel 6. - * @note Macro IS_TIM_CC6_INSTANCE(TIMx) can be used to check whether or not - * output channel 6 is supported by a timer instance. - * @rmtoll CCR6 CCR6 LL_TIM_OC_GetCompareCH6 - * @param TIMx Timer instance - * @retval CompareValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_OC_GetCompareCH6(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR6)); -} - -/** - * @brief Select on which reference signal the OC5REF is combined to. - * @note Macro IS_TIM_COMBINED3PHASEPWM_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports the combined 3-phase PWM mode. - * @rmtoll CCR5 GC5C3 LL_TIM_SetCH5CombinedChannels\n - * CCR5 GC5C2 LL_TIM_SetCH5CombinedChannels\n - * CCR5 GC5C1 LL_TIM_SetCH5CombinedChannels - * @param TIMx Timer instance - * @param GroupCH5 This parameter can be a combination of the following values: - * @arg @ref LL_TIM_GROUPCH5_NONE - * @arg @ref LL_TIM_GROUPCH5_OC1REFC - * @arg @ref LL_TIM_GROUPCH5_OC2REFC - * @arg @ref LL_TIM_GROUPCH5_OC3REFC - * @retval None - */ -static inline void LL_TIM_SetCH5CombinedChannels(TIM_TypeDef *TIMx, uint32_t GroupCH5) -{ - MODIFY_REG(TIMx->CCR5, (TIM_CCR5_GC5C3 | TIM_CCR5_GC5C2 | TIM_CCR5_GC5C1), GroupCH5); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Input_Channel Input channel configuration - * @{ - */ -/** - * @brief Configure input channel. - * @rmtoll CCMR1 CC1S LL_TIM_IC_Config\n - * CCMR1 IC1PSC LL_TIM_IC_Config\n - * CCMR1 IC1F LL_TIM_IC_Config\n - * CCMR1 CC2S LL_TIM_IC_Config\n - * CCMR1 IC2PSC LL_TIM_IC_Config\n - * CCMR1 IC2F LL_TIM_IC_Config\n - * CCMR2 CC3S LL_TIM_IC_Config\n - * CCMR2 IC3PSC LL_TIM_IC_Config\n - * CCMR2 IC3F LL_TIM_IC_Config\n - * CCMR2 CC4S LL_TIM_IC_Config\n - * CCMR2 IC4PSC LL_TIM_IC_Config\n - * CCMR2 IC4F LL_TIM_IC_Config\n - * CCER CC1P LL_TIM_IC_Config\n - * CCER CC1NP LL_TIM_IC_Config\n - * CCER CC2P LL_TIM_IC_Config\n - * CCER CC2NP LL_TIM_IC_Config\n - * CCER CC3P LL_TIM_IC_Config\n - * CCER CC3NP LL_TIM_IC_Config\n - * CCER CC4P LL_TIM_IC_Config\n - * CCER CC4NP LL_TIM_IC_Config - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param Configuration This parameter must be a combination of all the following values: - * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI or @ref LL_TIM_ACTIVEINPUT_INDIRECTTI or @ref LL_TIM_ACTIVEINPUT_TRC - * @arg @ref LL_TIM_ICPSC_DIV1 or ... or @ref LL_TIM_ICPSC_DIV8 - * @arg @ref LL_TIM_IC_FILTER_FDIV1 or ... or @ref LL_TIM_IC_FILTER_FDIV32_N8 - * @arg @ref LL_TIM_IC_POLARITY_RISING or @ref LL_TIM_IC_POLARITY_FALLING or @ref LL_TIM_IC_POLARITY_BOTHEDGE - * @retval None - */ -static inline void LL_TIM_IC_Config(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t Configuration) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), - ((Configuration >> 16U) & (TIM_CCMR1_IC1F | TIM_CCMR1_IC1PSC | TIM_CCMR1_CC1S)) \ - << SHIFT_TAB_ICxx[iChannel]); - MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), - (Configuration & (TIM_CCER_CC1NP | TIM_CCER_CC1P)) << SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Set the active input. - * @rmtoll CCMR1 CC1S LL_TIM_IC_SetActiveInput\n - * CCMR1 CC2S LL_TIM_IC_SetActiveInput\n - * CCMR2 CC3S LL_TIM_IC_SetActiveInput\n - * CCMR2 CC4S LL_TIM_IC_SetActiveInput - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICActiveInput This parameter can be one of the following values: - * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_TRC - * @retval None - */ -static inline void LL_TIM_IC_SetActiveInput(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICActiveInput) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel]), (ICActiveInput >> 16U) << SHIFT_TAB_ICxx[iChannel]); -} - -/** - * @brief Get the current active input. - * @rmtoll CCMR1 CC1S LL_TIM_IC_GetActiveInput\n - * CCMR1 CC2S LL_TIM_IC_GetActiveInput\n - * CCMR2 CC3S LL_TIM_IC_GetActiveInput\n - * CCMR2 CC4S LL_TIM_IC_GetActiveInput - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_ACTIVEINPUT_DIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_INDIRECTTI - * @arg @ref LL_TIM_ACTIVEINPUT_TRC - */ -static inline uint32_t LL_TIM_IC_GetActiveInput(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return ((READ_BIT(*pReg, ((TIM_CCMR1_CC1S) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); -} - -/** - * @brief Set the prescaler of input channel. - * @rmtoll CCMR1 IC1PSC LL_TIM_IC_SetPrescaler\n - * CCMR1 IC2PSC LL_TIM_IC_SetPrescaler\n - * CCMR2 IC3PSC LL_TIM_IC_SetPrescaler\n - * CCMR2 IC4PSC LL_TIM_IC_SetPrescaler - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICPrescaler This parameter can be one of the following values: - * @arg @ref LL_TIM_ICPSC_DIV1 - * @arg @ref LL_TIM_ICPSC_DIV2 - * @arg @ref LL_TIM_ICPSC_DIV4 - * @arg @ref LL_TIM_ICPSC_DIV8 - * @retval None - */ -static inline void LL_TIM_IC_SetPrescaler(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPrescaler) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel]), (ICPrescaler >> 16U) << SHIFT_TAB_ICxx[iChannel]); -} - -/** - * @brief Get the current prescaler value acting on an input channel. - * @rmtoll CCMR1 IC1PSC LL_TIM_IC_GetPrescaler\n - * CCMR1 IC2PSC LL_TIM_IC_GetPrescaler\n - * CCMR2 IC3PSC LL_TIM_IC_GetPrescaler\n - * CCMR2 IC4PSC LL_TIM_IC_GetPrescaler - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_ICPSC_DIV1 - * @arg @ref LL_TIM_ICPSC_DIV2 - * @arg @ref LL_TIM_ICPSC_DIV4 - * @arg @ref LL_TIM_ICPSC_DIV8 - */ -static inline uint32_t LL_TIM_IC_GetPrescaler(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1PSC) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); -} - -/** - * @brief Set the input filter duration. - * @rmtoll CCMR1 IC1F LL_TIM_IC_SetFilter\n - * CCMR1 IC2F LL_TIM_IC_SetFilter\n - * CCMR2 IC3F LL_TIM_IC_SetFilter\n - * CCMR2 IC4F LL_TIM_IC_SetFilter - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_IC_FILTER_FDIV1 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_IC_SetFilter(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICFilter) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - MODIFY_REG(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel]), (ICFilter >> 16U) << SHIFT_TAB_ICxx[iChannel]); -} - -/** - * @brief Get the input filter duration. - * @rmtoll CCMR1 IC1F LL_TIM_IC_GetFilter\n - * CCMR1 IC2F LL_TIM_IC_GetFilter\n - * CCMR2 IC3F LL_TIM_IC_GetFilter\n - * CCMR2 IC4F LL_TIM_IC_GetFilter - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_IC_FILTER_FDIV1 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_IC_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_IC_FILTER_FDIV32_N8 - */ -static inline uint32_t LL_TIM_IC_GetFilter(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - const __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->CCMR1) + OFFSET_TAB_CCMRx[iChannel])); - return ((READ_BIT(*pReg, ((TIM_CCMR1_IC1F) << SHIFT_TAB_ICxx[iChannel])) >> SHIFT_TAB_ICxx[iChannel]) << 16U); -} - -/** - * @brief Set the input channel polarity. - * @rmtoll CCER CC1P LL_TIM_IC_SetPolarity\n - * CCER CC1NP LL_TIM_IC_SetPolarity\n - * CCER CC2P LL_TIM_IC_SetPolarity\n - * CCER CC2NP LL_TIM_IC_SetPolarity\n - * CCER CC3P LL_TIM_IC_SetPolarity\n - * CCER CC3NP LL_TIM_IC_SetPolarity\n - * CCER CC4P LL_TIM_IC_SetPolarity\n - * CCER CC4NP LL_TIM_IC_SetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @param ICPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_IC_POLARITY_RISING - * @arg @ref LL_TIM_IC_POLARITY_FALLING - * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE - * @retval None - */ -static inline void LL_TIM_IC_SetPolarity(TIM_TypeDef *TIMx, uint32_t Channel, uint32_t ICPolarity) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - MODIFY_REG(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel]), - ICPolarity << SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Get the current input channel polarity. - * @rmtoll CCER CC1P LL_TIM_IC_GetPolarity\n - * CCER CC1NP LL_TIM_IC_GetPolarity\n - * CCER CC2P LL_TIM_IC_GetPolarity\n - * CCER CC2NP LL_TIM_IC_GetPolarity\n - * CCER CC3P LL_TIM_IC_GetPolarity\n - * CCER CC3NP LL_TIM_IC_GetPolarity\n - * CCER CC4P LL_TIM_IC_GetPolarity\n - * CCER CC4NP LL_TIM_IC_GetPolarity - * @param TIMx Timer instance - * @param Channel This parameter can be one of the following values: - * @arg @ref LL_TIM_CHANNEL_CH1 - * @arg @ref LL_TIM_CHANNEL_CH2 - * @arg @ref LL_TIM_CHANNEL_CH3 - * @arg @ref LL_TIM_CHANNEL_CH4 - * @retval Returned value can be one of the following values: - * @arg @ref LL_TIM_IC_POLARITY_RISING - * @arg @ref LL_TIM_IC_POLARITY_FALLING - * @arg @ref LL_TIM_IC_POLARITY_BOTHEDGE - */ -static inline uint32_t LL_TIM_IC_GetPolarity(const TIM_TypeDef *TIMx, uint32_t Channel) -{ - uint8_t iChannel = TIM_GET_CHANNEL_INDEX(Channel); - return (READ_BIT(TIMx->CCER, ((TIM_CCER_CC1NP | TIM_CCER_CC1P) << SHIFT_TAB_CCxP[iChannel])) >> - SHIFT_TAB_CCxP[iChannel]); -} - -/** - * @brief Connect the TIMx_CH1, CH2 and CH3 pins to the TI1 input (XOR combination). - * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an XOR input. - * @rmtoll CR2 TI1S LL_TIM_IC_EnableXORCombination - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_IC_EnableXORCombination(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->CR2, TIM_CR2_TI1S); -} - -/** - * @brief Disconnect the TIMx_CH1, CH2 and CH3 pins from the TI1 input. - * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an XOR input. - * @rmtoll CR2 TI1S LL_TIM_IC_DisableXORCombination - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_IC_DisableXORCombination(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->CR2, TIM_CR2_TI1S); -} - -/** - * @brief Indicates whether the TIMx_CH1, CH2 and CH3 pins are connectected to the TI1 input. - * @note Macro IS_TIM_XOR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an XOR input. - * @rmtoll CR2 TI1S LL_TIM_IC_IsEnabledXORCombination - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IC_IsEnabledXORCombination(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->CR2, TIM_CR2_TI1S) == (TIM_CR2_TI1S)) ? 1UL : 0UL); -} - -/** - * @brief Get captured value for input channel 1. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC1_INSTANCE(TIMx) can be used to check whether or not - * input channel 1 is supported by a timer instance. - * @rmtoll CCR1 CCR1 LL_TIM_IC_GetCaptureCH1 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH1(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR1)); -} - -/** - * @brief Get captured value for input channel 2. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC2_INSTANCE(TIMx) can be used to check whether or not - * input channel 2 is supported by a timer instance. - * @rmtoll CCR2 CCR2 LL_TIM_IC_GetCaptureCH2 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH2(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR2)); -} - -/** - * @brief Get captured value for input channel 3. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC3_INSTANCE(TIMx) can be used to check whether or not - * input channel 3 is supported by a timer instance. - * @rmtoll CCR3 CCR3 LL_TIM_IC_GetCaptureCH3 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH3(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR3)); -} - -/** - * @brief Get captured value for input channel 4. - * @note In 32-bit timer implementations returned captured value can be between 0x00000000 and 0xFFFFFFFF. - * @note Macro IS_TIM_32B_COUNTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports a 32 bits counter. - * @note Macro IS_TIM_CC4_INSTANCE(TIMx) can be used to check whether or not - * input channel 4 is supported by a timer instance. - * @rmtoll CCR4 CCR4 LL_TIM_IC_GetCaptureCH4 - * @param TIMx Timer instance - * @retval CapturedValue (between Min_Data=0 and Max_Data=65535) - */ -static inline uint32_t LL_TIM_IC_GetCaptureCH4(const TIM_TypeDef *TIMx) -{ - return (uint32_t)(READ_REG(TIMx->CCR4)); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Clock_Selection Counter clock selection - * @{ - */ -/** - * @brief Enable external clock mode 2. - * @note When external clock mode 2 is enabled the counter is clocked by any active edge on the ETRF signal. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR ECE LL_TIM_EnableExternalClock - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableExternalClock(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->SMCR, TIM_SMCR_ECE); -} - -/** - * @brief Disable external clock mode 2. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR ECE LL_TIM_DisableExternalClock - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableExternalClock(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->SMCR, TIM_SMCR_ECE); -} - -/** - * @brief Indicate whether external clock mode 2 is enabled. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR ECE LL_TIM_IsEnabledExternalClock - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledExternalClock(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SMCR, TIM_SMCR_ECE) == (TIM_SMCR_ECE)) ? 1UL : 0UL); -} - -/** - * @brief Set the clock source of the counter clock. - * @note when selected clock source is external clock mode 1, the timer input - * the external clock is applied is selected by calling the @ref LL_TIM_SetTriggerInput() - * function. This timer input must be configured by calling - * the @ref LL_TIM_IC_Config() function. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE1_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode1. - * @note Macro IS_TIM_CLOCKSOURCE_ETRMODE2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports external clock mode2. - * @rmtoll SMCR SMS LL_TIM_SetClockSource\n - * SMCR ECE LL_TIM_SetClockSource - * @param TIMx Timer instance - * @param ClockSource This parameter can be one of the following values: - * @arg @ref LL_TIM_CLOCKSOURCE_INTERNAL - * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE1 - * @arg @ref LL_TIM_CLOCKSOURCE_EXT_MODE2 - * @retval None - */ -static inline void LL_TIM_SetClockSource(TIM_TypeDef *TIMx, uint32_t ClockSource) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS | TIM_SMCR_ECE, ClockSource); -} - -/** - * @brief Set the encoder interface mode. - * @note Macro IS_TIM_ENCODER_INTERFACE_INSTANCE(TIMx) can be used to check - * whether or not a timer instance supports the encoder mode. - * @rmtoll SMCR SMS LL_TIM_SetEncoderMode - * @param TIMx Timer instance - * @param EncoderMode This parameter can be one of the following values: - * @arg @ref LL_TIM_ENCODERMODE_X2_TI1 - * @arg @ref LL_TIM_ENCODERMODE_X2_TI2 - * @arg @ref LL_TIM_ENCODERMODE_X4_TI12 - * @retval None - */ -static inline void LL_TIM_SetEncoderMode(TIM_TypeDef *TIMx, uint32_t EncoderMode) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, EncoderMode); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Timer_Synchronization Timer synchronisation configuration - * @{ - */ -/** - * @brief Set the trigger output (TRGO) used for timer synchronization . - * @note Macro IS_TIM_MASTER_INSTANCE(TIMx) can be used to check - * whether or not a timer instance can operate as a master timer. - * @rmtoll CR2 MMS LL_TIM_SetTriggerOutput - * @param TIMx Timer instance - * @param TimerSynchronization This parameter can be one of the following values: - * @arg @ref LL_TIM_TRGO_RESET - * @arg @ref LL_TIM_TRGO_ENABLE - * @arg @ref LL_TIM_TRGO_UPDATE - * @arg @ref LL_TIM_TRGO_CC1IF - * @arg @ref LL_TIM_TRGO_OC1REF - * @arg @ref LL_TIM_TRGO_OC2REF - * @arg @ref LL_TIM_TRGO_OC3REF - * @arg @ref LL_TIM_TRGO_OC4REF - * @retval None - */ -static inline void LL_TIM_SetTriggerOutput(TIM_TypeDef *TIMx, uint32_t TimerSynchronization) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_MMS, TimerSynchronization); -} - -/** - * @brief Set the trigger output 2 (TRGO2) used for ADC synchronization . - * @note Macro IS_TIM_TRGO2_INSTANCE(TIMx) can be used to check - * whether or not a timer instance can be used for ADC synchronization. - * @rmtoll CR2 MMS2 LL_TIM_SetTriggerOutput2 - * @param TIMx Timer Instance - * @param ADCSynchronization This parameter can be one of the following values: - * @arg @ref LL_TIM_TRGO2_RESET - * @arg @ref LL_TIM_TRGO2_ENABLE - * @arg @ref LL_TIM_TRGO2_UPDATE - * @arg @ref LL_TIM_TRGO2_CC1F - * @arg @ref LL_TIM_TRGO2_OC1 - * @arg @ref LL_TIM_TRGO2_OC2 - * @arg @ref LL_TIM_TRGO2_OC3 - * @arg @ref LL_TIM_TRGO2_OC4 - * @arg @ref LL_TIM_TRGO2_OC5 - * @arg @ref LL_TIM_TRGO2_OC6 - * @arg @ref LL_TIM_TRGO2_OC4_RISINGFALLING - * @arg @ref LL_TIM_TRGO2_OC6_RISINGFALLING - * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_RISING - * @arg @ref LL_TIM_TRGO2_OC4_RISING_OC6_FALLING - * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_RISING - * @arg @ref LL_TIM_TRGO2_OC5_RISING_OC6_FALLING - * @retval None - */ -static inline void LL_TIM_SetTriggerOutput2(TIM_TypeDef *TIMx, uint32_t ADCSynchronization) -{ - MODIFY_REG(TIMx->CR2, TIM_CR2_MMS2, ADCSynchronization); -} - -/** - * @brief Set the synchronization mode of a slave timer. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR SMS LL_TIM_SetSlaveMode - * @param TIMx Timer instance - * @param SlaveMode This parameter can be one of the following values: - * @arg @ref LL_TIM_SLAVEMODE_DISABLED - * @arg @ref LL_TIM_SLAVEMODE_RESET - * @arg @ref LL_TIM_SLAVEMODE_GATED - * @arg @ref LL_TIM_SLAVEMODE_TRIGGER - * @arg @ref LL_TIM_SLAVEMODE_COMBINED_RESETTRIGGER - * @retval None - */ -static inline void LL_TIM_SetSlaveMode(TIM_TypeDef *TIMx, uint32_t SlaveMode) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_SMS, SlaveMode); -} - -/** - * @brief Set the selects the trigger input to be used to synchronize the counter. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR TS LL_TIM_SetTriggerInput - * @param TIMx Timer instance - * @param TriggerInput This parameter can be one of the following values: - * @arg @ref LL_TIM_TS_ITR0 - * @arg @ref LL_TIM_TS_ITR1 - * @arg @ref LL_TIM_TS_ITR2 - * @arg @ref LL_TIM_TS_ITR3 - * @arg @ref LL_TIM_TS_ITR4 - * @arg @ref LL_TIM_TS_ITR5 - * @arg @ref LL_TIM_TS_ITR6 - * @arg @ref LL_TIM_TS_ITR7 - * @arg @ref LL_TIM_TS_ITR8 (*) - * @arg @ref LL_TIM_TS_ITR9 (*) - * @arg @ref LL_TIM_TS_ITR10 (*) - * @arg @ref LL_TIM_TS_ITR11 (*) - * @arg @ref LL_TIM_TS_ITR12 (*) - * @arg @ref LL_TIM_TS_ITR13 (*) - * @arg @ref LL_TIM_TS_TI1F_ED - * @arg @ref LL_TIM_TS_TI1FP1 - * @arg @ref LL_TIM_TS_TI2FP2 - * @arg @ref LL_TIM_TS_ETRF - * - * (*) Value not defined in all devices. - * @retval None - */ -static inline void LL_TIM_SetTriggerInput(TIM_TypeDef *TIMx, uint32_t TriggerInput) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_TS, TriggerInput); -} - -/** - * @brief Enable the Master/Slave mode. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR MSM LL_TIM_EnableMasterSlaveMode - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableMasterSlaveMode(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->SMCR, TIM_SMCR_MSM); -} - -/** - * @brief Disable the Master/Slave mode. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR MSM LL_TIM_DisableMasterSlaveMode - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableMasterSlaveMode(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->SMCR, TIM_SMCR_MSM); -} - -/** - * @brief Indicates whether the Master/Slave mode is enabled. - * @note Macro IS_TIM_SLAVE_INSTANCE(TIMx) can be used to check whether or not - * a timer instance can operate as a slave timer. - * @rmtoll SMCR MSM LL_TIM_IsEnabledMasterSlaveMode - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledMasterSlaveMode(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SMCR, TIM_SMCR_MSM) == (TIM_SMCR_MSM)) ? 1UL : 0UL); -} - -/** - * @brief Configure the external trigger (ETR) input. - * @note Macro IS_TIM_ETR_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides an external trigger input. - * @rmtoll SMCR ETP LL_TIM_ConfigETR\n - * SMCR ETPS LL_TIM_ConfigETR\n - * SMCR ETF LL_TIM_ConfigETR - * @param TIMx Timer instance - * @param ETRPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_ETR_POLARITY_NONINVERTED - * @arg @ref LL_TIM_ETR_POLARITY_INVERTED - * @param ETRPrescaler This parameter can be one of the following values: - * @arg @ref LL_TIM_ETR_PRESCALER_DIV1 - * @arg @ref LL_TIM_ETR_PRESCALER_DIV2 - * @arg @ref LL_TIM_ETR_PRESCALER_DIV4 - * @arg @ref LL_TIM_ETR_PRESCALER_DIV8 - * @param ETRFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_ETR_FILTER_FDIV1 - * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_ETR_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_ETR_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_ConfigETR(TIM_TypeDef *TIMx, uint32_t ETRPolarity, uint32_t ETRPrescaler, - uint32_t ETRFilter) -{ - MODIFY_REG(TIMx->SMCR, TIM_SMCR_ETP | TIM_SMCR_ETPS | TIM_SMCR_ETF, ETRPolarity | ETRPrescaler | ETRFilter); -} - -/** - * @brief Select the external trigger (ETR) input source. - * @note Macro IS_TIM_ETRSEL_INSTANCE(TIMx) can be used to check whether or - * not a timer instance supports ETR source selection. - * @rmtoll AF1 ETRSEL LL_TIM_SetETRSource - * @param TIMx Timer instance - * @param ETRSource This parameter can be one of the following values: - * For TIM1, the parameter is one of the following values: - * @arg LL_TIM_TIM1_ETRSOURCE_GPIO: TIM1_ETR is connected to GPIO - * @arg LL_TIM_TIM1_ETRSOURCE_COMP1: TIM1_ETR is connected to COMP1 output - * @arg LL_TIM_TIM1_ETRSOURCE_COMP2: TIM1_ETR is connected to COMP2 output - * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD1: TIM1_ETR is connected to ADC1 AWD1 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD2: TIM1_ETR is connected to ADC1 AWD2 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC1_AWD3: TIM1_ETR is connected to ADC1 AWD3 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD1: TIM1_ETR is connected to ADC3 AWD1 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD2: TIM1_ETR is connected to ADC3 AWD2 - * @arg LL_TIM_TIM1_ETRSOURCE_ADC3_AWD3: TIM1_ETR is connected to ADC3 AWD3 - * - * For TIM2, the parameter is one of the following values: - * @arg LL_TIM_TIM2_ETRSOURCE_GPIO: TIM2_ETR is connected to GPIO - * @arg LL_TIM_TIM2_ETRSOURCE_COMP1: TIM2_ETR is connected to COMP1 output - * @arg LL_TIM_TIM2_ETRSOURCE_COMP2: TIM2_ETR is connected to COMP2 output - * @arg LL_TIM_TIM2_ETRSOURCE_LSE: TIM2_ETR is connected to LSE - * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSA: TIM2_ETR is connected to SAI1 FS_A - * @arg LL_TIM_TIM2_ETRSOURCE_SAI1_FSB: TIM2_ETR is connected to SAI1 FS_B - * - * For TIM3, the parameter is one of the following values: - * @arg LL_TIM_TIM3_ETRSOURCE_GPIO: TIM3_ETR is connected to GPIO - * @arg LL_TIM_TIM3_ETRSOURCE_COMP1: TIM3_ETR is connected to COMP1 output - * - * For TIM5, the parameter is one of the following values: - * @arg LL_TIM_TIM5_ETRSOURCE_GPIO: TIM5_ETR is connected to GPIO - * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSA: TIM5_ETR is connected to SAI2 FS_A (*) - * @arg LL_TIM_TIM5_ETRSOURCE_SAI2_FSB: TIM5_ETR is connected to SAI2 FS_B (*) - * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSA: TIM5_ETR is connected to SAI2 FS_A (*) - * @arg LL_TIM_TIM5_ETRSOURCE_SAI4_FSB: TIM5_ETR is connected to SAI2 FS_B (*) - * - * For TIM8, the parameter is one of the following values: - * @arg LL_TIM_TIM8_ETRSOURCE_GPIO: TIM8_ETR is connected to GPIO - * @arg LL_TIM_TIM8_ETRSOURCE_COMP1: TIM8_ETR is connected to COMP1 output - * @arg LL_TIM_TIM8_ETRSOURCE_COMP2: TIM8_ETR is connected to COMP2 output - * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD1: TIM8_ETR is connected to ADC2 AWD1 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD2: TIM8_ETR is connected to ADC2 AWD2 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC2_AWD3: TIM8_ETR is connected to ADC2 AWD3 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD1: TIM8_ETR is connected to ADC3 AWD1 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD2: TIM8_ETR is connected to ADC3 AWD2 - * @arg LL_TIM_TIM8_ETRSOURCE_ADC3_AWD3: TIM8_ETR is connected to ADC3 AWD3 - * - * For TIM23, the parameter is one of the following values: (*) - * @arg LL_TIM_TIM23_ETRSOURCE_GPIO TIM23_ETR is connected to GPIO - * @arg LL_TIM_TIM23_ETRSOURCE_COMP1 TIM23_ETR is connected to COMP1 output - * @arg LL_TIM_TIM23_ETRSOURCE_COMP2 TIM23_ETR is connected to COMP2 output - * - * For TIM24, the parameter is one of the following values: (*) - * @arg LL_TIM_TIM24_ETRSOURCE_GPIO TIM24_ETR is connected to GPIO - * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSA TIM24_ETR is connected to SAI4 FS_A - * @arg LL_TIM_TIM24_ETRSOURCE_SAI4_FSB TIM24_ETR is connected to SAI4 FS_B - * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSA TIM24_ETR is connected to SAI1 FS_A - * @arg LL_TIM_TIM24_ETRSOURCE_SAI1_FSB TIM24_ETR is connected to SAI1 FS_B - * - * (*) Value not defined in all devices. - * @retval None - */ -static inline void LL_TIM_SetETRSource(TIM_TypeDef *TIMx, uint32_t ETRSource) -{ - MODIFY_REG(TIMx->AF1, TIMx_AF1_ETRSEL, ETRSource); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Break_Function Break function configuration - * @{ - */ -/** - * @brief Enable the break function. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR BKE LL_TIM_EnableBRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableBRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BKE); -} - -/** - * @brief Disable the break function. - * @rmtoll BDTR BKE LL_TIM_DisableBRK - * @param TIMx Timer instance - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @retval None - */ -static inline void LL_TIM_DisableBRK(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BKE); -} - -#if defined(TIM_BDTR_BKBID) -/** - * @brief Configure the break input. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @note Bidirectional mode is only supported by advanced timer instances. - * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not - * a timer instance is an advanced-control timer. - * @note In bidirectional mode (BKBID bit set), the Break input is configured both - * in input mode and in open drain output mode. Any active Break event will - * assert a low logic level on the Break input to indicate an internal break - * event to external devices. - * @note When bidirectional mode isn't supported, BreakAFMode must be set to - * LL_TIM_BREAK_AFMODE_INPUT. - * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n - * BDTR BKF LL_TIM_ConfigBRK\n - * BDTR BKBID LL_TIM_ConfigBRK - * @param TIMx Timer instance - * @param BreakPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_POLARITY_LOW - * @arg @ref LL_TIM_BREAK_POLARITY_HIGH - * @param BreakFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 - * @param BreakAFMode This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_AFMODE_INPUT - * @arg @ref LL_TIM_BREAK_AFMODE_BIDIRECTIONAL - * @retval None - */ -static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, uint32_t BreakFilter, - uint32_t BreakAFMode) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF | TIM_BDTR_BKBID, BreakPolarity | BreakFilter | BreakAFMode); -} - -#else -/** - * @brief Configure the break input. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR BKP LL_TIM_ConfigBRK\n - * BDTR BKF LL_TIM_ConfigBRK - * @param TIMx Timer instance - * @param BreakPolarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_POLARITY_LOW - * @arg @ref LL_TIM_BREAK_POLARITY_HIGH - * @param BreakFilter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_ConfigBRK(TIM_TypeDef *TIMx, uint32_t BreakPolarity, - uint32_t BreakFilter) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BKP | TIM_BDTR_BKF, BreakPolarity | BreakFilter); -} - -#endif /* TIM_BDTR_BKBID */ -#if defined(TIM_BDTR_BKBID) -/** - * @brief Disarm the break input (when it operates in bidirectional mode). - * @note The break input can be disarmed only when it is configured in - * bidirectional mode and when when MOE is reset. - * @note Purpose is to be able to have the input voltage back to high-state, - * whatever the time constant on the output . - * @rmtoll BDTR BKDSRM LL_TIM_DisarmBRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisarmBRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BKDSRM); -} - -#endif /*TIM_BDTR_BKBID */ -/** - * @brief Enable the break 2 function. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @rmtoll BDTR BK2E LL_TIM_EnableBRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableBRK2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BK2E); -} - -/** - * @brief Disable the break 2 function. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @rmtoll BDTR BK2E LL_TIM_DisableBRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableBRK2(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_BK2E); -} - -#if defined(TIM_BDTR_BKBID) -/** - * @brief Configure the break 2 input. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @note Bidirectional mode is only supported by advanced timer instances. - * Macro IS_TIM_ADVANCED_INSTANCE(TIMx) can be used to check whether or not - * a timer instance is an advanced-control timer. - * @note In bidirectional mode (BK2BID bit set), the Break 2 input is configured both - * in input mode and in open drain output mode. Any active Break event will - * assert a low logic level on the Break 2 input to indicate an internal break - * event to external devices. - * @note When bidirectional mode isn't supported, Break2AFMode must be set to - * LL_TIM_BREAK2_AFMODE_INPUT. - * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n - * BDTR BK2F LL_TIM_ConfigBRK2\n - * BDTR BK2BID LL_TIM_ConfigBRK2 - * @param TIMx Timer instance - * @param Break2Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_POLARITY_LOW - * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH - * @param Break2Filter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 - * @param Break2AFMode This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_AFMODE_INPUT - * @arg @ref LL_TIM_BREAK2_AFMODE_BIDIRECTIONAL - * @retval None - */ -static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter, - uint32_t Break2AFMode) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F | TIM_BDTR_BK2BID, Break2Polarity | Break2Filter | Break2AFMode); -} - -#else -/** - * @brief Configure the break 2 input. - * @note Macro IS_TIM_BKIN2_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a second break input. - * @rmtoll BDTR BK2P LL_TIM_ConfigBRK2\n - * BDTR BK2F LL_TIM_ConfigBRK2 - * @param TIMx Timer instance - * @param Break2Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_POLARITY_LOW - * @arg @ref LL_TIM_BREAK2_POLARITY_HIGH - * @param Break2Filter This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N2 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N4 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV1_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV2_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV4_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV8_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV16_N8 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N5 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N6 - * @arg @ref LL_TIM_BREAK2_FILTER_FDIV32_N8 - * @retval None - */ -static inline void LL_TIM_ConfigBRK2(TIM_TypeDef *TIMx, uint32_t Break2Polarity, uint32_t Break2Filter) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_BK2P | TIM_BDTR_BK2F, Break2Polarity | Break2Filter); -} - -#endif /*TIM_BDTR_BKBID */ -#if defined(TIM_BDTR_BKBID) -/** - * @brief Disarm the break 2 input (when it operates in bidirectional mode). - * @note The break 2 input can be disarmed only when it is configured in - * bidirectional mode and when when MOE is reset. - * @note Purpose is to be able to have the input voltage back to high-state, - * whatever the time constant on the output. - * @rmtoll BDTR BK2DSRM LL_TIM_DisarmBRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisarmBRK2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_BK2DSRM); -} - -#endif /*TIM_BDTR_BKBID */ -/** - * @brief Select the outputs off state (enabled v.s. disabled) in Idle and Run modes. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR OSSI LL_TIM_SetOffStates\n - * BDTR OSSR LL_TIM_SetOffStates - * @param TIMx Timer instance - * @param OffStateIdle This parameter can be one of the following values: - * @arg @ref LL_TIM_OSSI_DISABLE - * @arg @ref LL_TIM_OSSI_ENABLE - * @param OffStateRun This parameter can be one of the following values: - * @arg @ref LL_TIM_OSSR_DISABLE - * @arg @ref LL_TIM_OSSR_ENABLE - * @retval None - */ -static inline void LL_TIM_SetOffStates(TIM_TypeDef *TIMx, uint32_t OffStateIdle, uint32_t OffStateRun) -{ - MODIFY_REG(TIMx->BDTR, TIM_BDTR_OSSI | TIM_BDTR_OSSR, OffStateIdle | OffStateRun); -} - -/** - * @brief Enable automatic output (MOE can be set by software or automatically when a break input is active). - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR AOE LL_TIM_EnableAutomaticOutput - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableAutomaticOutput(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_AOE); -} - -/** - * @brief Disable automatic output (MOE can be set only by software). - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR AOE LL_TIM_DisableAutomaticOutput - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableAutomaticOutput(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_AOE); -} - -/** - * @brief Indicate whether automatic output is enabled. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR AOE LL_TIM_IsEnabledAutomaticOutput - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledAutomaticOutput(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->BDTR, TIM_BDTR_AOE) == (TIM_BDTR_AOE)) ? 1UL : 0UL); -} - -/** - * @brief Enable the outputs (set the MOE bit in TIMx_BDTR register). - * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by - * software and is reset in case of break or break2 event - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR MOE LL_TIM_EnableAllOutputs - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableAllOutputs(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->BDTR, TIM_BDTR_MOE); -} - -/** - * @brief Disable the outputs (reset the MOE bit in TIMx_BDTR register). - * @note The MOE bit in TIMx_BDTR register allows to enable /disable the outputs by - * software and is reset in case of break or break2 event. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR MOE LL_TIM_DisableAllOutputs - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableAllOutputs(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->BDTR, TIM_BDTR_MOE); -} - -/** - * @brief Indicates whether outputs are enabled. - * @note Macro IS_TIM_BREAK_INSTANCE(TIMx) can be used to check whether or not - * a timer instance provides a break input. - * @rmtoll BDTR MOE LL_TIM_IsEnabledAllOutputs - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledAllOutputs(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->BDTR, TIM_BDTR_MOE) == (TIM_BDTR_MOE)) ? 1UL : 0UL); -} - -#if defined(TIM_BREAK_INPUT_SUPPORT) -/** - * @brief Enable the signals connected to the designated timer break input. - * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether - * or not a timer instance allows for break input selection. - * @rmtoll AF1 BKINE LL_TIM_EnableBreakInputSource\n - * AF1 BKCMP1E LL_TIM_EnableBreakInputSource\n - * AF1 BKCMP2E LL_TIM_EnableBreakInputSource\n - * AF1 BKDF1BK0E LL_TIM_EnableBreakInputSource\n - * AF2 BK2INE LL_TIM_EnableBreakInputSource\n - * AF2 BK2CMP1E LL_TIM_EnableBreakInputSource\n - * AF2 BK2CMP2E LL_TIM_EnableBreakInputSource\n - * AF2 BK2DF1BK1E LL_TIM_EnableBreakInputSource - * @param TIMx Timer instance - * @param BreakInput This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_INPUT_BKIN - * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 - * @param Source This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_SOURCE_BKIN - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 - * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK - * @retval None - */ -static inline void LL_TIM_EnableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) -{ - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); - SET_BIT(*pReg, Source); -} - -/** - * @brief Disable the signals connected to the designated timer break input. - * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether - * or not a timer instance allows for break input selection. - * @rmtoll AF1 BKINE LL_TIM_DisableBreakInputSource\n - * AF1 BKCMP1E LL_TIM_DisableBreakInputSource\n - * AF1 BKCMP2E LL_TIM_DisableBreakInputSource\n - * AF1 BKDF1BK0E LL_TIM_DisableBreakInputSource\n - * AF2 BK2INE LL_TIM_DisableBreakInputSource\n - * AF2 BK2CMP1E LL_TIM_DisableBreakInputSource\n - * AF2 BK2CMP2E LL_TIM_DisableBreakInputSource\n - * AF2 BK2DF1BK1E LL_TIM_DisableBreakInputSource - * @param TIMx Timer instance - * @param BreakInput This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_INPUT_BKIN - * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 - * @param Source This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_SOURCE_BKIN - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 - * @arg @ref LL_TIM_BKIN_SOURCE_DF1BK - * @retval None - */ -static inline void LL_TIM_DisableBreakInputSource(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source) -{ - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); - CLEAR_BIT(*pReg, Source); -} - -/** - * @brief Set the polarity of the break signal for the timer break input. - * @note Macro IS_TIM_BREAKSOURCE_INSTANCE(TIMx) can be used to check whether - * or not a timer instance allows for break input selection. - * @rmtoll AF1 BKINP LL_TIM_SetBreakInputSourcePolarity\n - * AF1 BKCMP1P LL_TIM_SetBreakInputSourcePolarity\n - * AF1 BKCMP2P LL_TIM_SetBreakInputSourcePolarity\n - * AF2 BK2INP LL_TIM_SetBreakInputSourcePolarity\n - * AF2 BK2CMP1P LL_TIM_SetBreakInputSourcePolarity\n - * AF2 BK2CMP2P LL_TIM_SetBreakInputSourcePolarity - * @param TIMx Timer instance - * @param BreakInput This parameter can be one of the following values: - * @arg @ref LL_TIM_BREAK_INPUT_BKIN - * @arg @ref LL_TIM_BREAK_INPUT_BKIN2 - * @param Source This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_SOURCE_BKIN - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP1 - * @arg @ref LL_TIM_BKIN_SOURCE_BKCOMP2 - * @param Polarity This parameter can be one of the following values: - * @arg @ref LL_TIM_BKIN_POLARITY_LOW - * @arg @ref LL_TIM_BKIN_POLARITY_HIGH - * @retval None - */ -static inline void LL_TIM_SetBreakInputSourcePolarity(TIM_TypeDef *TIMx, uint32_t BreakInput, uint32_t Source, - uint32_t Polarity) -{ - __IO uint32_t *pReg = (__IO uint32_t *)((uintptr_t)((uintptr_t)(&TIMx->AF1) + BreakInput)); - MODIFY_REG(*pReg, (TIMx_AF1_BKINP << TIM_POSITION_BRK_SOURCE), (Polarity << TIM_POSITION_BRK_SOURCE)); -} -#endif /* TIM_BREAK_INPUT_SUPPORT */ -/** - * @} - */ - -/** @defgroup TIM_LL_EF_DMA_Burst_Mode DMA burst mode configuration - * @{ - */ -/** - * @brief Configures the timer DMA burst feature. - * @note Macro IS_TIM_DMABURST_INSTANCE(TIMx) can be used to check whether or - * not a timer instance supports the DMA burst mode. - * @rmtoll DCR DBL LL_TIM_ConfigDMABurst\n - * DCR DBA LL_TIM_ConfigDMABurst - * @param TIMx Timer instance - * @param DMABurstBaseAddress This parameter can be one of the following values: - * @arg @ref LL_TIM_DMABURST_BASEADDR_CR1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CR2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_SMCR - * @arg @ref LL_TIM_DMABURST_BASEADDR_DIER - * @arg @ref LL_TIM_DMABURST_BASEADDR_SR - * @arg @ref LL_TIM_DMABURST_BASEADDR_EGR - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCER - * @arg @ref LL_TIM_DMABURST_BASEADDR_CNT - * @arg @ref LL_TIM_DMABURST_BASEADDR_PSC - * @arg @ref LL_TIM_DMABURST_BASEADDR_ARR - * @arg @ref LL_TIM_DMABURST_BASEADDR_RCR - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR3 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR4 - * @arg @ref LL_TIM_DMABURST_BASEADDR_BDTR - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCMR3 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR5 - * @arg @ref LL_TIM_DMABURST_BASEADDR_CCR6 - * @arg @ref LL_TIM_DMABURST_BASEADDR_AF1 - * @arg @ref LL_TIM_DMABURST_BASEADDR_AF2 - * @arg @ref LL_TIM_DMABURST_BASEADDR_TISEL - * - * @param DMABurstLength This parameter can be one of the following values: - * @arg @ref LL_TIM_DMABURST_LENGTH_1TRANSFER - * @arg @ref LL_TIM_DMABURST_LENGTH_2TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_3TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_4TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_5TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_6TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_7TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_8TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_9TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_10TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_11TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_12TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_13TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_14TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_15TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_16TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_17TRANSFERS - * @arg @ref LL_TIM_DMABURST_LENGTH_18TRANSFERS - * @retval None - */ -static inline void LL_TIM_ConfigDMABurst(TIM_TypeDef *TIMx, uint32_t DMABurstBaseAddress, uint32_t DMABurstLength) -{ - MODIFY_REG(TIMx->DCR, (TIM_DCR_DBL | TIM_DCR_DBA), (DMABurstBaseAddress | DMABurstLength)); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_Timer_Inputs_Remapping Timer input remapping - * @{ - */ -/** - * @brief Remap TIM inputs (input channel, internal/external triggers). - * @note Macro IS_TIM_REMAP_INSTANCE(TIMx) can be used to check whether or not - * a some timer inputs can be remapped. - * TIM1: one of the following values: - * @arg LL_TIM_TIM1_TI1_RMP_GPIO: TIM1 TI1 is connected to GPIO - * @arg LL_TIM_TIM1_TI1_RMP_COMP1: TIM1 TI1 is connected to COMP1 output - * - * TIM2: one of the following values: - * @arg LL_TIM_TIM2_TI4_RMP_GPIO: TIM2 TI4 is connected to GPIO - * @arg LL_TIM_TIM2_TI4_RMP_COMP1: TIM2 TI4 is connected to COMP1 output - * @arg LL_TIM_TIM2_TI4_RMP_COMP2: TIM2 TI4 is connected to COMP2 output - * @arg LL_TIM_TIM2_TI4_RMP_COMP1_COMP2: TIM2 TI4 is connected to logical OR between COMP1 and COMP2 output - * - * TIM3: one of the following values: - * @arg LL_TIM_TIM3_TI1_RMP_GPIO: TIM3 TI1 is connected to GPIO - * @arg LL_TIM_TIM3_TI1_RMP_COMP1: TIM3 TI1 is connected to COMP1 output - * @arg LL_TIM_TIM3_TI1_RMP_COMP2: TIM3 TI1 is connected to COMP2 output - * @arg LL_TIM_TIM3_TI1_RMP_COMP1_COMP2: TIM3 TI1 is connected to logical OR between COMP1 and COMP2 output - * - * TIM5: one of the following values: - * @arg LL_TIM_TIM5_TI1_RMP_GPIO: TIM5 TI1 is connected to GPIO - * @arg LL_TIM_TIM5_TI1_RMP_CAN_TMP: TIM5 TI1 is connected to CAN TMP - * @arg LL_TIM_TIM5_TI1_RMP_CAN_RTP: TIM5 TI1 is connected to CAN RTP - * - * TIM8: one of the following values: - * @arg LL_TIM_TIM8_TI1_RMP_GPIO: TIM8 TI1 is connected to GPIO - * @arg LL_TIM_TIM8_TI1_RMP_COMP2: TIM8 TI1 is connected to COMP2 output - * - * TIM12: one of the following values: (*) - * @arg LL_TIM_TIM12_TI1_RMP_GPIO: TIM12 TI1 is connected to GPIO - * @arg LL_TIM_TIM12_TI1_RMP_SPDIF_FS: TIM12 TI1 is connected to SPDIF FS - * - * TIM15: one of the following values: - * @arg LL_TIM_TIM15_TI1_RMP_GPIO: TIM15 TI1 is connected to GPIO - * @arg LL_TIM_TIM15_TI1_RMP_TIM2: TIM15 TI1 is connected to TIM2 CH1 - * @arg LL_TIM_TIM15_TI1_RMP_TIM3: TIM15 TI1 is connected to TIM3 CH1 - * @arg LL_TIM_TIM15_TI1_RMP_TIM4: TIM15 TI1 is connected to TIM4 CH1 - * @arg LL_TIM_TIM15_TI1_RMP_LSE: TIM15 TI1 is connected to LSE - * @arg LL_TIM_TIM15_TI1_RMP_CSI: TIM15 TI1 is connected to CSI - * @arg LL_TIM_TIM15_TI1_RMP_MCO2: TIM15 TI1 is connected to MCO2 - * @arg LL_TIM_TIM15_TI2_RMP_GPIO: TIM15 TI2 is connected to GPIO - * @arg LL_TIM_TIM15_TI2_RMP_TIM2: TIM15 TI2 is connected to TIM2 CH2 - * @arg LL_TIM_TIM15_TI2_RMP_TIM3: TIM15 TI2 is connected to TIM3 CH2 - * @arg LL_TIM_TIM15_TI2_RMP_TIM4: TIM15 TI2 is connected to TIM4 CH2 - * - * TIM16: one of the following values: - * @arg LL_TIM_TIM16_TI1_RMP_GPIO: TIM16 TI1 is connected to GPIO - * @arg LL_TIM_TIM16_TI1_RMP_LSI: TIM16 TI1 is connected to LSI - * @arg LL_TIM_TIM16_TI1_RMP_LSE: TIM16 TI1 is connected to LSE - * @arg LL_TIM_TIM16_TI1_RMP_RTC: TIM16 TI1 is connected to RTC wakeup interrupt - * - * TIM17: one of the following values: - * @arg LL_TIM_TIM17_TI1_RMP_GPIO: TIM17 TI1 is connected to GPIO - * @arg LL_TIM_TIM17_TI1_RMP_SPDIF_FS: TIM17 TI1 is connected to SPDIF FS (*) - * @arg LL_TIM_TIM17_TI1_RMP_HSE_1MHZ: TIM17 TI1 is connected to HSE 1MHz - * @arg LL_TIM_TIM17_TI1_RMP_MCO1: TIM17 TI1 is connected to MCO1 - * - * TIM23: one of the following values: (*) - * @arg LL_TIM_TIM23_TI4_RMP_GPIO TIM23_TI4 is connected to GPIO - * @arg LL_TIM_TIM23_TI4_RMP_COMP1 TIM23_TI4 is connected to COMP1 output - * @arg LL_TIM_TIM23_TI4_RMP_COMP2 TIM23_TI4 is connected to COMP2 output - * @arg LL_TIM_TIM23_TI4_RMP_COMP1_COMP2 TIM23_TI4 is connected to COMP2 output - * - * TIM24: one of the following values: (*) - * @arg LL_TIM_TIM24_TI1_RMP_GPIO TIM24_TI1 is connected to GPIO - * @arg LL_TIM_TIM24_TI1_RMP_CAN_TMP TIM24_TI1 is connected to CAN_TMP - * @arg LL_TIM_TIM24_TI1_RMP_CAN_RTP TIM24_TI1 is connected to CAN_RTP - * @arg LL_TIM_TIM24_TI1_RMP_CAN_SOC TIM24_TI1 is connected to CAN_SOC - * - * (*) Value not defined in all devices. \n - * @retval None - */ -static inline void LL_TIM_SetRemap(TIM_TypeDef *TIMx, uint32_t Remap) -{ - MODIFY_REG(TIMx->TISEL, (TIM_TISEL_TI1SEL | TIM_TISEL_TI2SEL | TIM_TISEL_TI3SEL | TIM_TISEL_TI4SEL), Remap); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_FLAG_Management FLAG-Management - * @{ - */ -/** - * @brief Clear the update interrupt flag (UIF). - * @rmtoll SR UIF LL_TIM_ClearFlag_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_UPDATE(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_UIF)); -} - -/** - * @brief Indicate whether update interrupt flag (UIF) is set (update interrupt is pending). - * @rmtoll SR UIF LL_TIM_IsActiveFlag_UPDATE - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_UPDATE(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_UIF) == (TIM_SR_UIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 1 interrupt flag (CC1F). - * @rmtoll SR CC1IF LL_TIM_ClearFlag_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC1(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC1IF)); -} - -/** - * @brief Indicate whether Capture/Compare 1 interrupt flag (CC1F) is set (Capture/Compare 1 interrupt is pending). - * @rmtoll SR CC1IF LL_TIM_IsActiveFlag_CC1 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC1(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC1IF) == (TIM_SR_CC1IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 2 interrupt flag (CC2F). - * @rmtoll SR CC2IF LL_TIM_ClearFlag_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC2(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC2IF)); -} - -/** - * @brief Indicate whether Capture/Compare 2 interrupt flag (CC2F) is set (Capture/Compare 2 interrupt is pending). - * @rmtoll SR CC2IF LL_TIM_IsActiveFlag_CC2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC2IF) == (TIM_SR_CC2IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 3 interrupt flag (CC3F). - * @rmtoll SR CC3IF LL_TIM_ClearFlag_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC3(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC3IF)); -} - -/** - * @brief Indicate whether Capture/Compare 3 interrupt flag (CC3F) is set (Capture/Compare 3 interrupt is pending). - * @rmtoll SR CC3IF LL_TIM_IsActiveFlag_CC3 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC3(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC3IF) == (TIM_SR_CC3IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 4 interrupt flag (CC4F). - * @rmtoll SR CC4IF LL_TIM_ClearFlag_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC4(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC4IF)); -} - -/** - * @brief Indicate whether Capture/Compare 4 interrupt flag (CC4F) is set (Capture/Compare 4 interrupt is pending). - * @rmtoll SR CC4IF LL_TIM_IsActiveFlag_CC4 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC4(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC4IF) == (TIM_SR_CC4IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 5 interrupt flag (CC5F). - * @rmtoll SR CC5IF LL_TIM_ClearFlag_CC5 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC5(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC5IF)); -} - -/** - * @brief Indicate whether Capture/Compare 5 interrupt flag (CC5F) is set (Capture/Compare 5 interrupt is pending). - * @rmtoll SR CC5IF LL_TIM_IsActiveFlag_CC5 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC5(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC5IF) == (TIM_SR_CC5IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 6 interrupt flag (CC6F). - * @rmtoll SR CC6IF LL_TIM_ClearFlag_CC6 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC6(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC6IF)); -} - -/** - * @brief Indicate whether Capture/Compare 6 interrupt flag (CC6F) is set (Capture/Compare 6 interrupt is pending). - * @rmtoll SR CC6IF LL_TIM_IsActiveFlag_CC6 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC6(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC6IF) == (TIM_SR_CC6IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the commutation interrupt flag (COMIF). - * @rmtoll SR COMIF LL_TIM_ClearFlag_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_COM(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_COMIF)); -} - -/** - * @brief Indicate whether commutation interrupt flag (COMIF) is set (commutation interrupt is pending). - * @rmtoll SR COMIF LL_TIM_IsActiveFlag_COM - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_COM(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_COMIF) == (TIM_SR_COMIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the trigger interrupt flag (TIF). - * @rmtoll SR TIF LL_TIM_ClearFlag_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_TRIG(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_TIF)); -} - -/** - * @brief Indicate whether trigger interrupt flag (TIF) is set (trigger interrupt is pending). - * @rmtoll SR TIF LL_TIM_IsActiveFlag_TRIG - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_TRIG(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_TIF) == (TIM_SR_TIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the break interrupt flag (BIF). - * @rmtoll SR BIF LL_TIM_ClearFlag_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_BRK(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_BIF)); -} - -/** - * @brief Indicate whether break interrupt flag (BIF) is set (break interrupt is pending). - * @rmtoll SR BIF LL_TIM_IsActiveFlag_BRK - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_BRK(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_BIF) == (TIM_SR_BIF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the break 2 interrupt flag (B2IF). - * @rmtoll SR B2IF LL_TIM_ClearFlag_BRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_BRK2(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_B2IF)); -} - -/** - * @brief Indicate whether break 2 interrupt flag (B2IF) is set (break 2 interrupt is pending). - * @rmtoll SR B2IF LL_TIM_IsActiveFlag_BRK2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_BRK2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_B2IF) == (TIM_SR_B2IF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 1 over-capture interrupt flag (CC1OF). - * @rmtoll SR CC1OF LL_TIM_ClearFlag_CC1OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC1OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC1OF)); -} - -/** - * @brief Indicate whether Capture/Compare 1 over-capture interrupt flag (CC1OF) is set - * (Capture/Compare 1 interrupt is pending). - * @rmtoll SR CC1OF LL_TIM_IsActiveFlag_CC1OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC1OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC1OF) == (TIM_SR_CC1OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 2 over-capture interrupt flag (CC2OF). - * @rmtoll SR CC2OF LL_TIM_ClearFlag_CC2OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC2OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC2OF)); -} - -/** - * @brief Indicate whether Capture/Compare 2 over-capture interrupt flag (CC2OF) is set - * (Capture/Compare 2 over-capture interrupt is pending). - * @rmtoll SR CC2OF LL_TIM_IsActiveFlag_CC2OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC2OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC2OF) == (TIM_SR_CC2OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 3 over-capture interrupt flag (CC3OF). - * @rmtoll SR CC3OF LL_TIM_ClearFlag_CC3OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC3OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC3OF)); -} - -/** - * @brief Indicate whether Capture/Compare 3 over-capture interrupt flag (CC3OF) is set - * (Capture/Compare 3 over-capture interrupt is pending). - * @rmtoll SR CC3OF LL_TIM_IsActiveFlag_CC3OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC3OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC3OF) == (TIM_SR_CC3OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the Capture/Compare 4 over-capture interrupt flag (CC4OF). - * @rmtoll SR CC4OF LL_TIM_ClearFlag_CC4OVR - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_CC4OVR(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_CC4OF)); -} - -/** - * @brief Indicate whether Capture/Compare 4 over-capture interrupt flag (CC4OF) is set - * (Capture/Compare 4 over-capture interrupt is pending). - * @rmtoll SR CC4OF LL_TIM_IsActiveFlag_CC4OVR - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_CC4OVR(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_CC4OF) == (TIM_SR_CC4OF)) ? 1UL : 0UL); -} - -/** - * @brief Clear the system break interrupt flag (SBIF). - * @rmtoll SR SBIF LL_TIM_ClearFlag_SYSBRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_ClearFlag_SYSBRK(TIM_TypeDef *TIMx) -{ - WRITE_REG(TIMx->SR, ~(TIM_SR_SBIF)); -} - -/** - * @brief Indicate whether system break interrupt flag (SBIF) is set (system break interrupt is pending). - * @rmtoll SR SBIF LL_TIM_IsActiveFlag_SYSBRK - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsActiveFlag_SYSBRK(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->SR, TIM_SR_SBIF) == (TIM_SR_SBIF)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_IT_Management IT-Management - * @{ - */ -/** - * @brief Enable update interrupt (UIE). - * @rmtoll DIER UIE LL_TIM_EnableIT_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_UPDATE(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_UIE); -} - -/** - * @brief Disable update interrupt (UIE). - * @rmtoll DIER UIE LL_TIM_DisableIT_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_UPDATE(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_UIE); -} - -/** - * @brief Indicates whether the update interrupt (UIE) is enabled. - * @rmtoll DIER UIE LL_TIM_IsEnabledIT_UPDATE - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_UPDATE(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_UIE) == (TIM_DIER_UIE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 1 interrupt (CC1IE). - * @rmtoll DIER CC1IE LL_TIM_EnableIT_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC1(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC1IE); -} - -/** - * @brief Disable capture/compare 1 interrupt (CC1IE). - * @rmtoll DIER CC1IE LL_TIM_DisableIT_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC1(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1IE); -} - -/** - * @brief Indicates whether the capture/compare 1 interrupt (CC1IE) is enabled. - * @rmtoll DIER CC1IE LL_TIM_IsEnabledIT_CC1 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC1(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1IE) == (TIM_DIER_CC1IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 2 interrupt (CC2IE). - * @rmtoll DIER CC2IE LL_TIM_EnableIT_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC2IE); -} - -/** - * @brief Disable capture/compare 2 interrupt (CC2IE). - * @rmtoll DIER CC2IE LL_TIM_DisableIT_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC2(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2IE); -} - -/** - * @brief Indicates whether the capture/compare 2 interrupt (CC2IE) is enabled. - * @rmtoll DIER CC2IE LL_TIM_IsEnabledIT_CC2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2IE) == (TIM_DIER_CC2IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 3 interrupt (CC3IE). - * @rmtoll DIER CC3IE LL_TIM_EnableIT_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC3(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC3IE); -} - -/** - * @brief Disable capture/compare 3 interrupt (CC3IE). - * @rmtoll DIER CC3IE LL_TIM_DisableIT_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC3(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3IE); -} - -/** - * @brief Indicates whether the capture/compare 3 interrupt (CC3IE) is enabled. - * @rmtoll DIER CC3IE LL_TIM_IsEnabledIT_CC3 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC3(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3IE) == (TIM_DIER_CC3IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 4 interrupt (CC4IE). - * @rmtoll DIER CC4IE LL_TIM_EnableIT_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_CC4(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC4IE); -} - -/** - * @brief Disable capture/compare 4 interrupt (CC4IE). - * @rmtoll DIER CC4IE LL_TIM_DisableIT_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_CC4(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4IE); -} - -/** - * @brief Indicates whether the capture/compare 4 interrupt (CC4IE) is enabled. - * @rmtoll DIER CC4IE LL_TIM_IsEnabledIT_CC4 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_CC4(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4IE) == (TIM_DIER_CC4IE)) ? 1UL : 0UL); -} - -/** - * @brief Enable commutation interrupt (COMIE). - * @rmtoll DIER COMIE LL_TIM_EnableIT_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_COM(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_COMIE); -} - -/** - * @brief Disable commutation interrupt (COMIE). - * @rmtoll DIER COMIE LL_TIM_DisableIT_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_COM(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_COMIE); -} - -/** - * @brief Indicates whether the commutation interrupt (COMIE) is enabled. - * @rmtoll DIER COMIE LL_TIM_IsEnabledIT_COM - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_COM(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_COMIE) == (TIM_DIER_COMIE)) ? 1UL : 0UL); -} - -/** - * @brief Enable trigger interrupt (TIE). - * @rmtoll DIER TIE LL_TIM_EnableIT_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_TRIG(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_TIE); -} - -/** - * @brief Disable trigger interrupt (TIE). - * @rmtoll DIER TIE LL_TIM_DisableIT_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_TRIG(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_TIE); -} - -/** - * @brief Indicates whether the trigger interrupt (TIE) is enabled. - * @rmtoll DIER TIE LL_TIM_IsEnabledIT_TRIG - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_TRIG(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_TIE) == (TIM_DIER_TIE)) ? 1UL : 0UL); -} - -/** - * @brief Enable break interrupt (BIE). - * @rmtoll DIER BIE LL_TIM_EnableIT_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableIT_BRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_BIE); -} - -/** - * @brief Disable break interrupt (BIE). - * @rmtoll DIER BIE LL_TIM_DisableIT_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableIT_BRK(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_BIE); -} - -/** - * @brief Indicates whether the break interrupt (BIE) is enabled. - * @rmtoll DIER BIE LL_TIM_IsEnabledIT_BRK - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledIT_BRK(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_BIE) == (TIM_DIER_BIE)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_DMA_Management DMA Management - * @{ - */ -/** - * @brief Enable update DMA request (UDE). - * @rmtoll DIER UDE LL_TIM_EnableDMAReq_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_UPDATE(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_UDE); -} - -/** - * @brief Disable update DMA request (UDE). - * @rmtoll DIER UDE LL_TIM_DisableDMAReq_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_UPDATE(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_UDE); -} - -/** - * @brief Indicates whether the update DMA request (UDE) is enabled. - * @rmtoll DIER UDE LL_TIM_IsEnabledDMAReq_UPDATE - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_UPDATE(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_UDE) == (TIM_DIER_UDE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 1 DMA request (CC1DE). - * @rmtoll DIER CC1DE LL_TIM_EnableDMAReq_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC1(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC1DE); -} - -/** - * @brief Disable capture/compare 1 DMA request (CC1DE). - * @rmtoll DIER CC1DE LL_TIM_DisableDMAReq_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC1(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC1DE); -} - -/** - * @brief Indicates whether the capture/compare 1 DMA request (CC1DE) is enabled. - * @rmtoll DIER CC1DE LL_TIM_IsEnabledDMAReq_CC1 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC1(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC1DE) == (TIM_DIER_CC1DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 2 DMA request (CC2DE). - * @rmtoll DIER CC2DE LL_TIM_EnableDMAReq_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC2DE); -} - -/** - * @brief Disable capture/compare 2 DMA request (CC2DE). - * @rmtoll DIER CC2DE LL_TIM_DisableDMAReq_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC2(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC2DE); -} - -/** - * @brief Indicates whether the capture/compare 2 DMA request (CC2DE) is enabled. - * @rmtoll DIER CC2DE LL_TIM_IsEnabledDMAReq_CC2 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC2(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC2DE) == (TIM_DIER_CC2DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 3 DMA request (CC3DE). - * @rmtoll DIER CC3DE LL_TIM_EnableDMAReq_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC3(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC3DE); -} - -/** - * @brief Disable capture/compare 3 DMA request (CC3DE). - * @rmtoll DIER CC3DE LL_TIM_DisableDMAReq_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC3(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC3DE); -} - -/** - * @brief Indicates whether the capture/compare 3 DMA request (CC3DE) is enabled. - * @rmtoll DIER CC3DE LL_TIM_IsEnabledDMAReq_CC3 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC3(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC3DE) == (TIM_DIER_CC3DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable capture/compare 4 DMA request (CC4DE). - * @rmtoll DIER CC4DE LL_TIM_EnableDMAReq_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_CC4(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_CC4DE); -} - -/** - * @brief Disable capture/compare 4 DMA request (CC4DE). - * @rmtoll DIER CC4DE LL_TIM_DisableDMAReq_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_CC4(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_CC4DE); -} - -/** - * @brief Indicates whether the capture/compare 4 DMA request (CC4DE) is enabled. - * @rmtoll DIER CC4DE LL_TIM_IsEnabledDMAReq_CC4 - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_CC4(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_CC4DE) == (TIM_DIER_CC4DE)) ? 1UL : 0UL); -} - -/** - * @brief Enable commutation DMA request (COMDE). - * @rmtoll DIER COMDE LL_TIM_EnableDMAReq_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_COM(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_COMDE); -} - -/** - * @brief Disable commutation DMA request (COMDE). - * @rmtoll DIER COMDE LL_TIM_DisableDMAReq_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_COM(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_COMDE); -} - -/** - * @brief Indicates whether the commutation DMA request (COMDE) is enabled. - * @rmtoll DIER COMDE LL_TIM_IsEnabledDMAReq_COM - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_COM(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_COMDE) == (TIM_DIER_COMDE)) ? 1UL : 0UL); -} - -/** - * @brief Enable trigger interrupt (TDE). - * @rmtoll DIER TDE LL_TIM_EnableDMAReq_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_EnableDMAReq_TRIG(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->DIER, TIM_DIER_TDE); -} - -/** - * @brief Disable trigger interrupt (TDE). - * @rmtoll DIER TDE LL_TIM_DisableDMAReq_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_DisableDMAReq_TRIG(TIM_TypeDef *TIMx) -{ - CLEAR_BIT(TIMx->DIER, TIM_DIER_TDE); -} - -/** - * @brief Indicates whether the trigger interrupt (TDE) is enabled. - * @rmtoll DIER TDE LL_TIM_IsEnabledDMAReq_TRIG - * @param TIMx Timer instance - * @retval State of bit (1 or 0). - */ -static inline uint32_t LL_TIM_IsEnabledDMAReq_TRIG(const TIM_TypeDef *TIMx) -{ - return ((READ_BIT(TIMx->DIER, TIM_DIER_TDE) == (TIM_DIER_TDE)) ? 1UL : 0UL); -} - -/** - * @} - */ - -/** @defgroup TIM_LL_EF_EVENT_Management EVENT-Management - * @{ - */ -/** - * @brief Generate an update event. - * @rmtoll EGR UG LL_TIM_GenerateEvent_UPDATE - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_UPDATE(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_UG); -} - -/** - * @brief Generate Capture/Compare 1 event. - * @rmtoll EGR CC1G LL_TIM_GenerateEvent_CC1 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC1(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC1G); -} - -/** - * @brief Generate Capture/Compare 2 event. - * @rmtoll EGR CC2G LL_TIM_GenerateEvent_CC2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC2G); -} - -/** - * @brief Generate Capture/Compare 3 event. - * @rmtoll EGR CC3G LL_TIM_GenerateEvent_CC3 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC3(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC3G); -} - -/** - * @brief Generate Capture/Compare 4 event. - * @rmtoll EGR CC4G LL_TIM_GenerateEvent_CC4 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_CC4(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_CC4G); -} - -/** - * @brief Generate commutation event. - * @rmtoll EGR COMG LL_TIM_GenerateEvent_COM - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_COM(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_COMG); -} - -/** - * @brief Generate trigger event. - * @rmtoll EGR TG LL_TIM_GenerateEvent_TRIG - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_TRIG(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_TG); -} - -/** - * @brief Generate break event. - * @rmtoll EGR BG LL_TIM_GenerateEvent_BRK - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_BRK(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_BG); -} - -/** - * @brief Generate break 2 event. - * @rmtoll EGR B2G LL_TIM_GenerateEvent_BRK2 - * @param TIMx Timer instance - * @retval None - */ -static inline void LL_TIM_GenerateEvent_BRK2(TIM_TypeDef *TIMx) -{ - SET_BIT(TIMx->EGR, TIM_EGR_B2G); -} - -/** - * @} - */ - -#if defined(USE_FULL_LL_DRIVER) -/** @defgroup TIM_LL_EF_Init Initialisation and deinitialisation functions - * @{ - */ - -ErrorStatus LL_TIM_DeInit(const TIM_TypeDef *TIMx); -void LL_TIM_StructInit(LL_TIM_InitTypeDef *TIM_InitStruct); -ErrorStatus LL_TIM_Init(TIM_TypeDef *TIMx, const LL_TIM_InitTypeDef *TIM_InitStruct); -void LL_TIM_OC_StructInit(LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); -ErrorStatus LL_TIM_OC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_OC_InitTypeDef *TIM_OC_InitStruct); -void LL_TIM_IC_StructInit(LL_TIM_IC_InitTypeDef *TIM_ICInitStruct); -ErrorStatus LL_TIM_IC_Init(TIM_TypeDef *TIMx, uint32_t Channel, const LL_TIM_IC_InitTypeDef *TIM_IC_InitStruct); -void LL_TIM_ENCODER_StructInit(LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); -ErrorStatus LL_TIM_ENCODER_Init(TIM_TypeDef *TIMx, const LL_TIM_ENCODER_InitTypeDef *TIM_EncoderInitStruct); -void LL_TIM_HALLSENSOR_StructInit(LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); -ErrorStatus LL_TIM_HALLSENSOR_Init(TIM_TypeDef *TIMx, const LL_TIM_HALLSENSOR_InitTypeDef *TIM_HallSensorInitStruct); -void LL_TIM_BDTR_StructInit(LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); -ErrorStatus LL_TIM_BDTR_Init(TIM_TypeDef *TIMx, const LL_TIM_BDTR_InitTypeDef *TIM_BDTRInitStruct); -/** - * @} - */ -#endif /* USE_FULL_LL_DRIVER */ - -/** - * @} - */ - -/** - * @} - */ - -#endif /* TIM1 || TIM2 || TIM3 || TIM4 || TIM5 || TIM6 || TIM7 || TIM8 || TIM12 || TIM13 ||TIM14 || TIM15 || TIM16 || TIM17 || TIM23 || TIM24 */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32H7xx_LL_TIM_H */ diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 2132cfb78..c2b56e106 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -27,8 +27,7 @@ class TimerRegister : public RegisterBase { static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); -class TIM_TypeDef{ -public: +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/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index f363cee7f..6d5850340 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -2,6 +2,15 @@ #define STM32H723xx_WRAPPER_H #include + +#define STM32H723xx + +#if defined(__GNUC__) || defined(__GNUG__) +# define __STATIC_INLINE static inline +#else +# error :) +#endif + #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permissions */ #else @@ -12,8 +21,7 @@ #define __RBIT __RBIT__CMSIS #define TIM_TypeDef TIM_TypeDef__CMSIS -// don't do anything in "core_cm7.h" -#define __CORE_CM7_H_GENERIC +// only do __CORE_CM7_H_GENERIC in "core_cm7.h" #define __CORE_CM7_H_DEPENDANT #include "stm32h723xx.h" @@ -21,7 +29,6 @@ #undef TIM_TypeDef #undef RCC - extern RCC_TypeDef *RCC; #endif // STM32H723xx_WRAPPER_H From 25316b9acdb0998b3990721c6ae721602ec67cf4 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:34:30 +0100 Subject: [PATCH 216/281] fix ci/cd and add the other submodule to be automatically added --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb2cfe6e..57955f586 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ endif() if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include) execute_process( - COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx + COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx Drivers/STM32H7xx_HAL_Driver WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 ) endif() @@ -38,6 +38,11 @@ endif() if(NOT CMAKE_CROSSCOMPILING) message(STATUS "Compiling for simulator") add_subdirectory(Tests) +else() + execute_process( + COMMAND git submodule update --init --depth 1 Drivers/BSP/Components/lan8742 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7 + ) endif() # ============================ From be9b61ad560c40060616084ff912c49763803c14 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:36:44 +0100 Subject: [PATCH 217/281] fix: actually add stm32h7xx_ll_tim_wrapper.h --- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h new file mode 100644 index 000000000..6d82146f0 --- /dev/null +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -0,0 +1,17 @@ +#ifndef STM32H7xx_LL_TIM_WRAPPER_H +#define STM32H7xx_LL_TIM_WRAPPER_H + +#include + +#include "MockedDrivers/stm32h723xx_wrapper.h" + +#include "stm32h7xx.h" + +#include "MockedDrivers/mocked_ll_tim.hpp" +#define uint32_t size_t +#include "stm32h7xx_ll_tim.h" +#undef uint32_t + +#include "MockedDrivers/compiler_specific.hpp" + +#endif // STM32H7xx_LL_TIM_WRAPPER_H From 5b3eab5a77c10f8a6221b3fab6d6e75e10388d66 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:54:29 +0100 Subject: [PATCH 218/281] try to fix ci/cd warning --- Inc/MockedDrivers/common.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 76326dc42..83fb6f217 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -15,6 +15,7 @@ #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) +#if 0 #ifdef SET_BIT # undef SET_BIT #endif @@ -43,3 +44,4 @@ #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) +#endif From 23b07dd5d59fc5ecff8a28b11f8963c20d4bbdb5 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 15:58:03 +0100 Subject: [PATCH 219/281] try fix warnings again --- Inc/MockedDrivers/common.hpp | 2 -- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 83fb6f217..76326dc42 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -15,7 +15,6 @@ #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) -#if 0 #ifdef SET_BIT # undef SET_BIT #endif @@ -44,4 +43,3 @@ #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) -#endif diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index 6d82146f0..cf9b0d15e 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -12,6 +12,6 @@ #include "stm32h7xx_ll_tim.h" #undef uint32_t -#include "MockedDrivers/compiler_specific.hpp" +#include "MockedDrivers/common.hpp" #endif // STM32H7xx_LL_TIM_WRAPPER_H From b31872345a5ec09f7d64746862004411d3a7b6d1 Mon Sep 17 00:00:00 2001 From: victhor Date: Thu, 18 Dec 2025 16:20:55 +0100 Subject: [PATCH 220/281] fix: add ignore Woverflow to stm32h7xx_ll_tim --- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index cf9b0d15e..fc918244c 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -8,9 +8,16 @@ #include "stm32h7xx.h" #include "MockedDrivers/mocked_ll_tim.hpp" + +// -Woverflow does not do much in stm32h7xx_ll_tim.h +// the only places where it's used in are in WRITE_REG(reg, ~(bit)) +// where they should use CLEAR_BIT(reg, bit) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Woverflow" #define uint32_t size_t #include "stm32h7xx_ll_tim.h" #undef uint32_t +#pragma GCC diagnostic pop #include "MockedDrivers/common.hpp" From 9240c01227f9c1c4486a93991e2c0e9e87374e62 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 19 Dec 2025 11:27:37 +0100 Subject: [PATCH 221/281] fix: remove need to ignore Woverflow warnings --- Inc/MockedDrivers/common.hpp | 9 ++++++--- Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 6 ------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 76326dc42..def8838ec 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -28,18 +28,21 @@ # undef MODIFY_REG #endif +// this is needed because later I will do a #define uint32_t size_t +typedef uint32_t u32; + #define SET_BIT(REG, BIT) ((REG) |= (BIT)) -#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT))) +#define CLEAR_BIT(REG, BIT) ((REG) = static_cast(static_cast(REG) & ~static_cast(BIT))) #define READ_BIT(REG, BIT) ((REG) & (BIT)) #define CLEAR_REG(REG) ((REG) = (0x0)) -#define WRITE_REG(REG, VAL) ((REG) = static_cast(VAL)) +#define WRITE_REG(REG, VAL) ((REG) = static_cast(VAL)) #define READ_REG(REG) ((REG)) -#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(uint32_t)(CLEARMASK))) | (SETMASK))) +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(u32)(CLEARMASK))) | (SETMASK))) #define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index fc918244c..904f5bb5f 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -9,15 +9,9 @@ #include "MockedDrivers/mocked_ll_tim.hpp" -// -Woverflow does not do much in stm32h7xx_ll_tim.h -// the only places where it's used in are in WRITE_REG(reg, ~(bit)) -// where they should use CLEAR_BIT(reg, bit) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Woverflow" #define uint32_t size_t #include "stm32h7xx_ll_tim.h" #undef uint32_t -#pragma GCC diagnostic pop #include "MockedDrivers/common.hpp" From 96481c3b3228b01178def2df529407c780d15aa1 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 19 Dec 2025 14:40:31 +0100 Subject: [PATCH 222/281] fix: Remove tim_register_definitions.hpp We're already including them in stm32h723xx_wrapper --- Inc/MockedDrivers/mocked_ll_tim.hpp | 2 +- .../tim_register_definitions.hpp | 914 ------------------ 2 files changed, 1 insertion(+), 915 deletions(-) delete mode 100644 Inc/MockedDrivers/tim_register_definitions.hpp diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index c2b56e106..eb5a8b3bf 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,9 +1,9 @@ #pragma once #include #include "MockedDrivers/stm32h723xx_wrapper.h" +#include "stm32h7xx.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" -#include "MockedDrivers/tim_register_definitions.hpp" #include "MockedDrivers/Register.hpp" #include enum class TimReg { diff --git a/Inc/MockedDrivers/tim_register_definitions.hpp b/Inc/MockedDrivers/tim_register_definitions.hpp deleted file mode 100644 index 1788be399..000000000 --- a/Inc/MockedDrivers/tim_register_definitions.hpp +++ /dev/null @@ -1,914 +0,0 @@ -#pragma once -/******************************************************************************/ -/* */ -/* TIM */ -/* */ -/******************************************************************************/ -#define TIM_BREAK_INPUT_SUPPORT /*! Date: Sat, 27 Dec 2025 13:31:57 +0100 Subject: [PATCH 223/281] Initial TimerDomain commit, lots of work to do... --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 622 +++++++++++++++++++ 1 file changed, 622 insertions(+) create mode 100644 Inc/HALAL/Models/TimerDomain/TimerDomain.hpp diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp new file mode 100644 index 000000000..ba76d8c84 --- /dev/null +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -0,0 +1,622 @@ +/* + * New TimerPeripheral.hpp + * + * Created on: 3 dic. 2025 + * Author: victor + */ + +#pragma once + +#include "stm32h7xx_hal_tim.h" + +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; +extern TIM_HandleTypeDef htim3; +extern TIM_HandleTypeDef htim4; +extern TIM_HandleTypeDef htim6; +extern TIM_HandleTypeDef htim7; +extern TIM_HandleTypeDef htim8; +extern TIM_HandleTypeDef htim12; +extern TIM_HandleTypeDef htim13; +extern TIM_HandleTypeDef htim14; +extern TIM_HandleTypeDef htim15; +extern TIM_HandleTypeDef htim16; +extern TIM_HandleTypeDef htim17; +extern TIM_HandleTypeDef htim23; +extern TIM_HandleTypeDef htim24; + +/* Tim1 & Tim8 are advanced-control timers + * their ARR & prescaler are 16bit + * they have up to 6 independent channels for: + * - input capture (not channel 5 or 6) + * - output capture + * - PWM generation + * - One-pulse mode output + */ + +/* Timers {TIM2, TIM5, TIM23, TIM24} are the only 32-bit counter resolution timers, the rest are 16-bit */ +/* Timers 2, 3, 4, 5, 23, 24 are general-purpose timers + * Timers 12, 13, 14 are also general-purpose timers (but separate in the ref manual) + * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) + */ + +/* Tim6 & Tim7 are basic timers */ + +/* basic timer features: + - 16-bit ARR upcounter + - 16-bit PSC + - Synchronization circuit to trigger the DAC + - Interrupt/DMA generation on the update event +*/ + +/* advanced timer features: + - 16-bit ARR up/down counter + - 16-bit PSC + - Up to 6 independent channels for: + · Input capture (all channels but 5 and 6) + · Output compare + · PWM generation (Edge and Center aligned mode) + · One-pulse mode output + - Complementary outputs with programmable dead-time + - Synchronization circuit to control the timer with + external signals and to interconnect several timers together. + - Repetition counter to update the timer registers only after + a given number of cycles of the counter. + - 2 break inputs to put the timer’s output signals in a safe user selectable configuration. + - Interrupt/DMA generation on the following events: + · Update: counter overflow/underflow, counter initialization (by software or internal/external trigger) + · Trigger event (counter start, stop, initialization or count by internal/external trigger) + · Input capture + · Output compare + - Supports incremental (quadrature) encoder and Hall-sensor circuitry for positioning purposes + - Trigger input for external clock or cycle-by-cycle current management +*/ +class TimerDomain { + static constexpr std::array create_idxmap() { + std::array result{}; + + // invalid timers that don't exist + result[0] = -1; + result[9] = -1; result[10] = -1; result[11] = -1; + result[18] = -1; result[19] = -1; result[20] = -1; result[21] = -1; result[22] = -1; + + // general-purpose timers + result[2] = 0; result[3] = 1; result[4] = 2; + result[5] = 3; result[23] = 4; result[24] = 5; + + // more general-purpose timers + result[12] = 6; result[13] = 7; result[14] = 8; + + // more general-purpose timers + result[15] = 9; result[16] = 10; result[17] = 11; + + // basic timers + result[6] = 12; result[7] = 13; + + // advanced control timers + result[1] = 14; result[8] = 15; + + return result; + } + + static constexpr std::array idxmap = create_idxmap(); + + static const TIM_HandleTypeDef *hal_handles[16] = { + // general purpose timers + &htim2, &htim3, &htim4, &htim5, &htim23, &htim24, + &htim12, &htim13, &htim14, + &htim15, &htim16, &htim17, + + // basic timers + &htim6, &htim7, + + // advanced control timers + &htim1, &htim8 + }; + + static const TIM_TypeDef *cmsis_timers[16] = { + // general purpose timers + TIM2, TIM3, TIM4, TIM5, TIM23, TIM24, + TIM12, TIM13, TIM14, + TIM15, TIM16, TIM17, + + // basic timers + TIM6, TIM7, + + // advanced control timers + TIM1, TIM8 + }; + + static inline void rcc_enable_timer(TIM_TypeDef *tim) { + switch(tim) { + case TIM2: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM2EN); break; + case TIM3: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM3EN); break; + case TIM4: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM4EN); break; + case TIM5: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM5EN); break; + case TIM6: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM6EN); break; + case TIM7: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM7EN); break; + case TIM12: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM12EN); break; + case TIM13: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM13EN); break; + case TIM14: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM14EN); break; + + case TIM24: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM24EN); break; + case TIM23: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM23EN); break; + + case TIM17: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM17EN); break; + case TIM16: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM16EN); break; + case TIM15: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM15EN); break; + case TIM8: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM8EN); break; + case TIM1: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM1EN); break; + } + } + + static consteval bool check_timer(Config *cfg, const Entry req, uint16_t timer_idx, int reqidx) { + if(req.period == 0) { + ErrorInRequestN("Error: In request reqidx: period must be greater than 0 (>0)", reqidx); + return false; + } + + uint8_t reqint = static_cast(req.request); + if(!(reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24)) { + if(req.period > 0xFFFF) { + ErrorInRequestN("Error: In request reqidx: Timers other than {TIM2, TIM5, TIM23, TIM24} have a maximum period of 0xFFFF (they are uint16_t)", reqidx); + return false; + } + } + + if(!(reqint == 1 || reqint == 8 || + reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || + reqint == 3 || reqint == 4)) + { + if(req.counting_mode != CountingMode::UP) { + ErrorInRequestN("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting", reqidx); + return false; + } + } + + if(timer_idx == 12 || timer_idx == 13) { + // basic timers + cfg->kind = TimerDomain::Kind::Basic; + } else if(timer_idx == 14 || timer_idx == 15) { + // advanced timers + cfg->kind = TimerDomain::Kind::Advanced; + } else { + if(timer_idx >= 0 && timer_idx <= 5) { + // general purpose timers 1 + } else if(timer_idx >= 6 && timer_idx <= 8) { + // general purpose timers 2 + } else if(timer_idx >= 9 && timer_idx <= 11) { + // general purpose timers 3 + } else { + ErrorInRequestN("Unknown timer idx in reqidx", reqidx); + } + + cfg->kind = TimerDomain::Kind::GeneralPurpose; + } + } + + /* to show the error with an index */ + static consteval ErrorInRequestN(char *str, int n) + { + switch(n) { + case 0: compile_error(str); + case 1: compile_error(str); + case 2: compile_error(str); + case 3: compile_error(str); + case 4: compile_error(str); + case 5: compile_error(str); + case 6: compile_error(str); + case 7: compile_error(str); + case 8: compile_error(str); + case 9: compile_error(str); + case 10: compile_error(str); + case 11: compile_error(str); + case 12: compile_error(str); + case 13: compile_error(str); + case 14: compile_error(str); + case 15: compile_error(str); + } + } + + enum Kind : uint8_t { + Basic, + GeneralPurpose, + Advanced, + }; + +public: + enum CountingMode : uint8_t { + UP = 0, + DOWN = 1, + /* center-aligned = counter counts up and down alternatively */ + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting down */ + CENTER_ALIGNED_INTERRUPT_DOWN = 2, + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting up */ + CENTER_ALIGNED_INTERRUPT_UP = 3, + /* both up and down */ + CENTER_ALIGNED_INTERRUPT_BOTH = 4, + }; + + enum PWM_MODE : uint8_t { + NORMAL = 0, + PHASED = 1, + CENTER_ALIGNED = 2, + }; + + struct PWMData { + uint32_t channel; + PWM_MODE mode; + }; + + /* The number corresponds with the timer nº */ + enum TimerRequest : uint8_t { + Advanced1 = 1, + Advanced2 = 8, + + AnyGeneralPurpose = 0xFF, + GeneralPurpose1 = 2, + GeneralPurpose2 = 3, + GeneralPurpose3 = 4, + GeneralPurpose4 = 5, + GeneralPurpose5 = 23, + GeneralPurpose6 = 24, + + GeneralPurpose7 = 12, + GeneralPurpose8 = 13, + GeneralPurpose9 = 14, + + GeneralPurpose10 = 15, + GeneralPurpose11 = 16, + GeneralPurpose12 = 17, + + Basic1 = 6, + Basic2 = 7, + }; + + struct Entry { + string name; + TimerRequest request; + ST_LIB::GPIODomain::Pin *pin; + TimerDomain::CountingMode counting_mode; + uint16_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + + struct Device { + using domain = TimerDomain; + Entry e; + + consteval Device(string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, + ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, + uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, + uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) : + e(name, request, pin, counting_mode, prescaler, period, deadtime, polarity, negated_polarity) {} + + template + consteval void inscribe(Ctx &ctx) const { + ctx.template add(e); + } + }; + + // There are 16 timers + static constexpr std::size_t max_instances = 16; + + struct Config { + char name[8]; /* "Timerxx\0" */ + TimerDomain::Kind kind; + uint16_t timer_idx; + ST_LIB::GPIODomain::Pin *asociated_pin; + TimerDomain::CountingMode counting_mode; + uint32_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + + template + static consteval std::array build(span requests) { + array cfgs{}; + uint16_t cfg_idx = 0; + bool usedTimer[25] = {0}; + + if(requests.size() > max_instances) { + throw "too many Timer requests, there are only 16 timers"; + } + + int remaining_requests[max_instances] = {}; + std::size_t count_remaining_requests = requsts.size(); + for(int i = 0; i < requests.size(); i++) remaining_requests[i] = i; + + for(int i = 0; i < requests.size(); i++) { + if(requests[i].request != TimerRequest::AnyGeneralPurpose && + (requests[i].request < 1 || requests[i].request > 24 || + (requests[i].request > 17 && requests[i].request < 23))) + { + ErrorInRequestN("Invalid TimerRequest value for timer i", i); + } + } + + // First find any that have requested a specific timer + for(std::size_t i = 0; i < N; i++) { + uint8_t reqint = static_cast(requests[i].request); + if(reqint != static_cast(TimerRequest::AnyGeneralPurpose)) { + if(usedTimer[reqint]) { + ErrorInRequestN("Error: Timer already used. Error in request i", i); + } + + Config cfg; + if(requests[i].name[0] == '\0') { + // "Timer" + tostring(reqint) + cfg.name[0] = 'T'; + cfg.name[1] = 'i'; + cfg.name[2] = 'm'; + cfg.name[3] = 'e'; + cfg.name[4] = 'r'; + cfg.name[5] = (reqint/10) + '0'; + cfg.name[6] = (reqint%10) + '0'; + } else { + if(requests[i].name.length() >= sizeof(cfg.name)) { + ErrorInRequestN("Error: Timer name too large, max = 7 (sizeof cfg.name - 1). In request i", i); + } + for(int si = 0; si < requests[i].name.length(); si++) { + cfg.name[si] = requests[i].name[si]; + } + cfg.name[requests[i].name.length()] = '\0'; + } + cfg.timer_idx = TimerDomain.idxmap[reqint]; + cfg.prescaler = requests[i].prescaler; + cfg.period = requests[i].period; + cfg.deadtime = requests[i].deadtime; + cfg.polarity = requests[i].polarity; + cfg.negated_polarity = requests[i].negated_polarity; + + cfgs[cfg_idx++] = cfg; + + // unordered remove + count_remaining_requests--; + remaining_requests[i] = remaining_requests[count_remaining_requests]; + } + } + + // Now do AnyGeneralPurpose + for(int i = 0; i < count_remaining_requests; i++) { + const Entry &e = requests[remaining_requests[i]]; + if(e.request == AnyGeneralPurpose) { + // TODO: Find first general purpose timer that isn't used + } + } + + return cfgs; + } + + // Runtime object + struct Instance { + template friend struct TimerWrapper; + + inline void counter_enable() { + SET_BIT(tim->CR1, TIM_CR1_CEN); + } + inline void counter_disable() { + CLEAR_BIT(tim->CR1, TIM_CR1_CEN); + } + + inline void clear_update_interrupt_flag() { + CLEAR_BIT(tim->SR, TIM_SR_UIF); + } + + /* Enabled by default */ + inline void enable_update_interrupt() { + CLEAR_BIT(tim->CR1, TIM_CR1_UDIS); + } + inline void disable_update_interrupt() { + SET_BIT(tim->CR1, TIM_CR1_UDIS); + } + + /* interrupt gets called only once, counter needs to be reenabled */ + inline void set_one_pulse_mode() { + SET_BIT(tim->CR1, TIM_CR1_OPM); + } + inline void multi_interrupt() { + CLEAR_BIT(tim->CR1, TIM_CR1_OPM); + } + + inline TIM_HandleTypeDef *get_hal_handle() { + return hal_tim; + } + inline TIM_TypeDef *get_cmsis_handle() { + return tim; + } + + template + inline void configure(void (*callback)()) { + if constexpr (psc != 0) { + tim->PSC = psc; + } + this.callback = callback; + this.counter_enable(); + } + + // leftover from old TimerPeripheral, maybe this was useful? + inline uint32_t get_prescaler() { + return tim->PSC; + } + inline uint32_t get_period() { + return tim->ARR; + } + }; + + template + struct TimerWrapper { + TIM_TypeDef *tim; + TIM_HandleTypeDef *hal_tim; + char name[8]; + const TimerDomain::Kind kind; + uint16_t timer_idx; + void (*callback)(TimerDomain::Instance); + + // NOTE: Need counter_enable() here for configure(), kept counter_disable() for consistency + if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { + // advanced specific functions + } + + if constexpr (dev.e.request != TimerRequest::Basic1 && dev.e.request != TimerRequest::Basic2) { + // general purpose and advanced functions + } + + /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ + template + inline void set_mode(void) { + constexpr uint8_t reqint = static_cast(dev.e.request); + if constexpr (!(reqint == 1 || reqint == 8 || + reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || + reqint == 3 || reqint == 4)) + { + compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + return; + } + + if constexpr (mode == CounterMode::UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == CounterMode::DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } + } + }; + + 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 Config &e = cfgs[i]; + + 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; + handle->Init.Period = e.period; + handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + handle->Init.RepetitionCounter = 0; + + TIM_TypeDef *tim = &cmsis_timers[e.timer_idx]; + tim->PSC = e.prescaler; + tim->ARR = e.period; + + if constexpr (e.counting_mode == CounterMode::UP) { + CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (e.counting_mode == CounterMode::DOWN) { + SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } + + rcc_enable_timer(tim); + + // InputCapture stuff should be dome somewhere else.. + // PWM stuff should be done somewhere else.. + + instances[i] = Instance{ + .tim = &cmsis_timers[e.timer_idx], + .hal_tim = handle, + .name = {e.name[0], e.name[1], e.name[2], e.name[3], e.name[4], e.name[5], e.name[6], e.name[7]}, + .kind = e.kind, + .timer_idx = e.timer_idx, + }; + } + } + } + + // Leftover from last iteration of the design of NewTimerPeripheral, will cleanup soon +private: + enum TIM_CAPABILITIES { + Basic_Start = 0, + Basic_End = 1, + + General_Start = 2, + General_End = 13, + + Advanced_Start = 14, + Advanced_End = 15, + + Count_Cap = 16, + }; + + // This should use __builtin_ffs() - 1 to get the index of the next + static uint32_t free_bmp = 0xFFFF'FFFF; + + static void (*callbacks)()[16]; +}; + + +/* 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); + } +*/ \ No newline at end of file From 9191b05154127ba58186e23ca3ecea6ef48414b0 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 13:32:50 +0100 Subject: [PATCH 224/281] Change name to TimerDomain.hpp in comment --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ba76d8c84..ce0c7086d 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -1,5 +1,5 @@ /* - * New TimerPeripheral.hpp + * TimerDomain.hpp * * Created on: 3 dic. 2025 * Author: victor From 703364fbbe300000b5801fbcfd79fb35efa9ddce Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:12:55 +0100 Subject: [PATCH 225/281] feat: Implement getting AnyGeneralPurpose timer with priorities --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 112 +++++++++++++------ 1 file changed, 77 insertions(+), 35 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ce0c7086d..d18bb05ca 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -9,6 +9,9 @@ #include "stm32h7xx_hal_tim.h" +// NOTE: only works for static arrays +#define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) + extern TIM_HandleTypeDef htim1; extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; @@ -150,7 +153,8 @@ class TimerDomain { } } - static consteval bool check_timer(Config *cfg, const Entry req, uint16_t timer_idx, int reqidx) { + // Do any compile time checks needed for the timers... + static consteval bool check_timer(Config *cfg, const Entry req, int reqidx) { if(req.period == 0) { ErrorInRequestN("Error: In request reqidx: period must be greater than 0 (>0)", reqidx); return false; @@ -174,18 +178,18 @@ class TimerDomain { } } - if(timer_idx == 12 || timer_idx == 13) { + if(req.request == Basic1 || req.request == Basic2) { // basic timers cfg->kind = TimerDomain::Kind::Basic; - } else if(timer_idx == 14 || timer_idx == 15) { + } else if(req.request == Advanced1 || req.request == Advanced2) { // advanced timers cfg->kind = TimerDomain::Kind::Advanced; } else { - if(timer_idx >= 0 && timer_idx <= 5) { + if(cfg->timer_idx >= 0 && cfg->timer_idx <= 5) { // general purpose timers 1 - } else if(timer_idx >= 6 && timer_idx <= 8) { + } else if(cfg->timer_idx >= 6 && cfg->timer_idx <= 8) { // general purpose timers 2 - } else if(timer_idx >= 9 && timer_idx <= 11) { + } else if(cfg->timer_idx >= 9 && cfg->timer_idx <= 11) { // general purpose timers 3 } else { ErrorInRequestN("Unknown timer idx in reqidx", reqidx); @@ -218,6 +222,38 @@ class TimerDomain { } } + Config DoTimer(const Entry request, uint8_t reqint, int reqidx, const char *name_too_long_msg) { + Config cfg; + if(request.name.length() == 0) { + // "Timer" + tostring(reqint) + cfg.name[0] = 'T'; + cfg.name[1] = 'i'; + cfg.name[2] = 'm'; + cfg.name[3] = 'e'; + cfg.name[4] = 'r'; + cfg.name[5] = (reqint/10) + '0'; + cfg.name[6] = (reqint%10) + '0'; + cfg.name[7] = '\0'; + } else { + if(request.name.length() >= sizeof(cfg.name)) { + ErrorInRequestN(name_too_long_msg, reqidx); + } + for(int si = 0; si < request.name.length(); si++) { + cfg.name[si] = request.name[si]; + } + cfg.name[request.name.length()] = '\0'; + } + cfg.timer_idx = TimerDomain.idxmap[reqint]; + cfg.prescaler = request.prescaler; + cfg.period = request.period; + cfg.deadtime = request.deadtime; + cfg.polarity = request.polarity; + cfg.negated_polarity = request.negated_polarity; + + check_timer(&cfg, request, i); + return cfg; + } + enum Kind : uint8_t { Basic, GeneralPurpose, @@ -349,46 +385,52 @@ class TimerDomain { if(usedTimer[reqint]) { ErrorInRequestN("Error: Timer already used. Error in request i", i); } + usedTimer[reqint] = true; - Config cfg; - if(requests[i].name[0] == '\0') { - // "Timer" + tostring(reqint) - cfg.name[0] = 'T'; - cfg.name[1] = 'i'; - cfg.name[2] = 'm'; - cfg.name[3] = 'e'; - cfg.name[4] = 'r'; - cfg.name[5] = (reqint/10) + '0'; - cfg.name[6] = (reqint%10) + '0'; - } else { - if(requests[i].name.length() >= sizeof(cfg.name)) { - ErrorInRequestN("Error: Timer name too large, max = 7 (sizeof cfg.name - 1). In request i", i); - } - for(int si = 0; si < requests[i].name.length(); si++) { - cfg.name[si] = requests[i].name[si]; - } - cfg.name[requests[i].name.length()] = '\0'; - } - cfg.timer_idx = TimerDomain.idxmap[reqint]; - cfg.prescaler = requests[i].prescaler; - cfg.period = requests[i].period; - cfg.deadtime = requests[i].deadtime; - cfg.polarity = requests[i].polarity; - cfg.negated_polarity = requests[i].negated_polarity; - + Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; - // unordered remove + // unordered remove (remaining requests is ) count_remaining_requests--; remaining_requests[i] = remaining_requests[count_remaining_requests]; } } - // Now do AnyGeneralPurpose + // 32 bit timers, very important for scheduler + uint8_t bits32_timers[] = {2, 5, 23, 24}; + // can use any CountingMode (32 bit timers can also but they are higher priority) + uint8_t up_down_updown_timers[] = {3, 4}; + // 16 bit timers + uint8_t bits16_timers[] = {12, 13, 14, 15, 16, 17}; + uint8_t remaining_timers[15] = {0}; + uint8_t count_remaining_timers = 0; + + for(int i = 0; i < ARRAY_LENGTH(bits16_timers); i++) { + if(!used_timers[bits16_timers[i]]) + remaining_timers[count_remaining_timers++] = bits16_timers[i]; + } + + for(int i = 0; i < ARRAY_LENGTH(up_down_updown_timers); i++) { + if(!used_timers[up_down_updown_timers[i]]) + remaining_timers[count_remaining_timers++] = up_down_updown_timers[i]; + } + + for(int i = 0; i < ARRAY_LENGTH(bits32_timers); i++) { + if(!used_timers[bits32_timers[i]]) + remaining_timers[count_remaining_timers++] = bits32_timers[i]; + } + + if(count_remaining_requests > count_remaining_timers) { + compile_error("This should not happen"); + } + for(int i = 0; i < count_remaining_requests; i++) { const Entry &e = requests[remaining_requests[i]]; if(e.request == AnyGeneralPurpose) { - // TODO: Find first general purpose timer that isn't used + uint8_t reqint = remaining_timers[i]; + // NOTE: I don't want to do an ordered remove so this has the real index + Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 (sizeof cfg.name - 1)"); + cfgs[cfg_idx++] = cfg; } } From 42e822554bb81954751d4bbf2307ffe0590d329c Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:16:30 +0100 Subject: [PATCH 226/281] Make prettier --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 25 ++++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index d18bb05ca..494982445 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -29,23 +29,22 @@ extern TIM_HandleTypeDef htim23; extern TIM_HandleTypeDef htim24; /* Tim1 & Tim8 are advanced-control timers - * their ARR & prescaler are 16bit - * they have up to 6 independent channels for: - * - input capture (not channel 5 or 6) - * - output capture - * - PWM generation - * - One-pulse mode output - */ + * their ARR & prescaler are 16bit + * they have up to 6 independent channels for: + * - input capture (not channel 5 or 6) + * - output capture + * - PWM generation + * - One-pulse mode output + */ /* Timers {TIM2, TIM5, TIM23, TIM24} are the only 32-bit counter resolution timers, the rest are 16-bit */ /* Timers 2, 3, 4, 5, 23, 24 are general-purpose timers - * Timers 12, 13, 14 are also general-purpose timers (but separate in the ref manual) - * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) - */ + * Timers 12, 13, 14 are also general-purpose timers (but separate in the ref manual) + * Timers 15, 16, 17 are also general purpose timers (but separate in the ref manual) + */ -/* Tim6 & Tim7 are basic timers */ -/* basic timer features: +/* Tim6 & Tim7 are basic timers. Features: - 16-bit ARR upcounter - 16-bit PSC - Synchronization circuit to trigger the DAC @@ -485,7 +484,7 @@ class TimerDomain { } // leftover from old TimerPeripheral, maybe this was useful? - inline uint32_t get_prescaler() { + inline uint16_t get_prescaler() { return tim->PSC; } inline uint32_t get_period() { From bd9e1b1cfba248d2298b8fe9da9b69a36dcc0b94 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:17:26 +0100 Subject: [PATCH 227/281] Remove leftovers --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 494982445..9b73e31a2 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -586,26 +586,6 @@ class TimerDomain { } } } - - // Leftover from last iteration of the design of NewTimerPeripheral, will cleanup soon -private: - enum TIM_CAPABILITIES { - Basic_Start = 0, - Basic_End = 1, - - General_Start = 2, - General_End = 13, - - Advanced_Start = 14, - Advanced_End = 15, - - Count_Cap = 16, - }; - - // This should use __builtin_ffs() - 1 to get the index of the next - static uint32_t free_bmp = 0xFFFF'FFFF; - - static void (*callbacks)()[16]; }; From 789be1fcb86e5fd46cb3e747b0930e1db00a780e Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:18:24 +0100 Subject: [PATCH 228/281] Remove outdated comment --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 9b73e31a2..51528d8b2 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -501,7 +501,6 @@ class TimerDomain { uint16_t timer_idx; void (*callback)(TimerDomain::Instance); - // NOTE: Need counter_enable() here for configure(), kept counter_disable() for consistency if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { // advanced specific functions } From 2e2624b7e14f6f778b14bfde9d15e13c397cb05d Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 14:19:12 +0100 Subject: [PATCH 229/281] fix: Finish the comment :) --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 51528d8b2..1adf0b6db 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -389,7 +389,7 @@ class TimerDomain { Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; - // unordered remove (remaining requests is ) + // unordered remove (remaining requests is not used here so these are ordered) count_remaining_requests--; remaining_requests[i] = remaining_requests[count_remaining_requests]; } From 37339a2919b07ad5989a173ddb32b2cabdf17922 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 17:46:37 +0100 Subject: [PATCH 230/281] Clean up error messages, add comment --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 1adf0b6db..fcbd4d1ae 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -311,7 +311,7 @@ class TimerDomain { }; struct Entry { - string name; + string name; /* max length = 7 */ TimerRequest request; ST_LIB::GPIODomain::Pin *pin; TimerDomain::CountingMode counting_mode; @@ -386,7 +386,7 @@ class TimerDomain { } usedTimer[reqint] = true; - Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 (sizeof cfg.name - 1)"); + Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -428,7 +428,7 @@ class TimerDomain { if(e.request == AnyGeneralPurpose) { uint8_t reqint = remaining_timers[i]; // NOTE: I don't want to do an ordered remove so this has the real index - Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 (sizeof cfg.name - 1)"); + Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; } } From a2afcce64c44d835f5631fbe82ec96679a421886 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 18:22:45 +0100 Subject: [PATCH 231/281] temp: setup to try to compile template_project --- Inc/HALAL/HALAL.hpp | 5 ++-- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 5 ++++ Inc/ST-LIB.hpp | 9 ++++++- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 28 ++++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 Src/HALAL/Models/TimerDomain/TimerDomain.cpp diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index bc896cce3..72ce03845 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -20,7 +20,8 @@ #include "HALAL/Services/PWM/PhasedPWM/PhasedPWM.hpp" #include "HALAL/Services/PWM/DualPhasedPWM/DualPhasedPWM.hpp" -#include "HALAL/Services/Time/Time.hpp" +//#include "HALAL/Services/Time/Time.hpp" +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" #include "HALAL/Services/Time/Scheduler.hpp" #include "HALAL/Services/Time/RTC.hpp" @@ -40,7 +41,7 @@ #include "HALAL/Services/InfoWarning/InfoWarning.hpp" #include "HALAL/Services/Watchdog/Watchdog.hpp" -#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" +//#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" #include "HALAL/Models/BoardID/BoardID.hpp" #include "HALAL/Models/Concepts/Concepts.hpp" diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index fcbd4d1ae..a4f1e96f0 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -509,6 +509,10 @@ class TimerDomain { // general purpose and advanced functions } + template + void set_mode(); + +#if 0 /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ template inline void set_mode(void) { @@ -535,6 +539,7 @@ class TimerDomain { MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); } } +#endif }; template struct Init { diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 32fb54814..07c14d1a4 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -70,7 +70,8 @@ template struct BuildCtx { } }; -using DomainsCtx = BuildCtx; template struct Board { @@ -88,12 +89,14 @@ template struct Board { static consteval auto build() { 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(); // ... struct ConfigBundle { std::array gpio_cfgs; + std::array tim_cfgs; std::array dout_cfgs; std::array din_cfgs; // ... @@ -102,6 +105,8 @@ template struct Board { return ConfigBundle{ .gpio_cfgs = GPIODomain::template build(ctx.template span()), + .tim_cfgs = + TimerDomain::template build(ctx.template span()), .dout_cfgs = DigitalOutputDomain::template build( ctx.template span()), .din_cfgs = DigitalInputDomain::template build( @@ -114,11 +119,13 @@ template struct Board { static void init() { 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(); // ... 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, diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp new file mode 100644 index 000000000..b79e2834f --- /dev/null +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -0,0 +1,28 @@ +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" + +template +TimerDomain::TimerWrapper::set_mode() { + constexpr uint8_t reqint = static_cast(dev.e.request); + if constexpr (!(reqint == 1 || reqint == 8 || + reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || + reqint == 3 || reqint == 4)) + { + compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + return; + } + + if constexpr (mode == CounterMode::UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == CounterMode::DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } +} + From 5110d5f23f0d72ea4d8d0ffbc66c195d13dd4444 Mon Sep 17 00:00:00 2001 From: victhor Date: Sat, 27 Dec 2025 20:31:24 +0100 Subject: [PATCH 232/281] Try to get TimerDomain to compile --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 434 ++++++++++--------- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 27 +- 2 files changed, 226 insertions(+), 235 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index a4f1e96f0..03022efbc 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -9,6 +9,10 @@ #include "stm32h7xx_hal_tim.h" +#include +#include +#include + // NOTE: only works for static arrays #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) @@ -16,6 +20,7 @@ extern TIM_HandleTypeDef htim1; extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim3; extern TIM_HandleTypeDef htim4; +extern TIM_HandleTypeDef htim5; extern TIM_HandleTypeDef htim6; extern TIM_HandleTypeDef htim7; extern TIM_HandleTypeDef htim8; @@ -73,37 +78,112 @@ extern TIM_HandleTypeDef htim24; - Supports incremental (quadrature) encoder and Hall-sensor circuitry for positioning purposes - Trigger input for external clock or cycle-by-cycle current management */ -class TimerDomain { - static constexpr std::array create_idxmap() { - std::array result{}; - - // invalid timers that don't exist - result[0] = -1; - result[9] = -1; result[10] = -1; result[11] = -1; - result[18] = -1; result[19] = -1; result[20] = -1; result[21] = -1; result[22] = -1; - - // general-purpose timers - result[2] = 0; result[3] = 1; result[4] = 2; - result[5] = 3; result[23] = 4; result[24] = 5; +constexpr std::array create_idxmap() { + std::array result{}; + + // invalid timers that don't exist + result[0] = -1; + result[9] = -1; result[10] = -1; result[11] = -1; + result[18] = -1; result[19] = -1; result[20] = -1; result[21] = -1; result[22] = -1; + + // general-purpose timers + result[2] = 0; result[3] = 1; result[4] = 2; + result[5] = 3; result[23] = 4; result[24] = 5; + + // more general-purpose timers + result[12] = 6; result[13] = 7; result[14] = 8; + + // more general-purpose timers + result[15] = 9; result[16] = 10; result[17] = 11; + + // basic timers + result[6] = 12; result[7] = 13; + + // advanced control timers + result[1] = 14; result[8] = 15; + + return result; +} + +struct TimerDomain { + // There are 16 timers + static constexpr std::size_t max_instances = 16; - // more general-purpose timers - result[12] = 6; result[13] = 7; result[14] = 8; + /* The number corresponds with the timer nº */ + enum TimerRequest : uint8_t { + Advanced1 = 1, + Advanced2 = 8, - // more general-purpose timers - result[15] = 9; result[16] = 10; result[17] = 11; + AnyGeneralPurpose = 0xFF, + GeneralPurpose1 = 2, + GeneralPurpose2 = 3, + GeneralPurpose3 = 4, + GeneralPurpose4 = 5, + GeneralPurpose5 = 23, + GeneralPurpose6 = 24, - // basic timers - result[6] = 12; result[7] = 13; + GeneralPurpose7 = 12, + GeneralPurpose8 = 13, + GeneralPurpose9 = 14, - // advanced control timers - result[1] = 14; result[8] = 15; - - return result; - } + GeneralPurpose10 = 15, + GeneralPurpose11 = 16, + GeneralPurpose12 = 17, + + Basic1 = 6, + Basic2 = 7, + }; + + enum CountingMode : uint8_t { + UP = 0, + DOWN = 1, + /* center-aligned = counter counts up and down alternatively */ + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting down */ + CENTER_ALIGNED_INTERRUPT_DOWN = 2, + /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are + set only when the counter is counting up */ + CENTER_ALIGNED_INTERRUPT_UP = 3, + /* both up and down */ + CENTER_ALIGNED_INTERRUPT_BOTH = 4, + }; + enum Kind : uint8_t { + Basic, + GeneralPurpose, + Advanced, + }; + + struct Entry { + std::string name; /* max length = 7 */ + TimerRequest request; + ST_LIB::GPIODomain::Pin *pin; + TimerDomain::CountingMode counting_mode; + uint16_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + + struct Config { + char name[8]; /* "Timerxx\0" */ + TimerDomain::Kind kind; + uint16_t timer_idx; + ST_LIB::GPIODomain::Pin *asociated_pin; + TimerDomain::CountingMode counting_mode; + uint32_t prescaler; + uint32_t period; + uint32_t deadtime; + uint32_t polarity; + uint32_t negated_polarity; + }; + +private: + static void I_Need_To_Compile_TimerDomain_CPP(void); static constexpr std::array idxmap = create_idxmap(); - static const TIM_HandleTypeDef *hal_handles[16] = { + static constexpr TIM_HandleTypeDef *hal_handles[16] = { // general purpose timers &htim2, &htim3, &htim4, &htim5, &htim23, &htim24, &htim12, &htim13, &htim14, @@ -116,7 +196,7 @@ class TimerDomain { &htim1, &htim8 }; - static const TIM_TypeDef *cmsis_timers[16] = { + static constexpr TIM_TypeDef *cmsis_timers[16] = { // general purpose timers TIM2, TIM3, TIM4, TIM5, TIM23, TIM24, TIM12, TIM13, TIM14, @@ -129,29 +209,61 @@ class TimerDomain { TIM1, TIM8 }; - static inline void rcc_enable_timer(TIM_TypeDef *tim) { - switch(tim) { - case TIM2: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM2EN); break; - case TIM3: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM3EN); break; - case TIM4: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM4EN); break; - case TIM5: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM5EN); break; - case TIM6: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM6EN); break; - case TIM7: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM7EN); break; - case TIM12: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM12EN); break; - case TIM13: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM13EN); break; - case TIM14: SET_BIT(RCC->APB1LENR, RCC_APB1LENR_TIM14EN); break; - - case TIM24: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM24EN); break; - case TIM23: SET_BIT(RCC->APB1HENR, RCC_APB1HENR_TIM23EN); break; - - case TIM17: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM17EN); break; - case TIM16: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM16EN); break; - case TIM15: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM15EN); break; - case TIM8: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM8EN); break; - case TIM1: SET_BIT(RCC->APB2ENR, RCC_APB2ENR_TIM1EN); break; + /* to show the error with an index */ + static consteval void ErrorInRequestN(const char *str, int n) + { + switch(n) { + case 0: ST_LIB::compile_error(str); + case 1: ST_LIB::compile_error(str); + case 2: ST_LIB::compile_error(str); + case 3: ST_LIB::compile_error(str); + case 4: ST_LIB::compile_error(str); + case 5: ST_LIB::compile_error(str); + case 6: ST_LIB::compile_error(str); + case 7: ST_LIB::compile_error(str); + case 8: ST_LIB::compile_error(str); + case 9: ST_LIB::compile_error(str); + case 10: ST_LIB::compile_error(str); + case 11: ST_LIB::compile_error(str); + case 12: ST_LIB::compile_error(str); + case 13: ST_LIB::compile_error(str); + case 14: ST_LIB::compile_error(str); + case 15: ST_LIB::compile_error(str); } } + static inline void rcc_enable_timer(TIM_TypeDef *tim) { +#define TimerXList \ + X(TIM2, APB1LENR) \ + X(TIM3, APB1LENR) \ + X(TIM4, APB1LENR) \ + X(TIM5, APB1LENR) \ + X(TIM6, APB1LENR) \ + X(TIM7, APB1LENR) \ + X(TIM12, APB1LENR) \ + X(TIM13, APB1LENR) \ + X(TIM14, APB1LENR) \ + \ + X(TIM23, APB1HENR) \ + X(TIM24, APB1HENR) \ + \ + X(TIM1, APB2ENR) \ + X(TIM8, APB2ENR) \ + X(TIM15, APB2ENR) \ + X(TIM16, APB2ENR) \ + X(TIM17, APB2ENR) +#define X(t, b) \ + else if(tim == t) { SET_BIT(RCC->b, RCC_##b##_##t##EN); } + + if(false) {} + TimerXList + else { + ErrorHandler("Invalid timer given to rcc_enable_timer"); + } + +#undef X + } + // Do any compile time checks needed for the timers... static consteval bool check_timer(Config *cfg, const Entry req, int reqidx) { if(req.period == 0) { @@ -198,82 +310,38 @@ class TimerDomain { } } - /* to show the error with an index */ - static consteval ErrorInRequestN(char *str, int n) - { - switch(n) { - case 0: compile_error(str); - case 1: compile_error(str); - case 2: compile_error(str); - case 3: compile_error(str); - case 4: compile_error(str); - case 5: compile_error(str); - case 6: compile_error(str); - case 7: compile_error(str); - case 8: compile_error(str); - case 9: compile_error(str); - case 10: compile_error(str); - case 11: compile_error(str); - case 12: compile_error(str); - case 13: compile_error(str); - case 14: compile_error(str); - case 15: compile_error(str); - } - } - - Config DoTimer(const Entry request, uint8_t reqint, int reqidx, const char *name_too_long_msg) { - Config cfg; - if(request.name.length() == 0) { - // "Timer" + tostring(reqint) - cfg.name[0] = 'T'; - cfg.name[1] = 'i'; - cfg.name[2] = 'm'; - cfg.name[3] = 'e'; - cfg.name[4] = 'r'; - cfg.name[5] = (reqint/10) + '0'; - cfg.name[6] = (reqint%10) + '0'; - cfg.name[7] = '\0'; - } else { - if(request.name.length() >= sizeof(cfg.name)) { - ErrorInRequestN(name_too_long_msg, reqidx); - } - for(int si = 0; si < request.name.length(); si++) { - cfg.name[si] = request.name[si]; - } - cfg.name[request.name.length()] = '\0'; - } - cfg.timer_idx = TimerDomain.idxmap[reqint]; - cfg.prescaler = request.prescaler; - cfg.period = request.period; - cfg.deadtime = request.deadtime; - cfg.polarity = request.polarity; - cfg.negated_polarity = request.negated_polarity; - - check_timer(&cfg, request, i); - return cfg; - } - - enum Kind : uint8_t { - Basic, - GeneralPurpose, - Advanced, - }; + #define DoTimer(request, reqint, reqidx, name_too_long_msg) do{ \ + Config cfg; \ + if((request).name.length() == 0) { \ + /* "Timer" + tostring(reqint) */ \ + cfg.name[0] = 'T'; \ + cfg.name[1] = 'i'; \ + cfg.name[2] = 'm'; \ + cfg.name[3] = 'e'; \ + cfg.name[4] = 'r'; \ + cfg.name[5] = (reqint/10) + '0'; \ + cfg.name[6] = (reqint%10) + '0'; \ + cfg.name[7] = '\0'; \ + } else { \ + if((request).name.length() >= sizeof(cfg.name)) { \ + ErrorInRequestN(name_too_long_msg, reqidx); \ + } \ + for(std::size_t si = 0; si < (request).name.length(); si++) { \ + cfg.name[si] = (request).name[si]; \ + } \ + cfg.name[(request).name.length()] = '\0'; \ + } \ + cfg.timer_idx = TimerDomain::idxmap[reqint]; \ + cfg.prescaler = (request).prescaler; \ + cfg.period = (request).period; \ + cfg.deadtime = (request).deadtime; \ + cfg.polarity = (request).polarity; \ + cfg.negated_polarity = (request).negated_polarity; \ + \ + check_timer(&cfg, request, i); \ + } while(0) public: - enum CountingMode : uint8_t { - UP = 0, - DOWN = 1, - /* center-aligned = counter counts up and down alternatively */ - /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are - set only when the counter is counting down */ - CENTER_ALIGNED_INTERRUPT_DOWN = 2, - /* Output compare interrupt flags of channels configured in output (CCxS=00 in TIMx_CCMRx register) are - set only when the counter is counting up */ - CENTER_ALIGNED_INTERRUPT_UP = 3, - /* both up and down */ - CENTER_ALIGNED_INTERRUPT_BOTH = 4, - }; - enum PWM_MODE : uint8_t { NORMAL = 0, PHASED = 1, @@ -285,48 +353,11 @@ class TimerDomain { PWM_MODE mode; }; - /* The number corresponds with the timer nº */ - enum TimerRequest : uint8_t { - Advanced1 = 1, - Advanced2 = 8, - - AnyGeneralPurpose = 0xFF, - GeneralPurpose1 = 2, - GeneralPurpose2 = 3, - GeneralPurpose3 = 4, - GeneralPurpose4 = 5, - GeneralPurpose5 = 23, - GeneralPurpose6 = 24, - - GeneralPurpose7 = 12, - GeneralPurpose8 = 13, - GeneralPurpose9 = 14, - - GeneralPurpose10 = 15, - GeneralPurpose11 = 16, - GeneralPurpose12 = 17, - - Basic1 = 6, - Basic2 = 7, - }; - - struct Entry { - string name; /* max length = 7 */ - TimerRequest request; - ST_LIB::GPIODomain::Pin *pin; - TimerDomain::CountingMode counting_mode; - uint16_t prescaler; - uint32_t period; - uint32_t deadtime; - uint32_t polarity; - uint32_t negated_polarity; - }; - struct Device { using domain = TimerDomain; Entry e; - consteval Device(string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, + consteval Device(std::string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) : @@ -338,34 +369,18 @@ class TimerDomain { } }; - // There are 16 timers - static constexpr std::size_t max_instances = 16; - - struct Config { - char name[8]; /* "Timerxx\0" */ - TimerDomain::Kind kind; - uint16_t timer_idx; - ST_LIB::GPIODomain::Pin *asociated_pin; - TimerDomain::CountingMode counting_mode; - uint32_t prescaler; - uint32_t period; - uint32_t deadtime; - uint32_t polarity; - uint32_t negated_polarity; - }; - template - static consteval std::array build(span requests) { - array cfgs{}; + static consteval std::array build(std::span requests) { + std::array cfgs{}; uint16_t cfg_idx = 0; - bool usedTimer[25] = {0}; + bool used_timers[25] = {0}; if(requests.size() > max_instances) { throw "too many Timer requests, there are only 16 timers"; } int remaining_requests[max_instances] = {}; - std::size_t count_remaining_requests = requsts.size(); + std::size_t count_remaining_requests = requests.size(); for(int i = 0; i < requests.size(); i++) remaining_requests[i] = i; for(int i = 0; i < requests.size(); i++) { @@ -381,12 +396,13 @@ class TimerDomain { for(std::size_t i = 0; i < N; i++) { uint8_t reqint = static_cast(requests[i].request); if(reqint != static_cast(TimerRequest::AnyGeneralPurpose)) { - if(usedTimer[reqint]) { + if(used_timers[reqint]) { ErrorInRequestN("Error: Timer already used. Error in request i", i); } - usedTimer[reqint] = true; + used_timers[reqint] = true; - Config cfg = DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); + Config cfg; + DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -420,7 +436,7 @@ class TimerDomain { } if(count_remaining_requests > count_remaining_timers) { - compile_error("This should not happen"); + ST_LIB::compile_error("This should not happen"); } for(int i = 0; i < count_remaining_requests; i++) { @@ -428,7 +444,8 @@ class TimerDomain { if(e.request == AnyGeneralPurpose) { uint8_t reqint = remaining_timers[i]; // NOTE: I don't want to do an ordered remove so this has the real index - Config cfg = DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); + Config cfg; + DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); cfgs[cfg_idx++] = cfg; } } @@ -439,6 +456,16 @@ class TimerDomain { // Runtime object struct Instance { template friend struct TimerWrapper; + }; + + template + struct TimerWrapper { + TIM_TypeDef *tim; + TIM_HandleTypeDef *hal_tim; + char name[8]; + const TimerDomain::Kind kind; + uint16_t timer_idx; + void (*callback)(TimerDomain::Instance); inline void counter_enable() { SET_BIT(tim->CR1, TIM_CR1_CEN); @@ -490,17 +517,8 @@ class TimerDomain { inline uint32_t get_period() { return tim->ARR; } - }; - - template - struct TimerWrapper { - TIM_TypeDef *tim; - TIM_HandleTypeDef *hal_tim; - char name[8]; - const TimerDomain::Kind kind; - uint16_t timer_idx; - void (*callback)(TimerDomain::Instance); +#if 0 if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { // advanced specific functions } @@ -508,38 +526,34 @@ class TimerDomain { if constexpr (dev.e.request != TimerRequest::Basic1 && dev.e.request != TimerRequest::Basic2) { // general purpose and advanced functions } +#endif - template - void set_mode(); - -#if 0 /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ - template + template inline void set_mode(void) { constexpr uint8_t reqint = static_cast(dev.e.request); if constexpr (!(reqint == 1 || reqint == 8 || reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || reqint == 3 || reqint == 4)) { - compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); + ST_LIB::compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); return; } - if constexpr (mode == CounterMode::UP) { + if constexpr (mode == CountingMode::UP) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == CounterMode::DOWN) { + } else if constexpr (mode == CountingMode::DOWN) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); } } -#endif }; template struct Init { @@ -563,15 +577,15 @@ class TimerDomain { tim->PSC = e.prescaler; tim->ARR = e.period; - if constexpr (e.counting_mode == CounterMode::UP) { + if(e.counting_mode == CountingMode::UP) { CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (e.counting_mode == CounterMode::DOWN) { + } else if(e.counting_mode == CountingMode::DOWN) { SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { + } else if(e.counting_mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (e.counting_mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + } 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)); } @@ -589,7 +603,7 @@ class TimerDomain { }; } } - } + }; }; diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index b79e2834f..c23c50df2 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -1,28 +1,5 @@ #include "HALAL/Models/TimerDomain/TimerDomain.hpp" -template -TimerDomain::TimerWrapper::set_mode() { - constexpr uint8_t reqint = static_cast(dev.e.request); - if constexpr (!(reqint == 1 || reqint == 8 || - reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || - reqint == 3 || reqint == 4)) - { - compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); - return; - } - - if constexpr (mode == CounterMode::UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); - CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == CounterMode::DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); - SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == CounterMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); - } +void TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { + // Need to compile this file so I keep this symbol here } - From 74b150de64d8cce7b40badc184c2fe105b111f18 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 00:24:35 +0100 Subject: [PATCH 233/281] Fix all compilation errors (yipee) --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 12 +++++++++++- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 03022efbc..0c5b9703d 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -7,12 +7,17 @@ #pragma once -#include "stm32h7xx_hal_tim.h" +#include "stm32h7xx_hal.h" +//#include "stm32h7xx_hal_tim.h" +#ifdef HAL_TIM_MODULE_ENABLED #include #include #include +#include "HALAL/Models/GPIO.hpp" +#include "ErrorHandler/ErrorHandler.hpp" + // NOTE: only works for static arrays #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) @@ -105,6 +110,9 @@ constexpr std::array create_idxmap() { return result; } +namespace ST_LIB { +extern void compile_error(const char *msg); + struct TimerDomain { // There are 16 timers static constexpr std::size_t max_instances = 16; @@ -605,7 +613,9 @@ struct TimerDomain { } }; }; +} // namespace ST_LIB +#endif // HAL_TIM_MODULE_ENABLED /* Old init code from TimerPeripheral.cpp, some might be recycled diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index c23c50df2..faccd6d93 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -1,5 +1,5 @@ #include "HALAL/Models/TimerDomain/TimerDomain.hpp" -void TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { +void ST_LIB::TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { // Need to compile this file so I keep this symbol here } From 49e88e8b988144e6aef4f4cf1b6b139b9227f6c4 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 01:13:27 +0100 Subject: [PATCH 234/281] Try to fix compile errors when in template_project --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 103 ++++++++++--------- Inc/ST-LIB.hpp | 2 +- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 0c5b9703d..a2d844bd7 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -13,7 +13,6 @@ #include #include -#include #include "HALAL/Models/GPIO.hpp" #include "ErrorHandler/ErrorHandler.hpp" @@ -83,7 +82,10 @@ extern TIM_HandleTypeDef htim24; - Supports incremental (quadrature) encoder and Hall-sensor circuitry for positioning purposes - Trigger input for external clock or cycle-by-cycle current management */ -constexpr std::array create_idxmap() { +namespace ST_LIB { +extern void compile_error(const char *msg); + +constexpr std::array create_timer_idxmap() { std::array result{}; // invalid timers that don't exist @@ -110,8 +112,7 @@ constexpr std::array create_idxmap() { return result; } -namespace ST_LIB { -extern void compile_error(const char *msg); +static constexpr std::array timer_idxmap = create_timer_idxmap(); struct TimerDomain { // There are 16 timers @@ -163,7 +164,7 @@ struct TimerDomain { }; struct Entry { - std::string name; /* max length = 7 */ + std::array name; /* max length = 7 */ TimerRequest request; ST_LIB::GPIODomain::Pin *pin; TimerDomain::CountingMode counting_mode; @@ -189,7 +190,7 @@ struct TimerDomain { private: static void I_Need_To_Compile_TimerDomain_CPP(void); - static constexpr std::array idxmap = create_idxmap(); + static constexpr TIM_HandleTypeDef *hal_handles[16] = { // general purpose timers @@ -318,9 +319,9 @@ struct TimerDomain { } } - #define DoTimer(request, reqint, reqidx, name_too_long_msg) do{ \ + #define DoTimer(request, reqint, reqidx) do{ \ Config cfg; \ - if((request).name.length() == 0) { \ + if((request).name[0] == '\0') { \ /* "Timer" + tostring(reqint) */ \ cfg.name[0] = 'T'; \ cfg.name[1] = 'i'; \ @@ -331,21 +332,16 @@ struct TimerDomain { cfg.name[6] = (reqint%10) + '0'; \ cfg.name[7] = '\0'; \ } else { \ - if((request).name.length() >= sizeof(cfg.name)) { \ - ErrorInRequestN(name_too_long_msg, reqidx); \ - } \ - for(std::size_t si = 0; si < (request).name.length(); si++) { \ + for(int si = 0; si < 8; si++) { \ cfg.name[si] = (request).name[si]; \ } \ - cfg.name[(request).name.length()] = '\0'; \ } \ - cfg.timer_idx = TimerDomain::idxmap[reqint]; \ + cfg.timer_idx = timer_idxmap[reqint]; \ cfg.prescaler = (request).prescaler; \ cfg.period = (request).period; \ cfg.deadtime = (request).deadtime; \ cfg.polarity = (request).polarity; \ cfg.negated_polarity = (request).negated_polarity; \ - \ check_timer(&cfg, request, i); \ } while(0) @@ -361,11 +357,12 @@ struct TimerDomain { PWM_MODE mode; }; - struct Device { +#define EMPTY_TIMER_NAME {0,0,0,0, 0,0,0,0} + struct Timer { using domain = TimerDomain; Entry e; - consteval Device(std::string name = "", TimerRequest request = TimerRequest::AnyGeneralPurpose, + consteval Timer(std::array name = EMPTY_TIMER_NAME, TimerRequest request = TimerRequest::AnyGeneralPurpose, ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) : @@ -384,14 +381,14 @@ struct TimerDomain { bool used_timers[25] = {0}; if(requests.size() > max_instances) { - throw "too many Timer requests, there are only 16 timers"; + ST_LIB::compile_error("too many Timer requests, there are only 16 timers"); } int remaining_requests[max_instances] = {}; - std::size_t count_remaining_requests = requests.size(); - for(int i = 0; i < requests.size(); i++) remaining_requests[i] = i; + int count_remaining_requests = (int)requests.size(); + for(int i = 0; i < (int)requests.size(); i++) remaining_requests[i] = i; - for(int i = 0; i < requests.size(); i++) { + for(int i = 0; i < (int)requests.size(); i++) { if(requests[i].request != TimerRequest::AnyGeneralPurpose && (requests[i].request < 1 || requests[i].request > 24 || (requests[i].request > 17 && requests[i].request < 23))) @@ -410,7 +407,7 @@ struct TimerDomain { used_timers[reqint] = true; Config cfg; - DoTimer(requests[i], reqint, i, "Error: In request reqidx: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); + DoTimer(requests[i], reqint, i); cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -428,17 +425,17 @@ struct TimerDomain { uint8_t remaining_timers[15] = {0}; uint8_t count_remaining_timers = 0; - for(int i = 0; i < ARRAY_LENGTH(bits16_timers); i++) { + for(int i = 0; i < (int)ARRAY_LENGTH(bits16_timers); i++) { if(!used_timers[bits16_timers[i]]) remaining_timers[count_remaining_timers++] = bits16_timers[i]; } - for(int i = 0; i < ARRAY_LENGTH(up_down_updown_timers); i++) { + for(int i = 0; i < (int)ARRAY_LENGTH(up_down_updown_timers); i++) { if(!used_timers[up_down_updown_timers[i]]) remaining_timers[count_remaining_timers++] = up_down_updown_timers[i]; } - for(int i = 0; i < ARRAY_LENGTH(bits32_timers); i++) { + for(int i = 0; i < (int)ARRAY_LENGTH(bits32_timers); i++) { if(!used_timers[bits32_timers[i]]) remaining_timers[count_remaining_timers++] = bits32_timers[i]; } @@ -453,7 +450,7 @@ struct TimerDomain { uint8_t reqint = remaining_timers[i]; // NOTE: I don't want to do an ordered remove so this has the real index Config cfg; - DoTimer(requests[i], reqint, i, "Error: In one of AnyGeneralPurpose timers: Timer name too large, max = 7 characters (sizeof cfg.name - 1)"); + DoTimer(requests[i], reqint, i); cfgs[cfg_idx++] = cfg; } } @@ -463,11 +460,6 @@ struct TimerDomain { // Runtime object struct Instance { - template friend struct TimerWrapper; - }; - - template - struct TimerWrapper { TIM_TypeDef *tim; TIM_HandleTypeDef *hal_tim; char name[8]; @@ -475,55 +467,64 @@ struct TimerDomain { uint16_t timer_idx; void (*callback)(TimerDomain::Instance); + template friend struct TimerWrapper; + }; + + template + struct TimerWrapper { + Instance& instance; + + TimerWrapper(Instance& inst) : instance(inst) {} + inline void counter_enable() { - SET_BIT(tim->CR1, TIM_CR1_CEN); + SET_BIT(instance.tim->CR1, TIM_CR1_CEN); } inline void counter_disable() { - CLEAR_BIT(tim->CR1, TIM_CR1_CEN); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_CEN); } inline void clear_update_interrupt_flag() { - CLEAR_BIT(tim->SR, TIM_SR_UIF); + CLEAR_BIT(instance.tim->SR, TIM_SR_UIF); } /* Enabled by default */ inline void enable_update_interrupt() { - CLEAR_BIT(tim->CR1, TIM_CR1_UDIS); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); } inline void disable_update_interrupt() { - SET_BIT(tim->CR1, TIM_CR1_UDIS); + SET_BIT(instance.tim->CR1, TIM_CR1_UDIS); } /* interrupt gets called only once, counter needs to be reenabled */ inline void set_one_pulse_mode() { - SET_BIT(tim->CR1, TIM_CR1_OPM); + SET_BIT(instance.tim->CR1, TIM_CR1_OPM); } inline void multi_interrupt() { - CLEAR_BIT(tim->CR1, TIM_CR1_OPM); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_OPM); } inline TIM_HandleTypeDef *get_hal_handle() { - return hal_tim; + return instance.hal_tim; } inline TIM_TypeDef *get_cmsis_handle() { - return tim; + return instance.tim; } template inline void configure(void (*callback)()) { if constexpr (psc != 0) { - tim->PSC = psc; + instance.tim->PSC = psc; } - this.callback = callback; + instance.callback = callback; this.counter_enable(); } // leftover from old TimerPeripheral, maybe this was useful? inline uint16_t get_prescaler() { - return tim->PSC; + return instance.tim->PSC; } inline uint32_t get_period() { - return tim->ARR; + return instance.tim->ARR; } #if 0 @@ -549,17 +550,17 @@ struct TimerDomain { } if constexpr (mode == CountingMode::UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); - CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter } else if constexpr (mode == CountingMode::DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, 0); - SET_BIT(tim->CR1, TIM_CR1_DIR); // downcounter + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); } } }; diff --git a/Inc/ST-LIB.hpp b/Inc/ST-LIB.hpp index 07c14d1a4..87a1736ca 100644 --- a/Inc/ST-LIB.hpp +++ b/Inc/ST-LIB.hpp @@ -106,7 +106,7 @@ template struct Board { .gpio_cfgs = GPIODomain::template build(ctx.template span()), .tim_cfgs = - TimerDomain::template build(ctx.template span()), + TimerDomain::template build(ctx.template span()), .dout_cfgs = DigitalOutputDomain::template build( ctx.template span()), .din_cfgs = DigitalInputDomain::template build( From 3dd5e36ea87ab0336569ca218b5ad23850e82643 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 01:42:41 +0100 Subject: [PATCH 235/281] Try to fix compile errors... Goodbye ErrorInRequestN I thought it could be used T-T --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 148 ++++++++----------- 1 file changed, 62 insertions(+), 86 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index a2d844bd7..5cac56ae1 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -218,29 +218,6 @@ struct TimerDomain { TIM1, TIM8 }; - /* to show the error with an index */ - static consteval void ErrorInRequestN(const char *str, int n) - { - switch(n) { - case 0: ST_LIB::compile_error(str); - case 1: ST_LIB::compile_error(str); - case 2: ST_LIB::compile_error(str); - case 3: ST_LIB::compile_error(str); - case 4: ST_LIB::compile_error(str); - case 5: ST_LIB::compile_error(str); - case 6: ST_LIB::compile_error(str); - case 7: ST_LIB::compile_error(str); - case 8: ST_LIB::compile_error(str); - case 9: ST_LIB::compile_error(str); - case 10: ST_LIB::compile_error(str); - case 11: ST_LIB::compile_error(str); - case 12: ST_LIB::compile_error(str); - case 13: ST_LIB::compile_error(str); - case 14: ST_LIB::compile_error(str); - case 15: ST_LIB::compile_error(str); - } - } - static inline void rcc_enable_timer(TIM_TypeDef *tim) { #define TimerXList \ X(TIM2, APB1LENR) \ @@ -273,18 +250,39 @@ struct TimerDomain { #undef X } - // Do any compile time checks needed for the timers... - static consteval bool check_timer(Config *cfg, const Entry req, int reqidx) { - if(req.period == 0) { - ErrorInRequestN("Error: In request reqidx: period must be greater than 0 (>0)", reqidx); - return false; + static constexpr Config DoTimer(const Entry request, int reqint, int reqidx) { + Config cfg; + if((request).name[0] == '\0') { + /* "Timer" + tostring(reqint) */ + cfg.name[0] = 'T'; + cfg.name[1] = 'i'; + cfg.name[2] = 'm'; + cfg.name[3] = 'e'; + cfg.name[4] = 'r'; + cfg.name[5] = (reqint/10) + '0'; + cfg.name[6] = (reqint%10) + '0'; + cfg.name[7] = '\0'; + } else { + for(int si = 0; si < 8; si++) { + cfg.name[si] = (request).name[si]; + } + } + cfg.timer_idx = timer_idxmap[reqint]; + cfg.prescaler = (request).prescaler; + cfg.period = (request).period; + cfg.deadtime = (request).deadtime; + cfg.polarity = (request).polarity; + cfg.negated_polarity = (request).negated_polarity; + + //check_timer(&cfg, request, reqidx); + // Do any compile time checks needed for the timers... + if(request.period == 0) { + ST_LIB::compile_error("Error: period must be greater than 0 (>0)"); } - uint8_t reqint = static_cast(req.request); if(!(reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24)) { - if(req.period > 0xFFFF) { - ErrorInRequestN("Error: In request reqidx: Timers other than {TIM2, TIM5, TIM23, TIM24} have a maximum period of 0xFFFF (they are uint16_t)", reqidx); - return false; + if(request.period > 0xFFFF) { + ST_LIB::compile_error("Error: Timers other than {TIM2, TIM5, TIM23, TIM24} have a maximum period of 0xFFFF (they are uint16_t)"); } } @@ -292,58 +290,33 @@ struct TimerDomain { reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || reqint == 3 || reqint == 4)) { - if(req.counting_mode != CountingMode::UP) { - ErrorInRequestN("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting", reqidx); - return false; + 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"); } } - if(req.request == Basic1 || req.request == Basic2) { + if(request.request == Basic1 || request.request == Basic2) { // basic timers - cfg->kind = TimerDomain::Kind::Basic; - } else if(req.request == Advanced1 || req.request == Advanced2) { + cfg.kind = TimerDomain::Kind::Basic; + } else if(request.request == Advanced1 || request.request == Advanced2) { // advanced timers - cfg->kind = TimerDomain::Kind::Advanced; + cfg.kind = TimerDomain::Kind::Advanced; } else { - if(cfg->timer_idx >= 0 && cfg->timer_idx <= 5) { + if(cfg.timer_idx >= 0 && cfg.timer_idx <= 5) { // general purpose timers 1 - } else if(cfg->timer_idx >= 6 && cfg->timer_idx <= 8) { + } else if(cfg.timer_idx >= 6 && cfg.timer_idx <= 8) { // general purpose timers 2 - } else if(cfg->timer_idx >= 9 && cfg->timer_idx <= 11) { + } else if(cfg.timer_idx >= 9 && cfg.timer_idx <= 11) { // general purpose timers 3 } else { - ErrorInRequestN("Unknown timer idx in reqidx", reqidx); + ST_LIB::compile_error("Unknown timer idx"); } - cfg->kind = TimerDomain::Kind::GeneralPurpose; + cfg.kind = TimerDomain::Kind::GeneralPurpose; } - } - #define DoTimer(request, reqint, reqidx) do{ \ - Config cfg; \ - if((request).name[0] == '\0') { \ - /* "Timer" + tostring(reqint) */ \ - cfg.name[0] = 'T'; \ - cfg.name[1] = 'i'; \ - cfg.name[2] = 'm'; \ - cfg.name[3] = 'e'; \ - cfg.name[4] = 'r'; \ - cfg.name[5] = (reqint/10) + '0'; \ - cfg.name[6] = (reqint%10) + '0'; \ - cfg.name[7] = '\0'; \ - } else { \ - for(int si = 0; si < 8; si++) { \ - cfg.name[si] = (request).name[si]; \ - } \ - } \ - cfg.timer_idx = timer_idxmap[reqint]; \ - cfg.prescaler = (request).prescaler; \ - cfg.period = (request).period; \ - cfg.deadtime = (request).deadtime; \ - cfg.polarity = (request).polarity; \ - cfg.negated_polarity = (request).negated_polarity; \ - check_timer(&cfg, request, i); \ - } while(0) + return cfg; + } public: enum PWM_MODE : uint8_t { @@ -393,7 +366,7 @@ struct TimerDomain { (requests[i].request < 1 || requests[i].request > 24 || (requests[i].request > 17 && requests[i].request < 23))) { - ErrorInRequestN("Invalid TimerRequest value for timer i", i); + ST_LIB::compile_error("Invalid TimerRequest value for timer"); } } @@ -402,12 +375,11 @@ struct TimerDomain { uint8_t reqint = static_cast(requests[i].request); if(reqint != static_cast(TimerRequest::AnyGeneralPurpose)) { if(used_timers[reqint]) { - ErrorInRequestN("Error: Timer already used. Error in request i", i); + ST_LIB::compile_error("Error: Timer already used"); } used_timers[reqint] = true; - Config cfg; - DoTimer(requests[i], reqint, i); + Config cfg = DoTimer(requests[i], reqint, i); cfgs[cfg_idx++] = cfg; // unordered remove (remaining requests is not used here so these are ordered) @@ -449,8 +421,7 @@ struct TimerDomain { if(e.request == AnyGeneralPurpose) { uint8_t reqint = remaining_timers[i]; // NOTE: I don't want to do an ordered remove so this has the real index - Config cfg; - DoTimer(requests[i], reqint, i); + Config cfg = DoTimer(requests[i], reqint, i); cfgs[cfg_idx++] = cfg; } } @@ -463,7 +434,7 @@ struct TimerDomain { TIM_TypeDef *tim; TIM_HandleTypeDef *hal_tim; char name[8]; - const TimerDomain::Kind kind; + TimerDomain::Kind kind; uint16_t timer_idx; void (*callback)(TimerDomain::Instance); @@ -573,7 +544,7 @@ struct TimerDomain { for(std::size_t i = 0; i < N; i++) { const Config &e = cfgs[i]; - TIM_HandleTypeDef *handle = &hal_handles[e.timer_idx]; + TIM_HandleTypeDef *handle = (TIM_HandleTypeDef*)&hal_handles[e.timer_idx]; handle->Instance = cmsis_timers[e.timer_idx]; handle->Init.Prescaler = e.prescaler; handle->Init.CounterMode = TIM_COUNTERMODE_UP; @@ -582,7 +553,7 @@ struct TimerDomain { handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; handle->Init.RepetitionCounter = 0; - TIM_TypeDef *tim = &cmsis_timers[e.timer_idx]; + TIM_TypeDef *tim = cmsis_timers[e.timer_idx]; tim->PSC = e.prescaler; tim->ARR = e.period; @@ -603,13 +574,18 @@ struct TimerDomain { // InputCapture stuff should be dome somewhere else.. // PWM stuff should be done somewhere else.. - instances[i] = Instance{ - .tim = &cmsis_timers[e.timer_idx], - .hal_tim = handle, - .name = {e.name[0], e.name[1], e.name[2], e.name[3], e.name[4], e.name[5], e.name[6], e.name[7]}, - .kind = e.kind, - .timer_idx = e.timer_idx, - }; + instances[i].tim = cmsis_timers[e.timer_idx]; + instances[i].hal_tim = handle; + instances[i].name[0] = e.name[0]; + instances[i].name[1] = e.name[1]; + instances[i].name[2] = e.name[2]; + instances[i].name[3] = e.name[3]; + instances[i].name[4] = e.name[4]; + instances[i].name[5] = e.name[5]; + instances[i].name[6] = e.name[6]; + instances[i].name[7] = e.name[7]; + instances[i].kind = e.kind; + instances[i].timer_idx = e.timer_idx; } } }; From 21ad65713d79ffd5a04ffac57948d34b2d71268c Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 14:03:26 +0100 Subject: [PATCH 236/281] try fix again --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 5cac56ae1..75f2c3dcf 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -338,8 +338,18 @@ struct TimerDomain { consteval Timer(std::array name = EMPTY_TIMER_NAME, TimerRequest request = TimerRequest::AnyGeneralPurpose, ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, - uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) : - e(name, request, pin, counting_mode, prescaler, period, deadtime, polarity, negated_polarity) {} + uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) + { + e.name = name; + e.request = request; + e.pin = pin; + e.counting_mode = counting_mode; + e.prescaler = prescaler; + e.period = period; + e.deadtime = deadtime; + e.polarity = polarity; + e.negated_polarity = negated_polarity; + } template consteval void inscribe(Ctx &ctx) const { @@ -443,9 +453,10 @@ struct TimerDomain { template struct TimerWrapper { - Instance& instance; + const Instance& instance; - TimerWrapper(Instance& inst) : instance(inst) {} + TimerWrapper(const Instance& inst) : instance(const_cast(inst)) {} + //TimerWrapper(const Instance& inst) : instance(inst) {} inline void counter_enable() { SET_BIT(instance.tim->CR1, TIM_CR1_CEN); From b3d0a00d63f7e47df4c28d3a31144c1d32ad7591 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 14:22:57 +0100 Subject: [PATCH 237/281] slowly but surely --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 75f2c3dcf..ef084d199 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -439,6 +439,8 @@ struct TimerDomain { return cfgs; } + template struct TimerWrapper; + // Runtime object struct Instance { TIM_TypeDef *tim; @@ -448,15 +450,17 @@ struct TimerDomain { uint16_t timer_idx; void (*callback)(TimerDomain::Instance); - template friend struct TimerWrapper; + template friend struct TimerWrapper; }; - template + template struct TimerWrapper { - const Instance& instance; + Instance& instance; - TimerWrapper(const Instance& inst) : instance(const_cast(inst)) {} - //TimerWrapper(const Instance& inst) : instance(inst) {} + //TimerWrapper(const Instance& inst) : instance(const_cast(inst)) {} + TimerWrapper(Instance& inst) { + this->instance = inst; + } inline void counter_enable() { SET_BIT(instance.tim->CR1, TIM_CR1_CEN); From 55ddb2cf54294423c6e27e69b0bdeeb86b0bcc87 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 14:25:20 +0100 Subject: [PATCH 238/281] Fix TimerWrapper constructor --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ef084d199..a2cb5dde9 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -457,10 +457,7 @@ struct TimerDomain { struct TimerWrapper { Instance& instance; - //TimerWrapper(const Instance& inst) : instance(const_cast(inst)) {} - TimerWrapper(Instance& inst) { - this->instance = inst; - } + TimerWrapper(Instance& inst) : instance(inst) {} inline void counter_enable() { SET_BIT(instance.tim->CR1, TIM_CR1_CEN); From 13a1ed1ac0e2eb7ec9535b03203c594d72581001 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 17:21:16 +0100 Subject: [PATCH 239/281] Add timer interrupt callbacks, use XList for TIM_HandleTypeDef definitions --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 81 ++++++++------------ Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 54 ++++++++++++- 2 files changed, 87 insertions(+), 48 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index a2cb5dde9..5c23637f4 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -20,22 +20,29 @@ // NOTE: only works for static arrays #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) -extern TIM_HandleTypeDef htim1; -extern TIM_HandleTypeDef htim2; -extern TIM_HandleTypeDef htim3; -extern TIM_HandleTypeDef htim4; -extern TIM_HandleTypeDef htim5; -extern TIM_HandleTypeDef htim6; -extern TIM_HandleTypeDef htim7; -extern TIM_HandleTypeDef htim8; -extern TIM_HandleTypeDef htim12; -extern TIM_HandleTypeDef htim13; -extern TIM_HandleTypeDef htim14; -extern TIM_HandleTypeDef htim15; -extern TIM_HandleTypeDef htim16; -extern TIM_HandleTypeDef htim17; -extern TIM_HandleTypeDef htim23; -extern TIM_HandleTypeDef htim24; +#define TimerXList \ + X(2, APB1LENR) \ + X(3, APB1LENR) \ + X(4, APB1LENR) \ + X(5, APB1LENR) \ + X(6, APB1LENR) \ + X(7, APB1LENR) \ + X(12, APB1LENR) \ + X(13, APB1LENR) \ + X(14, APB1LENR) \ + \ + X(23, APB1HENR) \ + X(24, APB1HENR) \ + \ + X(1, APB2ENR) \ + X(8, APB2ENR) \ + X(15, APB2ENR) \ + X(16, APB2ENR) \ + X(17, APB2ENR) + +#define X(n, b) extern TIM_HandleTypeDef htim##n; +TimerXList +#undef X /* Tim1 & Tim8 are advanced-control timers * their ARR & prescaler are 16bit @@ -188,10 +195,6 @@ struct TimerDomain { uint32_t negated_polarity; }; -private: - static void I_Need_To_Compile_TimerDomain_CPP(void); - - static constexpr TIM_HandleTypeDef *hal_handles[16] = { // general purpose timers &htim2, &htim3, &htim4, &htim5, &htim23, &htim24, @@ -218,35 +221,17 @@ struct TimerDomain { TIM1, TIM8 }; + static void I_Need_To_Compile_TimerDomain_CPP(void); + static inline void rcc_enable_timer(TIM_TypeDef *tim) { -#define TimerXList \ - X(TIM2, APB1LENR) \ - X(TIM3, APB1LENR) \ - X(TIM4, APB1LENR) \ - X(TIM5, APB1LENR) \ - X(TIM6, APB1LENR) \ - X(TIM7, APB1LENR) \ - X(TIM12, APB1LENR) \ - X(TIM13, APB1LENR) \ - X(TIM14, APB1LENR) \ - \ - X(TIM23, APB1HENR) \ - X(TIM24, APB1HENR) \ - \ - X(TIM1, APB2ENR) \ - X(TIM8, APB2ENR) \ - X(TIM15, APB2ENR) \ - X(TIM16, APB2ENR) \ - X(TIM17, APB2ENR) -#define X(t, b) \ - else if(tim == t) { SET_BIT(RCC->b, RCC_##b##_##t##EN); } +#define X(n, b) \ + else if(tim == TIM##n) { SET_BIT(RCC->b, RCC_##b##_TIM##n##EN); } if(false) {} TimerXList else { ErrorHandler("Invalid timer given to rcc_enable_timer"); } - #undef X } @@ -318,7 +303,6 @@ struct TimerDomain { return cfg; } -public: enum PWM_MODE : uint8_t { NORMAL = 0, PHASED = 1, @@ -443,16 +427,18 @@ struct TimerDomain { // Runtime object struct Instance { + char name[8]; TIM_TypeDef *tim; TIM_HandleTypeDef *hal_tim; - char name[8]; TimerDomain::Kind kind; uint16_t timer_idx; - void (*callback)(TimerDomain::Instance); template friend struct TimerWrapper; }; + static void (*callbacks[TimerDomain::max_instances])(void*); + static void *callback_data[TimerDomain::max_instances]; + template struct TimerWrapper { Instance& instance; @@ -494,11 +480,12 @@ struct TimerDomain { } template - inline void configure(void (*callback)()) { + inline void configure(void (*callback)(), void *callback_data) { if constexpr (psc != 0) { instance.tim->PSC = psc; } - instance.callback = callback; + TimerDomain::callbacks[this.timer_idx] = callback; + TimerDomain::callback_data[this.timer_idx] = callback_data; this.counter_enable(); } diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index faccd6d93..dce237602 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -1,5 +1,57 @@ #include "HALAL/Models/TimerDomain/TimerDomain.hpp" -void ST_LIB::TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { +using namespace ST_LIB; + +#define X(n, b) TIM_HandleTypeDef htim##n; +TimerXList +#undef X + +void TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { // Need to compile this file so I keep this symbol here } + +void (*TimerDomain::callbacks[TimerDomain::max_instances])(void*) = {nullptr}; +void *TimerDomain::callback_data[TimerDomain::max_instances] = {nullptr}; + +extern "C" void TIM1_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[1]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[1]](TimerDomain::callback_data[timer_idxmap[1]]); +} + +extern "C" void TIM2_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[2]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[2]](TimerDomain::callback_data[timer_idxmap[2]]); +} + +extern "C" void TIM3_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[3]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[3]](TimerDomain::callback_data[timer_idxmap[3]]); +} + +extern "C" void TIM4_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[4]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[4]](TimerDomain::callback_data[timer_idxmap[4]]); +} + +extern "C" void TIM5_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[5]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[5]](TimerDomain::callback_data[timer_idxmap[5]]); +} + +extern "C" void TIM6_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[6]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[6]](TimerDomain::callback_data[timer_idxmap[6]]); +} + +extern "C" void TIM7_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[7]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[7]](TimerDomain::callback_data[timer_idxmap[7]]); +} + +extern "C" void TIM8_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[8]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[8]](TimerDomain::callback_data[timer_idxmap[8]]); +} + + + From 664d84cefb1fcbecc149750c126a9639cd8767fb Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 18:52:34 +0100 Subject: [PATCH 240/281] try to choose 16 bit or 32 bit at compile time --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 280 +++++++++++-------- 1 file changed, 161 insertions(+), 119 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 5c23637f4..082f900a0 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -127,27 +127,28 @@ struct TimerDomain { /* The number corresponds with the timer nº */ enum TimerRequest : uint8_t { - Advanced1 = 1, - Advanced2 = 8, + Advanced_1 = 1, + Advanced_2 = 8, AnyGeneralPurpose = 0xFF, - GeneralPurpose1 = 2, - GeneralPurpose2 = 3, - GeneralPurpose3 = 4, - GeneralPurpose4 = 5, - GeneralPurpose5 = 23, - GeneralPurpose6 = 24, - - GeneralPurpose7 = 12, - GeneralPurpose8 = 13, - GeneralPurpose9 = 14, - - GeneralPurpose10 = 15, - GeneralPurpose11 = 16, - GeneralPurpose12 = 17, - - Basic1 = 6, - Basic2 = 7, + GeneralPurpose32bit_1 = 2, + GeneralPurpose32bit_2 = 3, + GeneralPurpose32bit_3 = 23, + GeneralPurpose32bit_4 = 24, + + GeneralPurpose_1 = 4, + GeneralPurpose_2 = 5, + + GeneralPurpose_3 = 12, + GeneralPurpose_4 = 13, + GeneralPurpose_5 = 14, + + GeneralPurpose_6 = 15, + GeneralPurpose_7 = 16, + GeneralPurpose_8 = 17, + + Basic_1 = 6, + Basic_2 = 7, }; enum CountingMode : uint8_t { @@ -280,10 +281,10 @@ struct TimerDomain { } } - if(request.request == Basic1 || request.request == Basic2) { + if(request.request == Basic_1 || request.request == Basic_2) { // basic timers cfg.kind = TimerDomain::Kind::Basic; - } else if(request.request == Advanced1 || request.request == Advanced2) { + } else if(request.request == Advanced_1 || request.request == Advanced_2) { // advanced timers cfg.kind = TimerDomain::Kind::Advanced; } else { @@ -423,8 +424,6 @@ struct TimerDomain { return cfgs; } - template struct TimerWrapper; - // Runtime object struct Instance { char name[8]; @@ -439,102 +438,6 @@ struct TimerDomain { static void (*callbacks[TimerDomain::max_instances])(void*); static void *callback_data[TimerDomain::max_instances]; - template - struct TimerWrapper { - Instance& instance; - - TimerWrapper(Instance& inst) : instance(inst) {} - - inline void counter_enable() { - SET_BIT(instance.tim->CR1, TIM_CR1_CEN); - } - inline void counter_disable() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_CEN); - } - - inline void clear_update_interrupt_flag() { - CLEAR_BIT(instance.tim->SR, TIM_SR_UIF); - } - - /* Enabled by default */ - inline void enable_update_interrupt() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); - } - inline void disable_update_interrupt() { - SET_BIT(instance.tim->CR1, TIM_CR1_UDIS); - } - - /* interrupt gets called only once, counter needs to be reenabled */ - inline void set_one_pulse_mode() { - SET_BIT(instance.tim->CR1, TIM_CR1_OPM); - } - inline void multi_interrupt() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_OPM); - } - - inline TIM_HandleTypeDef *get_hal_handle() { - return instance.hal_tim; - } - inline TIM_TypeDef *get_cmsis_handle() { - return instance.tim; - } - - template - inline void configure(void (*callback)(), void *callback_data) { - if constexpr (psc != 0) { - instance.tim->PSC = psc; - } - TimerDomain::callbacks[this.timer_idx] = callback; - TimerDomain::callback_data[this.timer_idx] = callback_data; - this.counter_enable(); - } - - // 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; - } - -#if 0 - if constexpr (dev.e.request == TimerRequest::Advanced1 || dev.e.request == TimerRequest::Advanced2) { - // advanced specific functions - } - - if constexpr (dev.e.request != TimerRequest::Basic1 && dev.e.request != TimerRequest::Basic2) { - // general purpose and advanced functions - } -#endif - - /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ - template - inline void set_mode(void) { - constexpr uint8_t reqint = static_cast(dev.e.request); - if constexpr (!(reqint == 1 || reqint == 8 || - reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || - reqint == 3 || reqint == 4)) - { - ST_LIB::compile_error("Error: In request reqidx: Timers other than {Advanced{TIM1, TIM8}, TIM2, TIM3, TIM4, TIM5, TIM23, TIM24} only support upcounting"); - return; - } - - if constexpr (mode == CountingMode::UP) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); - CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == CountingMode::DOWN) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); - SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); - } - } - }; - template struct Init { static inline std::array instances{}; @@ -589,6 +492,145 @@ struct TimerDomain { } }; }; + +template +concept Bits32Timer = requires (const TimerDomain::Timer &dev) { + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_1) || + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_2) || + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_3) || + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_4); +}; +template +concept Bits16Timer = requires (const TimerDomain::Timer &dev) { + !((dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_1) || + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_2) || + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_3) || + (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_4)); +}; + +template +struct TimerWrapper { + TimerDomain::Instance& instance; + TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} + + inline void counter_enable() { + SET_BIT(instance.tim->CR1, TIM_CR1_CEN); + } + inline void counter_disable() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_CEN); + } + + inline void clear_update_interrupt_flag() { + CLEAR_BIT(instance.tim->SR, TIM_SR_UIF); + } + + /* Enabled by default */ + inline void enable_update_interrupt() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); + } + inline void disable_update_interrupt() { + SET_BIT(instance.tim->CR1, TIM_CR1_UDIS); + } + + /* interrupt gets called only once, counter needs to be reenabled */ + inline void set_one_pulse_mode() { + SET_BIT(instance.tim->CR1, TIM_CR1_OPM); + } + inline void multi_interrupt() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_OPM); + } + + inline TIM_HandleTypeDef *get_hal_handle() { + return instance.hal_tim; + } + inline TIM_TypeDef *get_cmsis_handle() { + return instance.tim; + } + +#if 1 + template requires Bits32Timer + inline void configure(void (*callback)(void*), void *callback_data, uint32_t period) + { + if constexpr (psc != 0) { + instance.tim->PSC = psc; + } + TimerDomain::callbacks[instance.timer_idx] = callback; + TimerDomain::callback_data[instance.timer_idx] = callback_data; + this->counter_enable(); + } + + template requires Bits16Timer + inline void configure(void (*callback)(void*), void *callback_data, uint16_t period) + { + if constexpr (psc != 0) { + instance.tim->PSC = psc; + } + TimerDomain::callbacks[instance.timer_idx] = callback; + TimerDomain::callback_data[instance.timer_idx] = callback_data; + this->counter_enable(); + } +#else + template + inline void configure(void (*callback)(void*), void *callback_data, uint32_t period) { + constexpr uint8_t reqint = static_cast(dev.e.request); + constexpr bool bits32timer = (reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24); + if constexpr (!bits32timer) { + if(period > 0xFFFF) { + ErrorHandler("Only Timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); + } + } + if constexpr (psc != 0) { + instance.tim->PSC = psc; + } + TimerDomain::callbacks[instance.timer_idx] = callback; + TimerDomain::callback_data[instance.timer_idx] = callback_data; + this->counter_enable(); + } +#endif + + // 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; + } + +#if 0 + if constexpr (dev.e.request == TimerDomain::TimerRequest::Advanced_1 || dev.e.request == TimerDomain::TimerRequest::Advanced_2) { + // advanced specific functions + } + + if constexpr (dev.e.request != TimerDomain::TimerRequest::Basic_1 && dev.e.request != TimerDomain::TimerRequest::Basic_2) { + // general purpose and advanced functions + } +#endif + + /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ + template + inline void set_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), + "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) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == TimerDomain::CountingMode::DOWN) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } + } +}; + } // namespace ST_LIB #endif // HAL_TIM_MODULE_ENABLED From 2bab97d27e4cae667d743737de9d19ac3595bb8e Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 20:43:08 +0100 Subject: [PATCH 241/281] Fix compilation issues --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 105 +++++++------------ 1 file changed, 40 insertions(+), 65 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 082f900a0..e7733090b 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -121,35 +121,36 @@ constexpr std::array create_timer_idxmap() { static constexpr std::array timer_idxmap = create_timer_idxmap(); +/* The number corresponds with the timer nº */ +enum TimerRequest : uint8_t { + Advanced_1 = 1, + Advanced_2 = 8, + + AnyGeneralPurpose = 0xFF, + GeneralPurpose32bit_1 = 2, + GeneralPurpose32bit_2 = 3, + GeneralPurpose32bit_3 = 23, + GeneralPurpose32bit_4 = 24, + + GeneralPurpose_1 = 4, + GeneralPurpose_2 = 5, + + GeneralPurpose_3 = 12, + GeneralPurpose_4 = 13, + GeneralPurpose_5 = 14, + + GeneralPurpose_6 = 15, + GeneralPurpose_7 = 16, + GeneralPurpose_8 = 17, + + Basic_1 = 6, + Basic_2 = 7, +}; + struct TimerDomain { // There are 16 timers static constexpr std::size_t max_instances = 16; - /* The number corresponds with the timer nº */ - enum TimerRequest : uint8_t { - Advanced_1 = 1, - Advanced_2 = 8, - - AnyGeneralPurpose = 0xFF, - GeneralPurpose32bit_1 = 2, - GeneralPurpose32bit_2 = 3, - GeneralPurpose32bit_3 = 23, - GeneralPurpose32bit_4 = 24, - - GeneralPurpose_1 = 4, - GeneralPurpose_2 = 5, - - GeneralPurpose_3 = 12, - GeneralPurpose_4 = 13, - GeneralPurpose_5 = 14, - - GeneralPurpose_6 = 15, - GeneralPurpose_7 = 16, - GeneralPurpose_8 = 17, - - Basic_1 = 6, - Basic_2 = 7, - }; enum CountingMode : uint8_t { UP = 0, @@ -493,21 +494,6 @@ struct TimerDomain { }; }; -template -concept Bits32Timer = requires (const TimerDomain::Timer &dev) { - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_1) || - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_2) || - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_3) || - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_4); -}; -template -concept Bits16Timer = requires (const TimerDomain::Timer &dev) { - !((dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_1) || - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_2) || - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_3) || - (dev.e.request == TimerDomain::TimerRequest::GeneralPurpose32bit_4)); -}; - template struct TimerWrapper { TimerDomain::Instance& instance; @@ -547,21 +533,17 @@ struct TimerWrapper { return instance.tim; } -#if 1 - template requires Bits32Timer - inline void configure(void (*callback)(void*), void *callback_data, uint32_t period) + template + inline void configure32bit(void (*callback)(void*), void *callback_data, uint32_t period) { - if constexpr (psc != 0) { - instance.tim->PSC = psc; - } - TimerDomain::callbacks[instance.timer_idx] = callback; - TimerDomain::callback_data[instance.timer_idx] = callback_data; - this->counter_enable(); - } + constexpr bool bits32timer = ( + dev.e.request == TimerRequest::GeneralPurpose32bit_1 || + dev.e.request == TimerRequest::GeneralPurpose32bit_2 || + dev.e.request == TimerRequest::GeneralPurpose32bit_3 || + dev.e.request == TimerRequest::GeneralPurpose32bit_4 + ); + static_assert(bits32timer, "Only timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); - template requires Bits16Timer - inline void configure(void (*callback)(void*), void *callback_data, uint16_t period) - { if constexpr (psc != 0) { instance.tim->PSC = psc; } @@ -569,16 +551,10 @@ struct TimerWrapper { TimerDomain::callback_data[instance.timer_idx] = callback_data; this->counter_enable(); } -#else + template - inline void configure(void (*callback)(void*), void *callback_data, uint32_t period) { - constexpr uint8_t reqint = static_cast(dev.e.request); - constexpr bool bits32timer = (reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24); - if constexpr (!bits32timer) { - if(period > 0xFFFF) { - ErrorHandler("Only Timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); - } - } + inline void configure16bit(void (*callback)(void*), void *callback_data, uint16_t period) + { if constexpr (psc != 0) { instance.tim->PSC = psc; } @@ -586,7 +562,6 @@ struct TimerWrapper { TimerDomain::callback_data[instance.timer_idx] = callback_data; this->counter_enable(); } -#endif // leftover from old TimerPeripheral, maybe this was useful? inline uint16_t get_prescaler() { @@ -597,11 +572,11 @@ struct TimerWrapper { } #if 0 - if constexpr (dev.e.request == TimerDomain::TimerRequest::Advanced_1 || dev.e.request == TimerDomain::TimerRequest::Advanced_2) { + if constexpr (dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2) { // advanced specific functions } - if constexpr (dev.e.request != TimerDomain::TimerRequest::Basic_1 && dev.e.request != TimerDomain::TimerRequest::Basic_2) { + if constexpr (dev.e.request != TimerRequest::Basic_1 && dev.e.request != TimerRequest::Basic_2) { // general purpose and advanced functions } #endif From 7b83c048acf8499507ac6f7098dfd041eec3bf39 Mon Sep 17 00:00:00 2001 From: victhor Date: Sun, 28 Dec 2025 21:38:16 +0100 Subject: [PATCH 242/281] Fix overflow calculation and a test --- Src/HALAL/Services/Time/Scheduler.cpp | 9 ++++++--- Tests/Time/scheduler_test.cpp | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index f6d3cf9fb..c4909b3d5 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -261,17 +261,20 @@ void Scheduler::schedule_next_interval() { return; } - Scheduler::global_timer_enable(); uint8_t next_id = Scheduler::front_id(); // sorted_task_ids_[0] Task& next_task = tasks_[next_id]; int32_t diff = (int32_t)(next_task.next_fire_us - static_cast(global_tick_us_)); - if (diff <= 1) [[unlikely]]{ + if (diff >= -1 && diff <= 1) [[unlikely]] { current_interval_us_ = 1; Scheduler_global_timer->ARR = 1; Scheduler_global_timer->CNT = 1; Scheduler::global_timer_enable(); } else { - current_interval_us_ = static_cast(diff); + if (diff < -1) [[unlikely]]{ + current_interval_us_ = static_cast(0 - diff); + } else { + current_interval_us_ = static_cast(diff); + } configure_timer_for_interval(current_interval_us_); } } diff --git a/Tests/Time/scheduler_test.cpp b/Tests/Time/scheduler_test.cpp index f32f13639..e1cc34435 100644 --- a/Tests/Time/scheduler_test.cpp +++ b/Tests/Time/scheduler_test.cpp @@ -213,6 +213,7 @@ TEST_F(SchedulerTests, SameTaskMultipleTimes) { multiple_tasks #undef X + multiple_task1count = 0; Scheduler::start(); TIM2_BASE->PSC = 2; // quicker test constexpr int NUM_TICKS = 300; From cb0bbd7a4e8029d380f1069c3759a9c1576af830 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 19:15:12 +0100 Subject: [PATCH 243/281] Fix all remaining issues --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 117 ++++++++++++++----- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 40 ++++++- 2 files changed, 127 insertions(+), 30 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index e7733090b..f684296ea 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -7,6 +7,10 @@ #pragma once +/* WARNING: Timer 15 TIM15 TIM 15 Timer15 + * is currently not working. Don't use it until this warning is removed + */ + #include "stm32h7xx_hal.h" //#include "stm32h7xx_hal_tim.h" #ifdef HAL_TIM_MODULE_ENABLED @@ -20,7 +24,7 @@ // NOTE: only works for static arrays #define ARRAY_LENGTH(a) (sizeof(a)/sizeof(*a)) -#define TimerXList \ +#define TimerXList \ X(2, APB1LENR) \ X(3, APB1LENR) \ X(4, APB1LENR) \ @@ -30,10 +34,10 @@ X(12, APB1LENR) \ X(13, APB1LENR) \ X(14, APB1LENR) \ - \ + \ X(23, APB1HENR) \ X(24, APB1HENR) \ - \ + \ X(1, APB2ENR) \ X(8, APB2ENR) \ X(15, APB2ENR) \ @@ -135,13 +139,13 @@ enum TimerRequest : uint8_t { GeneralPurpose_1 = 4, GeneralPurpose_2 = 5, - GeneralPurpose_3 = 12, - GeneralPurpose_4 = 13, - GeneralPurpose_5 = 14, + SlaveTimer_1 = 12, + SlaveTimer_2 = 13, + SlaveTimer_3 = 14, - GeneralPurpose_6 = 15, - GeneralPurpose_7 = 16, - GeneralPurpose_8 = 17, + GeneralPurpose_3 = 15, + GeneralPurpose_4 = 16, + GeneralPurpose_5 = 17, Basic_1 = 6, Basic_2 = 7, @@ -151,7 +155,6 @@ struct TimerDomain { // There are 16 timers static constexpr std::size_t max_instances = 16; - enum CountingMode : uint8_t { UP = 0, DOWN = 1, @@ -223,6 +226,21 @@ struct TimerDomain { TIM1, TIM8 }; + static constexpr IRQn_Type timer_irqn[] = { + // general purpose timers 1 + TIM2_IRQn, TIM3_IRQn, TIM4_IRQn, TIM5_IRQn, TIM23_IRQn, TIM24_IRQn, + // slave timers + TIM8_BRK_TIM12_IRQn, TIM8_UP_TIM13_IRQn, TIM8_TRG_COM_TIM14_IRQn, + // general purpose timers 2 + TIM15_IRQn, TIM16_IRQn, TIM17_IRQn, + + // basic timers + TIM6_DAC_IRQn, /* TIM6 global and DAC1&2 underrun error interrupts */ + TIM7_IRQn, + + TIM1_UP_IRQn, TIM8_UP_TIM13_IRQn + }; + static void I_Need_To_Compile_TimerDomain_CPP(void); static inline void rcc_enable_timer(TIM_TypeDef *tim) { @@ -384,12 +402,15 @@ struct TimerDomain { } } + /* NOTE: timers {TIM12, TIM13, TIM14} are also 16 bit but + * they are used as slave timers to tim8 + */ // 32 bit timers, very important for scheduler uint8_t bits32_timers[] = {2, 5, 23, 24}; // can use any CountingMode (32 bit timers can also but they are higher priority) uint8_t up_down_updown_timers[] = {3, 4}; // 16 bit timers - uint8_t bits16_timers[] = {12, 13, 14, 15, 16, 17}; + uint8_t bits16_timers[] = {16, 17}; uint8_t remaining_timers[15] = {0}; uint8_t count_remaining_timers = 0; @@ -460,9 +481,10 @@ struct TimerDomain { tim->PSC = e.prescaler; tim->ARR = e.period; - if(e.counting_mode == CountingMode::UP) { + /* if(e.counting_mode == CountingMode::UP) { CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter - } else if(e.counting_mode == CountingMode::DOWN) { + } 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); @@ -477,18 +499,20 @@ struct TimerDomain { // InputCapture stuff should be dome somewhere else.. // PWM stuff should be done somewhere else.. - instances[i].tim = cmsis_timers[e.timer_idx]; - instances[i].hal_tim = handle; - instances[i].name[0] = e.name[0]; - instances[i].name[1] = e.name[1]; - instances[i].name[2] = e.name[2]; - instances[i].name[3] = e.name[3]; - instances[i].name[4] = e.name[4]; - instances[i].name[5] = e.name[5]; - instances[i].name[6] = e.name[6]; - instances[i].name[7] = e.name[7]; - instances[i].kind = e.kind; - instances[i].timer_idx = e.timer_idx; + Instance *inst = &instances[i]; + inst->tim = cmsis_timers[e.timer_idx]; + inst->hal_tim = handle; + inst->name[0] = e.name[0]; + inst->name[1] = e.name[1]; + inst->name[2] = e.name[2]; + inst->name[3] = e.name[3]; + inst->name[4] = e.name[4]; + inst->name[5] = e.name[5]; + inst->name[6] = e.name[6]; + inst->name[7] = e.name[7]; + inst->kind = e.kind; + inst->timer_idx = e.timer_idx; + __NOP(); } } }; @@ -510,14 +534,51 @@ struct TimerWrapper { CLEAR_BIT(instance.tim->SR, TIM_SR_UIF); } - /* Enabled by default */ + /* Disabled by default */ inline void enable_update_interrupt() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); + SET_BIT(instance.tim->DIER, TIM_DIER_UIE); } inline void disable_update_interrupt() { + CLEAR_BIT(instance.tim->DIER, TIM_DIER_UIE); + } + + /* Disabled by default */ + inline void enable_nvic() { + NVIC_EnableIRQ(TimerDomain::timer_irqn[instance.timer_idx]); + } + inline void disable_nvic() { + NVIC_DisableIRQ(TimerDomain::timer_irqn[instance.timer_idx]); + } + + /* Enable UEV. The Update (UEV) event is generated by one of the following events: + * – Counter overflow/underflow + * – Setting the UG bit + * – Update generation through the slave mode controller + * Enabled by default + */ + inline void enable_update_event() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); + } + /* Disable UEV. The Update event is not generated, shadow registers keep their value + * (ARR, PSC, CCRx). However the counter and the prescaler are reinitialized if the UG bit + * is set or if a hardware reset is received from the slave mode controller. + */ + inline void disable_update_event() { SET_BIT(instance.tim->CR1, TIM_CR1_UDIS); } + /* default: disabled */ + inline void break_interrupt_enable() { + static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2, + "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); + ErrorHandler("Break interrupt is not allowed currently because gp timers {TIM12, TIM13, TIM14} use the same interrupt callback"); + } + inline void break_interrupt_disable() { + static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2, + "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); + SET_BIT(instance.tim->DIER, TIM_DIER_BIE); + } + /* interrupt gets called only once, counter needs to be reenabled */ inline void set_one_pulse_mode() { SET_BIT(instance.tim->CR1, TIM_CR1_OPM); @@ -547,6 +608,7 @@ struct TimerWrapper { 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(); @@ -558,6 +620,7 @@ struct TimerWrapper { 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(); diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index dce237602..2877af087 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -13,7 +13,7 @@ void TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { void (*TimerDomain::callbacks[TimerDomain::max_instances])(void*) = {nullptr}; void *TimerDomain::callback_data[TimerDomain::max_instances] = {nullptr}; -extern "C" void TIM1_IRQHandler(void) { +extern "C" void TIM1_UP_IRQHandler(void) { CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[1]]->SR, TIM_SR_UIF); TimerDomain::callbacks[timer_idxmap[1]](TimerDomain::callback_data[timer_idxmap[1]]); } @@ -38,7 +38,7 @@ extern "C" void TIM5_IRQHandler(void) { TimerDomain::callbacks[timer_idxmap[5]](TimerDomain::callback_data[timer_idxmap[5]]); } -extern "C" void TIM6_IRQHandler(void) { +extern "C" void TIM6_DAC_IRQHandler(void) { CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[6]]->SR, TIM_SR_UIF); TimerDomain::callbacks[timer_idxmap[6]](TimerDomain::callback_data[timer_idxmap[6]]); } @@ -48,10 +48,44 @@ extern "C" void TIM7_IRQHandler(void) { TimerDomain::callbacks[timer_idxmap[7]](TimerDomain::callback_data[timer_idxmap[7]]); } -extern "C" void TIM8_IRQHandler(void) { +/* NOTE: If it is needed, make changes so there's a specific callback for + * tim8 which takes an int or something to know from which interrupt + * it was called / make 3 callbacks +*/ +extern "C" void TIM8_BRK_TIM12_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[8]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[8]](TimerDomain::callback_data[timer_idxmap[8]]); +} +extern "C" void TIM8_UP_TIM13_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[8]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[8]](TimerDomain::callback_data[timer_idxmap[8]]); +} +extern "C" void TIM8_TRG_COM_TIM14_IRQHandler(void) { CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[8]]->SR, TIM_SR_UIF); TimerDomain::callbacks[timer_idxmap[8]](TimerDomain::callback_data[timer_idxmap[8]]); } +extern "C" void TIM15_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[8]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[8]](TimerDomain::callback_data[timer_idxmap[8]]); +} + +extern "C" void TIM16_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[16]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[16]](TimerDomain::callback_data[timer_idxmap[16]]); +} +extern "C" void TIM17_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[17]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[17]](TimerDomain::callback_data[timer_idxmap[17]]); +} +extern "C" void TIM23_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[23]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[23]](TimerDomain::callback_data[timer_idxmap[23]]); +} + +extern "C" void TIM24_IRQHandler(void) { + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[24]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[24]](TimerDomain::callback_data[timer_idxmap[24]]); +} From d7ec7c63eb4ccff21d9616555a010e84022c6a30 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 19:21:03 +0100 Subject: [PATCH 244/281] Change TimerRequest values --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 42 ++++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index f684296ea..ac080fdf6 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -128,27 +128,27 @@ static constexpr std::array timer_idxmap = create_timer_idxmap(); /* The number corresponds with the timer nº */ enum TimerRequest : uint8_t { Advanced_1 = 1, - Advanced_2 = 8, + Advanced_8 = 8, AnyGeneralPurpose = 0xFF, - GeneralPurpose32bit_1 = 2, - GeneralPurpose32bit_2 = 3, - GeneralPurpose32bit_3 = 23, - GeneralPurpose32bit_4 = 24, + GeneralPurpose32bit_2 = 2, + GeneralPurpose32bit_3 = 3, + GeneralPurpose32bit_23 = 23, + GeneralPurpose32bit_24 = 24, - GeneralPurpose_1 = 4, - GeneralPurpose_2 = 5, + GeneralPurpose_4 = 4, + GeneralPurpose_5 = 5, - SlaveTimer_1 = 12, - SlaveTimer_2 = 13, - SlaveTimer_3 = 14, + SlaveTimer_12 = 12, + SlaveTimer_13 = 13, + SlaveTimer_14 = 14, - GeneralPurpose_3 = 15, - GeneralPurpose_4 = 16, - GeneralPurpose_5 = 17, + GeneralPurpose_15 = 15, + GeneralPurpose_16 = 16, + GeneralPurpose_17 = 17, - Basic_1 = 6, - Basic_2 = 7, + Basic_6 = 6, + Basic_7 = 7, }; struct TimerDomain { @@ -300,10 +300,10 @@ struct TimerDomain { } } - if(request.request == Basic_1 || request.request == Basic_2) { + if(request.request == Basic_6 || request.request == Basic_7) { // basic timers cfg.kind = TimerDomain::Kind::Basic; - } else if(request.request == Advanced_1 || request.request == Advanced_2) { + } else if(request.request == Advanced_1 || request.request == Advanced_8) { // advanced timers cfg.kind = TimerDomain::Kind::Advanced; } else { @@ -569,12 +569,12 @@ struct TimerWrapper { /* default: disabled */ inline void break_interrupt_enable() { - static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2, + static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); ErrorHandler("Break interrupt is not allowed currently because gp timers {TIM12, TIM13, TIM14} use the same interrupt callback"); } inline void break_interrupt_disable() { - static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2, + static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); SET_BIT(instance.tim->DIER, TIM_DIER_BIE); } @@ -598,10 +598,10 @@ struct TimerWrapper { inline void configure32bit(void (*callback)(void*), void *callback_data, uint32_t period) { constexpr bool bits32timer = ( - dev.e.request == TimerRequest::GeneralPurpose32bit_1 || dev.e.request == TimerRequest::GeneralPurpose32bit_2 || dev.e.request == TimerRequest::GeneralPurpose32bit_3 || - dev.e.request == TimerRequest::GeneralPurpose32bit_4 + dev.e.request == TimerRequest::GeneralPurpose32bit_23 || + dev.e.request == TimerRequest::GeneralPurpose32bit_24 ); static_assert(bits32timer, "Only timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); From 401832f13b84b31f5b333ad8b4393d7fc8c8d42b Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 19:36:49 +0100 Subject: [PATCH 245/281] Remove temporary function --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 -- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 4 ---- 2 files changed, 6 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ac080fdf6..76ddd3a74 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -241,8 +241,6 @@ struct TimerDomain { TIM1_UP_IRQn, TIM8_UP_TIM13_IRQn }; - static void I_Need_To_Compile_TimerDomain_CPP(void); - static inline void rcc_enable_timer(TIM_TypeDef *tim) { #define X(n, b) \ else if(tim == TIM##n) { SET_BIT(RCC->b, RCC_##b##_TIM##n##EN); } diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index 2877af087..b61c07210 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -6,10 +6,6 @@ using namespace ST_LIB; TimerXList #undef X -void TimerDomain::I_Need_To_Compile_TimerDomain_CPP(void) { - // Need to compile this file so I keep this symbol here -} - void (*TimerDomain::callbacks[TimerDomain::max_instances])(void*) = {nullptr}; void *TimerDomain::callback_data[TimerDomain::max_instances] = {nullptr}; From 7a2ac9add71600d0d0d10c90ed0635706034c8b9 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 19:48:51 +0100 Subject: [PATCH 246/281] fix: Remove static assert --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 76ddd3a74..df563b9c1 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -462,7 +462,6 @@ struct TimerDomain { 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 Config &e = cfgs[i]; From 3085cda039271c1ac53e27e307cae2956de4d30d Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 20:48:27 +0100 Subject: [PATCH 247/281] fix: Change order of parameters --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index df563b9c1..a10416eff 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -337,8 +337,9 @@ struct TimerDomain { using domain = TimerDomain; Entry e; - consteval Timer(std::array name = EMPTY_TIMER_NAME, TimerRequest request = TimerRequest::AnyGeneralPurpose, - ST_LIB::GPIODomain::Pin *pin = 0, TimerDomain::CountingMode counting_mode = CountingMode::UP, + consteval Timer(TimerRequest request = TimerRequest::AnyGeneralPurpose, + TimerDomain::CountingMode counting_mode = CountingMode::UP, std::array name = EMPTY_TIMER_NAME, + ST_LIB::GPIODomain::Pin *pin = 0, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) { From fda8cf7f2c91d36cb55c5a9aa80054f3fa386e86 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 20:58:21 +0100 Subject: [PATCH 248/281] fix: timer 15 (hopefully?) --- Src/HALAL/Models/TimerDomain/TimerDomain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp index b61c07210..90a3709ba 100644 --- a/Src/HALAL/Models/TimerDomain/TimerDomain.cpp +++ b/Src/HALAL/Models/TimerDomain/TimerDomain.cpp @@ -62,8 +62,8 @@ extern "C" void TIM8_TRG_COM_TIM14_IRQHandler(void) { } extern "C" void TIM15_IRQHandler(void) { - CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[8]]->SR, TIM_SR_UIF); - TimerDomain::callbacks[timer_idxmap[8]](TimerDomain::callback_data[timer_idxmap[8]]); + CLEAR_BIT(TimerDomain::cmsis_timers[timer_idxmap[15]]->SR, TIM_SR_UIF); + TimerDomain::callbacks[timer_idxmap[15]](TimerDomain::callback_data[timer_idxmap[15]]); } extern "C" void TIM16_IRQHandler(void) { From 7d2835364522ee2ade5643216b2f161009ba1db5 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 22:18:26 +0100 Subject: [PATCH 249/281] fix: Rollback removal of tim15 when getting AnyGeneralPurpose timer --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index a10416eff..0ccb9de53 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -7,10 +7,6 @@ #pragma once -/* WARNING: Timer 15 TIM15 TIM 15 Timer15 - * is currently not working. Don't use it until this warning is removed - */ - #include "stm32h7xx_hal.h" //#include "stm32h7xx_hal_tim.h" #ifdef HAL_TIM_MODULE_ENABLED @@ -409,7 +405,7 @@ struct TimerDomain { // can use any CountingMode (32 bit timers can also but they are higher priority) uint8_t up_down_updown_timers[] = {3, 4}; // 16 bit timers - uint8_t bits16_timers[] = {16, 17}; + uint8_t bits16_timers[] = {15, 16, 17}; uint8_t remaining_timers[15] = {0}; uint8_t count_remaining_timers = 0; From 021a9aef1be0f209cd0fb5b95b7ba0cbba02c44a Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 29 Dec 2025 22:43:54 +0100 Subject: [PATCH 250/281] fix: pins are now part of TimerWrapper, not TimerDomain --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 75 +++++++++++--------- 1 file changed, 41 insertions(+), 34 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 0ccb9de53..83cdcd79a 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -92,6 +92,32 @@ TimerXList namespace ST_LIB { extern void compile_error(const char *msg); +/* The number corresponds with the timer nº */ +enum TimerRequest : uint8_t { + Advanced_1 = 1, + Advanced_8 = 8, + + AnyGeneralPurpose = 0xFF, + GeneralPurpose32bit_2 = 2, + GeneralPurpose32bit_3 = 3, + GeneralPurpose32bit_23 = 23, + GeneralPurpose32bit_24 = 24, + + GeneralPurpose_4 = 4, + GeneralPurpose_5 = 5, + + SlaveTimer_12 = 12, + SlaveTimer_13 = 13, + SlaveTimer_14 = 14, + + GeneralPurpose_15 = 15, + GeneralPurpose_16 = 16, + GeneralPurpose_17 = 17, + + Basic_6 = 6, + Basic_7 = 7, +}; + constexpr std::array create_timer_idxmap() { std::array result{}; @@ -121,32 +147,6 @@ constexpr std::array create_timer_idxmap() { static constexpr std::array timer_idxmap = create_timer_idxmap(); -/* The number corresponds with the timer nº */ -enum TimerRequest : uint8_t { - Advanced_1 = 1, - Advanced_8 = 8, - - AnyGeneralPurpose = 0xFF, - GeneralPurpose32bit_2 = 2, - GeneralPurpose32bit_3 = 3, - GeneralPurpose32bit_23 = 23, - GeneralPurpose32bit_24 = 24, - - GeneralPurpose_4 = 4, - GeneralPurpose_5 = 5, - - SlaveTimer_12 = 12, - SlaveTimer_13 = 13, - SlaveTimer_14 = 14, - - GeneralPurpose_15 = 15, - GeneralPurpose_16 = 16, - GeneralPurpose_17 = 17, - - Basic_6 = 6, - Basic_7 = 7, -}; - struct TimerDomain { // There are 16 timers static constexpr std::size_t max_instances = 16; @@ -174,7 +174,6 @@ struct TimerDomain { struct Entry { std::array name; /* max length = 7 */ TimerRequest request; - ST_LIB::GPIODomain::Pin *pin; TimerDomain::CountingMode counting_mode; uint16_t prescaler; uint32_t period; @@ -187,7 +186,6 @@ struct TimerDomain { char name[8]; /* "Timerxx\0" */ TimerDomain::Kind kind; uint16_t timer_idx; - ST_LIB::GPIODomain::Pin *asociated_pin; TimerDomain::CountingMode counting_mode; uint32_t prescaler; uint32_t period; @@ -335,13 +333,11 @@ struct TimerDomain { consteval Timer(TimerRequest request = TimerRequest::AnyGeneralPurpose, TimerDomain::CountingMode counting_mode = CountingMode::UP, std::array name = EMPTY_TIMER_NAME, - ST_LIB::GPIODomain::Pin *pin = 0, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) { e.name = name; e.request = request; - e.pin = pin; e.counting_mode = counting_mode; e.prescaler = prescaler; e.period = period; @@ -448,8 +444,6 @@ struct TimerDomain { TIM_HandleTypeDef *hal_tim; TimerDomain::Kind kind; uint16_t timer_idx; - - template friend struct TimerWrapper; }; static void (*callbacks[TimerDomain::max_instances])(void*); @@ -512,11 +506,24 @@ struct TimerDomain { }; }; -template +// Alternate functions for timers +enum TimerAF { + PWM, +}; + +struct TimerPin { + TimerAF af; + ST_LIB::GPIODomain::Pin pin; +}; + +template struct TimerWrapper { + static constexpr size_t PIN_COUNT = sizeof...(PinArgs); + static constexpr std::array pins = {PinArgs...}; + TimerDomain::Instance& instance; TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} - + inline void counter_enable() { SET_BIT(instance.tim->CR1, TIM_CR1_CEN); } From 7aade1f04681e9738afe848f21872ec790fb90e6 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 30 Dec 2025 13:14:54 +0100 Subject: [PATCH 251/281] fix: Split TimerWrapper into a different file: TimerWrapper.hpp --- Inc/HALAL/HALAL.hpp | 5 +- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 167 +---------------- Inc/HALAL/Services/Time/TimerWrapper.hpp | 185 +++++++++++++++++++ 3 files changed, 187 insertions(+), 170 deletions(-) create mode 100644 Inc/HALAL/Services/Time/TimerWrapper.hpp diff --git a/Inc/HALAL/HALAL.hpp b/Inc/HALAL/HALAL.hpp index 72ce03845..9bea3a79f 100644 --- a/Inc/HALAL/HALAL.hpp +++ b/Inc/HALAL/HALAL.hpp @@ -20,8 +20,7 @@ #include "HALAL/Services/PWM/PhasedPWM/PhasedPWM.hpp" #include "HALAL/Services/PWM/DualPhasedPWM/DualPhasedPWM.hpp" -//#include "HALAL/Services/Time/Time.hpp" -#include "HALAL/Models/TimerDomain/TimerDomain.hpp" +#include "HALAL/Services/Time/TimerWrapper.hpp" #include "HALAL/Services/Time/Scheduler.hpp" #include "HALAL/Services/Time/RTC.hpp" @@ -41,8 +40,6 @@ #include "HALAL/Services/InfoWarning/InfoWarning.hpp" #include "HALAL/Services/Watchdog/Watchdog.hpp" -//#include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" - #include "HALAL/Models/BoardID/BoardID.hpp" #include "HALAL/Models/Concepts/Concepts.hpp" diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 83cdcd79a..3a465e615 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -9,12 +9,12 @@ #include "stm32h7xx_hal.h" //#include "stm32h7xx_hal_tim.h" + #ifdef HAL_TIM_MODULE_ENABLED #include #include -#include "HALAL/Models/GPIO.hpp" #include "ErrorHandler/ErrorHandler.hpp" // NOTE: only works for static arrays @@ -505,171 +505,6 @@ struct TimerDomain { } }; }; - -// Alternate functions for timers -enum TimerAF { - PWM, -}; - -struct TimerPin { - TimerAF af; - ST_LIB::GPIODomain::Pin pin; -}; - -template -struct TimerWrapper { - static constexpr size_t PIN_COUNT = sizeof...(PinArgs); - static constexpr std::array pins = {PinArgs...}; - - TimerDomain::Instance& instance; - TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} - - inline void counter_enable() { - SET_BIT(instance.tim->CR1, TIM_CR1_CEN); - } - inline void counter_disable() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_CEN); - } - - inline void clear_update_interrupt_flag() { - CLEAR_BIT(instance.tim->SR, TIM_SR_UIF); - } - - /* Disabled by default */ - inline void enable_update_interrupt() { - SET_BIT(instance.tim->DIER, TIM_DIER_UIE); - } - inline void disable_update_interrupt() { - CLEAR_BIT(instance.tim->DIER, TIM_DIER_UIE); - } - - /* Disabled by default */ - inline void enable_nvic() { - NVIC_EnableIRQ(TimerDomain::timer_irqn[instance.timer_idx]); - } - inline void disable_nvic() { - NVIC_DisableIRQ(TimerDomain::timer_irqn[instance.timer_idx]); - } - - /* Enable UEV. The Update (UEV) event is generated by one of the following events: - * – Counter overflow/underflow - * – Setting the UG bit - * – Update generation through the slave mode controller - * Enabled by default - */ - inline void enable_update_event() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); - } - /* Disable UEV. The Update event is not generated, shadow registers keep their value - * (ARR, PSC, CCRx). However the counter and the prescaler are reinitialized if the UG bit - * is set or if a hardware reset is received from the slave mode controller. - */ - inline void disable_update_event() { - SET_BIT(instance.tim->CR1, TIM_CR1_UDIS); - } - - /* default: disabled */ - inline void break_interrupt_enable() { - static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, - "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); - ErrorHandler("Break interrupt is not allowed currently because gp timers {TIM12, TIM13, TIM14} use the same interrupt callback"); - } - inline void break_interrupt_disable() { - static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, - "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); - SET_BIT(instance.tim->DIER, TIM_DIER_BIE); - } - - /* interrupt gets called only once, counter needs to be reenabled */ - inline void set_one_pulse_mode() { - SET_BIT(instance.tim->CR1, TIM_CR1_OPM); - } - inline void multi_interrupt() { - CLEAR_BIT(instance.tim->CR1, TIM_CR1_OPM); - } - - inline TIM_HandleTypeDef *get_hal_handle() { - return instance.hal_tim; - } - inline TIM_TypeDef *get_cmsis_handle() { - return instance.tim; - } - - template - inline void configure32bit(void (*callback)(void*), void *callback_data, uint32_t period) - { - constexpr bool bits32timer = ( - dev.e.request == TimerRequest::GeneralPurpose32bit_2 || - dev.e.request == TimerRequest::GeneralPurpose32bit_3 || - dev.e.request == TimerRequest::GeneralPurpose32bit_23 || - dev.e.request == TimerRequest::GeneralPurpose32bit_24 - ); - static_assert(bits32timer, "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(); - } - - // 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; - } - -#if 0 - if constexpr (dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2) { - // advanced specific functions - } - - if constexpr (dev.e.request != TimerRequest::Basic_1 && dev.e.request != TimerRequest::Basic_2) { - // general purpose and advanced functions - } -#endif - - /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ - template - inline void set_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), - "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) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); - CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == TimerDomain::CountingMode::DOWN) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); - SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); - } - } -}; - } // namespace ST_LIB #endif // HAL_TIM_MODULE_ENABLED diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp new file mode 100644 index 000000000..b737862a3 --- /dev/null +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -0,0 +1,185 @@ +/* + * TimerWrapper.hpp + * + * Created on: 30 dic. 2025 + * Author: victor + */ + +#pragma once + +#ifdef HAL_TIM_MODULE_ENABLED + +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" +#include "HALAL/Models/GPIO.hpp" + +#include "ErrorHandler/ErrorHandler.hpp" + +#include "stm32h7xx_hal.h" + +namespace ST_LIB { +// Alternate functions for timers +enum TimerAF { + PWM, +}; + +struct TimerPin { + TimerAF af; + ST_LIB::GPIODomain::Pin pin; +}; + +template +struct TimerWrapper { + static constexpr size_t PIN_COUNT = sizeof...(PinArgs); + static constexpr std::array pins = {PinArgs...}; + + TimerDomain::Instance& instance; + TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} + + inline void counter_enable() { + SET_BIT(instance.tim->CR1, TIM_CR1_CEN); + } + inline void counter_disable() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_CEN); + } + + inline void clear_update_interrupt_flag() { + CLEAR_BIT(instance.tim->SR, TIM_SR_UIF); + } + + /* Disabled by default */ + inline void enable_update_interrupt() { + SET_BIT(instance.tim->DIER, TIM_DIER_UIE); + } + inline void disable_update_interrupt() { + CLEAR_BIT(instance.tim->DIER, TIM_DIER_UIE); + } + + /* Disabled by default */ + inline void enable_nvic() { + NVIC_EnableIRQ(TimerDomain::timer_irqn[instance.timer_idx]); + } + inline void disable_nvic() { + NVIC_DisableIRQ(TimerDomain::timer_irqn[instance.timer_idx]); + } + + /* Enable UEV. The Update (UEV) event is generated by one of the following events: + * – Counter overflow/underflow + * – Setting the UG bit + * – Update generation through the slave mode controller + * Enabled by default + */ + inline void enable_update_event() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_UDIS); + } + /* Disable UEV. The Update event is not generated, shadow registers keep their value + * (ARR, PSC, CCRx). However the counter and the prescaler are reinitialized if the UG bit + * is set or if a hardware reset is received from the slave mode controller. + */ + inline void disable_update_event() { + SET_BIT(instance.tim->CR1, TIM_CR1_UDIS); + } + + /* default: disabled */ + inline void break_interrupt_enable() { + static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, + "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); + ErrorHandler("Break interrupt is not allowed currently because gp timers {TIM12, TIM13, TIM14} use the same interrupt callback"); + } + inline void break_interrupt_disable() { + static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, + "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); + SET_BIT(instance.tim->DIER, TIM_DIER_BIE); + } + + /* interrupt gets called only once, counter needs to be reenabled */ + inline void set_one_pulse_mode() { + SET_BIT(instance.tim->CR1, TIM_CR1_OPM); + } + inline void multi_interrupt() { + CLEAR_BIT(instance.tim->CR1, TIM_CR1_OPM); + } + + inline TIM_HandleTypeDef *get_hal_handle() { + return instance.hal_tim; + } + inline TIM_TypeDef *get_cmsis_handle() { + return instance.tim; + } + + template + inline void configure32bit(void (*callback)(void*), void *callback_data, uint32_t period) + { + constexpr bool bits32timer = ( + dev.e.request == TimerRequest::GeneralPurpose32bit_2 || + dev.e.request == TimerRequest::GeneralPurpose32bit_3 || + dev.e.request == TimerRequest::GeneralPurpose32bit_23 || + dev.e.request == TimerRequest::GeneralPurpose32bit_24 + ); + static_assert(bits32timer, "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(); + } + + // 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; + } + +#if 0 + if constexpr (dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2) { + // advanced specific functions + } + + if constexpr (dev.e.request != TimerRequest::Basic_1 && dev.e.request != TimerRequest::Basic_2) { + // general purpose and advanced functions + } +#endif + + /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ + template + inline void set_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), + "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) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == TimerDomain::CountingMode::DOWN) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); + } + } +}; +} // namespace ST_LIB + +#endif // HAL_TIM_MODULE_ENABLED From 78a15269c52036fec50ceb8061ee49cc4a2ec8c4 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 30 Dec 2025 14:58:13 +0100 Subject: [PATCH 252/281] fix: Use new way to add Domain to board --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 3a465e615..899648d3d 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -348,7 +348,7 @@ struct TimerDomain { template consteval void inscribe(Ctx &ctx) const { - ctx.template add(e); + ctx.template add(e, this); } }; From 2822928265ecea2c57943ebcb9f91735158ec69e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 30 Dec 2025 19:54:24 +0100 Subject: [PATCH 253/281] feat: Initial implementation of new PWM class --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 80 ++++++--- Inc/HALAL/Services/PWM/PWM/NewPWM.hpp | 174 +++++++++++++++++++ Inc/HALAL/Services/Time/TimerWrapper.hpp | 46 +++-- 3 files changed, 263 insertions(+), 37 deletions(-) create mode 100644 Inc/HALAL/Services/PWM/PWM/NewPWM.hpp diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 899648d3d..af0d138f6 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -12,6 +12,8 @@ #ifdef HAL_TIM_MODULE_ENABLED +#include "HALAL/Models/GPIO.hpp" + #include #include @@ -94,10 +96,11 @@ extern void compile_error(const char *msg); /* The number corresponds with the timer nº */ enum TimerRequest : uint8_t { + AnyGeneralPurpose = 0, + Advanced_1 = 1, Advanced_8 = 8, - AnyGeneralPurpose = 0xFF, GeneralPurpose32bit_2 = 2, GeneralPurpose32bit_3 = 3, GeneralPurpose32bit_23 = 23, @@ -118,6 +121,18 @@ enum TimerRequest : uint8_t { Basic_7 = 7, }; +// Alternate functions for timers +enum class TimerAF { + None, + PWM, +}; + +struct TimerPin { + TimerAF af; + ST_LIB::GPIODomain::Pin pin; + uint8_t channel; +}; + constexpr std::array create_timer_idxmap() { std::array result{}; @@ -180,6 +195,8 @@ struct TimerDomain { uint32_t deadtime; uint32_t polarity; uint32_t negated_polarity; + uint8_t pin_count; + std::array pins; }; struct Config { @@ -249,7 +266,7 @@ struct TimerDomain { static constexpr Config DoTimer(const Entry request, int reqint, int reqidx) { Config cfg; - if((request).name[0] == '\0') { + if(request.name[0] == '\0') { /* "Timer" + tostring(reqint) */ cfg.name[0] = 'T'; cfg.name[1] = 'i'; @@ -261,20 +278,22 @@ struct TimerDomain { cfg.name[7] = '\0'; } else { for(int si = 0; si < 8; si++) { - cfg.name[si] = (request).name[si]; + cfg.name[si] = request.name[si]; } } cfg.timer_idx = timer_idxmap[reqint]; - cfg.prescaler = (request).prescaler; - cfg.period = (request).period; - cfg.deadtime = (request).deadtime; - cfg.polarity = (request).polarity; - cfg.negated_polarity = (request).negated_polarity; + cfg.prescaler = request.prescaler; + cfg.period = request.period; + cfg.deadtime = request.deadtime; + cfg.polarity = request.polarity; + cfg.negated_polarity = request.negated_polarity; - //check_timer(&cfg, request, reqidx); // Do any compile time checks needed for the timers... if(request.period == 0) { - ST_LIB::compile_error("Error: period must be greater than 0 (>0)"); + cfg.period = 1; + } + if(request.prescaler == 0) { + cfg.prescaler = 1; } if(!(reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24)) { @@ -315,18 +334,10 @@ struct TimerDomain { return cfg; } - enum PWM_MODE : uint8_t { - NORMAL = 0, - PHASED = 1, - CENTER_ALIGNED = 2, - }; - - struct PWMData { - uint32_t channel; - PWM_MODE mode; - }; + static constexpr std::array EMPTY_TIMER_NAME = {0,0,0,0, 0,0,0,0}; + static constexpr TimerPin EMPTY_PIN = {TimerAF::None, GPIODomain::Pin{GPIODomain::Port{},0}, 0 }; + static constexpr std::array EMPTY_TIMER_PINS = {EMPTY_PIN, EMPTY_PIN, EMPTY_PIN, EMPTY_PIN}; -#define EMPTY_TIMER_NAME {0,0,0,0, 0,0,0,0} struct Timer { using domain = TimerDomain; Entry e; @@ -334,7 +345,8 @@ struct TimerDomain { consteval Timer(TimerRequest request = TimerRequest::AnyGeneralPurpose, TimerDomain::CountingMode counting_mode = CountingMode::UP, std::array name = EMPTY_TIMER_NAME, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, - uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH) + uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH, + uint8_t pin_count = 0, std::array pins = EMPTY_TIMER_PINS) { e.name = name; e.request = request; @@ -344,6 +356,22 @@ struct TimerDomain { e.deadtime = deadtime; e.polarity = polarity; e.negated_polarity = negated_polarity; + e.pin_count = pin_count; + e.pins = pins; + } + + // anything not initialized will be 0 + consteval Timer(Entry e) { + this->e.name = e.name; + this->e.request = e.request; + this->e.counting_mode = e.counting_mode; + this->e.prescaler = e.prescaler; + this->e.period = e.period; + this->e.deadtime = e.deadtime; + this->e.polarity = e.polarity; + this->e.negated_polarity = e.negated_polarity; + this->e.pin_count = e.pin_count; + this->e.pins = e.pins; } template @@ -362,6 +390,8 @@ 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; @@ -504,6 +534,12 @@ struct TimerDomain { } } }; + + static consteval void check_pins(std::span requests) + { + /* good luck n_n */ + + } }; } // namespace ST_LIB diff --git a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp new file mode 100644 index 000000000..35fdc6ffb --- /dev/null +++ b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp @@ -0,0 +1,174 @@ +/* + * NewPWM.hpp + * + * Created on: Dec 30, 2025 + * Author: victor + */ +#pragma once + +#ifdef HAL_TIM_MODULE_ENABLED +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" +#include "HALAL/Models/GPIO.hpp" + +namespace ST_LIB { + +template +struct TimerWrapper; + +enum PWM_MODE : uint8_t { + NORMAL = 0, + PHASED = 1, + CENTER_ALIGNED = 2, +}; + +struct PWMData { + uint32_t channel; + PWM_MODE mode; +}; + +template +class PWM { + static constexpr size_t channel_to_CCR[7] = { + 0, + offsetof(TIM_TypeDef, CCR1), + offsetof(TIM_TypeDef, CCR2), + offsetof(TIM_TypeDef, CCR3), + offsetof(TIM_TypeDef, CCR4), + offsetof(TIM_TypeDef, CCR5), + offsetof(TIM_TypeDef, CCR6) + }; + + static constexpr uint32_t channel_to_channel_state_idx[7] = { + 0, + 0, 1, 2, 3, 4, 5, + }; + + static constexpr uint32_t channel_to_channelmul4[7] = { + 0, + 0x0, 0x4, 0x8, 0xC, 0x10, 0x14 + }; + +public: + 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; + uint32_t frequency; + float duty_cycle; + bool is_on = false; + bool is_center_aligned; + + 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; + } + + void turn_on() { + if(is_on) return; + + // if(HAL_TIM_PWM_Start(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } + HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[channel_to_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 << (channel_to_channelmul4[pin.channel] & 0x1FU); /* 0x1FU = 31 bits max shift */ + + SET_BIT(timer.tim->CCER, (uint32_t)(TIM_CCx_ENABLE << (channel_to_channelmul4[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)) + { + // Main Output Enable + SET_BIT(timer.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(!IS_TIM_SLAVEMODE_TRIGGER_ENABLED(tmpsmcr)) { + timer.counter_enable(); + } + } else { + timer.counter_enable(); + } + + is_on = true; + } + + void turn_off() { + if(!is_on) return; + // if(HAL_TIM_PWM_Stop(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } + + SET_BIT(timer.tim->CCER, (uint32_t)(TIM_CCx_DISABLE << (channel_to_channelmul4[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)) + { + // Disable Main Output Enable (MOE) + CLEAR_BIT(timer.tim->BDTR, TIM_BDTR_MOE); + } + + __HAL_TIM_DISABLE(timer.htim); + + HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[channel_to_channel_state_idx[pin.channel]]; + *state = HAL_TIM_CHANNEL_STATE_READY; + + 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) + channel_to_CCR[pin.channel]) = raw_duty; + this->duty_cycle = duty_cycle; + } + + void set_frequency(uint32_t frequency) { + if(is_center_aligned) { + frequency = 2*frequency; + } + this->frequency = frequency; + timer.tim->ARR = (HAL_RCC_GetPCLK1Freq() * 2 / (timer.tim->PSC + 1)) / frequency; + set_duty_cycle(duty_cycle); + } + + void set_dead_time(int64_t dead_time_ns) { + TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; + + int64_t time = dead_time_ns; + + if(time <= 127 * clock_period_ns) { + sBreakDeadTimeConfig.DeadTime = time / clock_period_ns; + } else if(time <= (2 * clock_period_ns * 127)) { + sBreakDeadTimeConfig.DeadTime = time / (2 * clock_period_ns) - 64 + 128; + } else if(time <= (8 * clock_period_ns * 127)) { + sBreakDeadTimeConfig.DeadTime = time / (8 * clock_period_ns) -32 + 192; + } else if(time <= (16 * clock_period_ns * 127)) { + sBreakDeadTimeConfig.DeadTime = time / (16 * clock_period_ns) -32 + 224; + } else { + ErrorHandler("Invalid dead time configuration"); + } + + sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; + sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; + sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF; + sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE; + 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; + HAL_TIMEx_ConfigBreakDeadTime(timer->htim, &sBreakDeadTimeConfig); + SET_BIT(timer->tim->BDTR, TIM_BDTR_MOE); + } +}; +} // namespace ST_LIB + +#endif // HAL_TIM_MODULE_ENABLED diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index b737862a3..7447e5b3b 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -10,6 +10,7 @@ #ifdef HAL_TIM_MODULE_ENABLED #include "HALAL/Models/TimerDomain/TimerDomain.hpp" +#include "HALAL/Services/PWM/PWM/NewPWM.hpp" #include "HALAL/Models/GPIO.hpp" #include "ErrorHandler/ErrorHandler.hpp" @@ -17,24 +18,39 @@ #include "stm32h7xx_hal.h" namespace ST_LIB { -// Alternate functions for timers -enum TimerAF { - PWM, -}; - -struct TimerPin { - TimerAF af; - ST_LIB::GPIODomain::Pin pin; -}; -template +template struct TimerWrapper { - static constexpr size_t PIN_COUNT = sizeof...(PinArgs); - static constexpr std::array pins = {PinArgs...}; - TimerDomain::Instance& instance; TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} + 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); + } + + 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); + } + + 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); + } + } + inline void counter_enable() { SET_BIT(instance.tim->CR1, TIM_CR1_CEN); } @@ -147,11 +163,11 @@ struct TimerWrapper { } #if 0 - if constexpr (dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_2) { + if constexpr (dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8) { // advanced specific functions } - if constexpr (dev.e.request != TimerRequest::Basic_1 && dev.e.request != TimerRequest::Basic_2) { + if constexpr (dev.e.request != TimerRequest::Basic_6 && dev.e.request != TimerRequest::Basic_7) { // general purpose and advanced functions } #endif From f640024c5dd2dfd0dafa5981fc9f553f3f127351 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 30 Dec 2025 19:55:19 +0100 Subject: [PATCH 254/281] fix: Make PWM class more private --- Inc/HALAL/Services/PWM/PWM/NewPWM.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp index 35fdc6ffb..20276eb91 100644 --- a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp +++ b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp @@ -48,7 +48,6 @@ class PWM { 0x0, 0x4, 0x8, 0xC, 0x10, 0x14 }; -public: 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; @@ -59,6 +58,7 @@ class PWM { 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); From 32d2426077d4d0db56150c81145b670e508615f4 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 30 Dec 2025 20:13:18 +0100 Subject: [PATCH 255/281] feat: Use an initializer_list to get the pins without needing a size --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 35 +++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index af0d138f6..fc6739226 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -16,6 +16,7 @@ #include #include +#include #include "ErrorHandler/ErrorHandler.hpp" @@ -335,8 +336,6 @@ struct TimerDomain { } static constexpr std::array EMPTY_TIMER_NAME = {0,0,0,0, 0,0,0,0}; - static constexpr TimerPin EMPTY_PIN = {TimerAF::None, GPIODomain::Pin{GPIODomain::Port{},0}, 0 }; - static constexpr std::array EMPTY_TIMER_PINS = {EMPTY_PIN, EMPTY_PIN, EMPTY_PIN, EMPTY_PIN}; struct Timer { using domain = TimerDomain; @@ -346,7 +345,7 @@ struct TimerDomain { TimerDomain::CountingMode counting_mode = CountingMode::UP, std::array name = EMPTY_TIMER_NAME, uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, uint32_t polarity = TIM_OCPOLARITY_HIGH, uint32_t negated_polarity = TIM_OCPOLARITY_HIGH, - uint8_t pin_count = 0, std::array pins = EMPTY_TIMER_PINS) + std::initializer_list pinargs = {}) { e.name = name; e.request = request; @@ -356,12 +355,20 @@ struct TimerDomain { e.deadtime = deadtime; e.polarity = polarity; e.negated_polarity = negated_polarity; - e.pin_count = pin_count; - e.pins = pins; + + 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 not initialized will be 0 - consteval Timer(Entry e) { + 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; @@ -370,8 +377,20 @@ struct TimerDomain { this->e.deadtime = e.deadtime; this->e.polarity = e.polarity; this->e.negated_polarity = e.negated_polarity; - this->e.pin_count = e.pin_count; - this->e.pins = e.pins; + 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++; + } + } } template From 57efe6fa66056cd101831a2a9190296a588592a0 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 12 Jan 2026 13:01:29 +0100 Subject: [PATCH 256/281] fix: Remove prescaler and period from TimerDomain --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 40 ++++---------------- 1 file changed, 7 insertions(+), 33 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index fc6739226..8172f93ba 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -191,8 +191,6 @@ struct TimerDomain { std::array name; /* max length = 7 */ TimerRequest request; TimerDomain::CountingMode counting_mode; - uint16_t prescaler; - uint32_t period; uint32_t deadtime; uint32_t polarity; uint32_t negated_polarity; @@ -205,8 +203,6 @@ struct TimerDomain { TimerDomain::Kind kind; uint16_t timer_idx; TimerDomain::CountingMode counting_mode; - uint32_t prescaler; - uint32_t period; uint32_t deadtime; uint32_t polarity; uint32_t negated_polarity; @@ -283,26 +279,11 @@ struct TimerDomain { } } cfg.timer_idx = timer_idxmap[reqint]; - cfg.prescaler = request.prescaler; - cfg.period = request.period; cfg.deadtime = request.deadtime; cfg.polarity = request.polarity; cfg.negated_polarity = request.negated_polarity; // Do any compile time checks needed for the timers... - if(request.period == 0) { - cfg.period = 1; - } - if(request.prescaler == 0) { - cfg.prescaler = 1; - } - - if(!(reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24)) { - if(request.period > 0xFFFF) { - ST_LIB::compile_error("Error: Timers other than {TIM2, TIM5, TIM23, TIM24} have a maximum period of 0xFFFF (they are uint16_t)"); - } - } - if(!(reqint == 1 || reqint == 8 || reqint == 2 || reqint == 5 || reqint == 23 || reqint == 24 || reqint == 3 || reqint == 4)) @@ -342,16 +323,14 @@ struct TimerDomain { Entry e; consteval Timer(TimerRequest request = TimerRequest::AnyGeneralPurpose, - TimerDomain::CountingMode counting_mode = CountingMode::UP, std::array name = EMPTY_TIMER_NAME, - uint16_t prescaler = 5, uint32_t period = 55000, uint32_t deadtime = 0, + 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 = {}) { e.name = name; e.request = request; e.counting_mode = counting_mode; - e.prescaler = prescaler; - e.period = period; e.deadtime = deadtime; e.polarity = polarity; e.negated_polarity = negated_polarity; @@ -372,8 +351,6 @@ struct TimerDomain { this->e.name = e.name; this->e.request = e.request; this->e.counting_mode = e.counting_mode; - this->e.prescaler = e.prescaler; - this->e.period = e.period; this->e.deadtime = e.deadtime; this->e.polarity = e.polarity; this->e.negated_polarity = e.negated_polarity; @@ -506,18 +483,15 @@ struct TimerDomain { const Config &e = cfgs[i]; TIM_HandleTypeDef *handle = (TIM_HandleTypeDef*)&hal_handles[e.timer_idx]; - handle->Instance = cmsis_timers[e.timer_idx]; - handle->Init.Prescaler = e.prescaler; + TIM_TypeDef *tim = cmsis_timers[e.timer_idx]; + handle->Instance = tim; + handle->Init.Period = 0; + handle->Init.Prescaler = 0; handle->Init.CounterMode = TIM_COUNTERMODE_UP; handle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - handle->Init.Period = e.period; handle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; handle->Init.RepetitionCounter = 0; - TIM_TypeDef *tim = cmsis_timers[e.timer_idx]; - tim->PSC = e.prescaler; - tim->ARR = e.period; - /* if(e.counting_mode == CountingMode::UP) { CLEAR_BIT(tim->CR1, TIM_CR1_DIR); // upcounter } else */ @@ -537,7 +511,7 @@ struct TimerDomain { // PWM stuff should be done somewhere else.. Instance *inst = &instances[i]; - inst->tim = cmsis_timers[e.timer_idx]; + inst->tim = tim; inst->hal_tim = handle; inst->name[0] = e.name[0]; inst->name[1] = e.name[1]; From 9a2a89b3fd96c0c6fb55b5749d26f252e55c29d6 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 13 Jan 2026 20:28:01 +0100 Subject: [PATCH 257/281] feat: Add Any32bitTimer to TimerDomain --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 50 ++++++++++++++++---- Inc/HALAL/Services/Time/TimerWrapper.hpp | 14 +++--- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 8172f93ba..52e66c434 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -98,6 +98,7 @@ extern void compile_error(const char *msg); /* The number corresponds with the timer nº */ enum TimerRequest : uint8_t { AnyGeneralPurpose = 0, + Any32bitTimer = 0xFF, Advanced_1 = 1, Advanced_8 = 8, @@ -404,7 +405,9 @@ struct TimerDomain { // First find any that have requested a specific timer for(std::size_t i = 0; i < N; i++) { uint8_t reqint = static_cast(requests[i].request); - if(reqint != static_cast(TimerRequest::AnyGeneralPurpose)) { + if((requests[i].request != TimerRequest::AnyGeneralPurpose) && + (requests[i].request != TimerRequest::Any32bitTimer)) + { if(used_timers[reqint]) { ST_LIB::compile_error("Error: Timer already used"); } @@ -419,14 +422,43 @@ struct TimerDomain { } } - /* NOTE: timers {TIM12, TIM13, TIM14} are also 16 bit but - * they are used as slave timers to tim8 - */ // 32 bit timers, very important for scheduler uint8_t bits32_timers[] = {2, 5, 23, 24}; + uint8_t remaining_32bit_timers[4] = {0}; + uint8_t count_remaining_32bit_timers = 0; + uint8_t count_32bit_requests = 0; + + for(int i = 0; i < (int)ARRAY_LENGTH(bits32_timers); i++) { + if(!used_timers[bits32_timers[i]]) + remaining_32bit_timers[count_remaining_32bit_timers++] = bits32_timers[i]; + } + + for(int i = 0; i < count_remaining_requests; ) { + const Entry &e = requests[remaining_requests[i]]; + if(e.request == TimerRequest::Any32bitTimer) { + if(count_remaining_32bit_timers <= count_32bit_requests) { + ST_LIB::compile_error("No remaining 32 bit timers, there are only 4. Timers {2, 5, 23, 24}"); + } + + uint8_t reqint = remaining_32bit_timers[count_32bit_requests]; + Config cfg = DoTimer(requests[i], reqint, i); + cfgs[cfg_idx++] = cfg; + + // unordered remove + count_remaining_requests--; + remaining_requests[i] = remaining_requests[count_remaining_requests]; + } else { + i++; + } + } + // can use any CountingMode (32 bit timers can also but they are higher priority) uint8_t up_down_updown_timers[] = {3, 4}; + // 16 bit timers + /* NOTE: timers {TIM12, TIM13, TIM14} are also 16 bit but + * they are used as slave timers to tim8 + */ uint8_t bits16_timers[] = {15, 16, 17}; uint8_t remaining_timers[15] = {0}; uint8_t count_remaining_timers = 0; @@ -452,12 +484,12 @@ struct TimerDomain { for(int i = 0; i < count_remaining_requests; i++) { const Entry &e = requests[remaining_requests[i]]; - if(e.request == AnyGeneralPurpose) { - uint8_t reqint = remaining_timers[i]; - // NOTE: I don't want to do an ordered remove so this has the real index - Config cfg = DoTimer(requests[i], reqint, i); - cfgs[cfg_idx++] = cfg; + if(e.request != TimerRequest::AnyGeneralPurpose) { + ST_LIB::compile_error("This only processes TimerRequest::AnyGeneralPurpose"); } + uint8_t reqint = remaining_timers[i]; + Config cfg = DoTimer(requests[i], reqint, i); + cfgs[cfg_idx++] = cfg; } return cfgs; diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 7447e5b3b..df819e898 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -24,6 +24,14 @@ struct TimerWrapper { TimerDomain::Instance& instance; TimerWrapper(TimerDomain::Instance& inst) : instance(inst) {} + static constexpr bool bits32timer = ( + dev.e.request == TimerRequest::GeneralPurpose32bit_2 || + dev.e.request == TimerRequest::GeneralPurpose32bit_3 || + dev.e.request == TimerRequest::GeneralPurpose32bit_23 || + dev.e.request == TimerRequest::GeneralPurpose32bit_24 || + dev.e.request == TimerRequest::Any32bitTimer + ); + template inline PWM get_pwm(uint8_t channel) { static_assert(dev.e.pin_count > 0, "Need at least one pin to get a pwm"); @@ -125,12 +133,6 @@ struct TimerWrapper { template inline void configure32bit(void (*callback)(void*), void *callback_data, uint32_t period) { - constexpr bool bits32timer = ( - dev.e.request == TimerRequest::GeneralPurpose32bit_2 || - dev.e.request == TimerRequest::GeneralPurpose32bit_3 || - dev.e.request == TimerRequest::GeneralPurpose32bit_23 || - dev.e.request == TimerRequest::GeneralPurpose32bit_24 - ); static_assert(bits32timer, "Only timers {TIM2, TIM5, TIM23, TIM24} have a 32-bit resolution"); if constexpr (psc != 0) { From 84de08b6eff6b1808e3ea62c036811bb4a97d3e2 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 13 Jan 2026 20:32:54 +0100 Subject: [PATCH 258/281] fix: Rename Any32bitTimer to Any32bit --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 52e66c434..a80dd52a8 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -98,7 +98,7 @@ extern void compile_error(const char *msg); /* The number corresponds with the timer nº */ enum TimerRequest : uint8_t { AnyGeneralPurpose = 0, - Any32bitTimer = 0xFF, + Any32bit = 0xFF, Advanced_1 = 1, Advanced_8 = 8, @@ -406,7 +406,7 @@ struct TimerDomain { for(std::size_t i = 0; i < N; i++) { uint8_t reqint = static_cast(requests[i].request); if((requests[i].request != TimerRequest::AnyGeneralPurpose) && - (requests[i].request != TimerRequest::Any32bitTimer)) + (requests[i].request != TimerRequest::Any32bit)) { if(used_timers[reqint]) { ST_LIB::compile_error("Error: Timer already used"); @@ -435,7 +435,7 @@ struct TimerDomain { for(int i = 0; i < count_remaining_requests; ) { const Entry &e = requests[remaining_requests[i]]; - if(e.request == TimerRequest::Any32bitTimer) { + if(e.request == TimerRequest::Any32bit) { if(count_remaining_32bit_timers <= count_32bit_requests) { ST_LIB::compile_error("No remaining 32 bit timers, there are only 4. Timers {2, 5, 23, 24}"); } From aba7bb222fc5f8acb2aeb9240e3bbde62e57a3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20L=C3=B3pez?= <120128034+victor-Lopez25@users.noreply.github.com> Date: Tue, 13 Jan 2026 20:34:49 +0100 Subject: [PATCH 259/281] Fix docker build hopefully --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d8d055afe..45a393abc 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -7,6 +7,6 @@ RUN apt-get update && apt-get -y install git git-lfs python3-colorama cmake g++ git lfs install # Install cubeclt -RUN mkdir /temp && cd /temp && git clone https://github.com/HyperloopUPV-H8/cubeclt.git && \ +RUN mkdir /temp && cd /temp && git clone https://github.com/Hyperloop-UPV/cubeclt.git && \ cd cubeclt && git lfs pull && chmod +x cubeclt_1.16.0_installer.sh && \ echo | LICENSE_ALREADY_ACCEPTED=1 ./cubeclt_1.16.0_installer.sh From 2e43f72badfef8c5676e21f9c27eb1be00eda2fc Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 13 Jan 2026 21:58:40 +0100 Subject: [PATCH 260/281] feat: add a macro: get_timer_instance --- Inc/HALAL/Services/Time/TimerWrapper.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index df819e898..e7d07eeb5 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -17,6 +17,9 @@ #include "stm32h7xx_hal.h" +#define get_timer_instance(board, timer_type) \ + ST_LIB::TimerWrapper(board::instance_of()) + namespace ST_LIB { template From 087bd8e208196122d2ba1ebc92488e0415412c58 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 13 Jan 2026 22:03:01 +0100 Subject: [PATCH 261/281] fix: compile error --- Inc/HALAL/Services/Time/TimerWrapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index e7d07eeb5..756704303 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -32,7 +32,7 @@ struct TimerWrapper { dev.e.request == TimerRequest::GeneralPurpose32bit_3 || dev.e.request == TimerRequest::GeneralPurpose32bit_23 || dev.e.request == TimerRequest::GeneralPurpose32bit_24 || - dev.e.request == TimerRequest::Any32bitTimer + dev.e.request == TimerRequest::Any32bit ); template From 80cdef57bd316c3e4ee5f96b062a5add6e30e01b Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 14 Jan 2026 19:12:27 +0100 Subject: [PATCH 262/281] fix: revert change to .vscode settings --- .vscode/settings.json | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f905829d4..cdd4cde8a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,26 +10,5 @@ "mem.h": "c", "tinydir.h": "c", "dirent.h": "c", - "compare": "cpp", - "cstdint": "cpp", - "iostream": "cpp" - }, - "testMate.cpp.debug.configTemplate": { - "type": "cppdbg", - "MIMode": "gdb", - "program": "${exec}", - "args": "${args}", - "cwd": "${cwd}", - - "externalConsole": false, - // This setupCommands block often fixes generic "pause" issues in GDB - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ] + } } - } - \ No newline at end of file From 2c3ea9d7759a914b0dae3f5af55e92a6d8500088 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 16 Jan 2026 22:13:12 +0100 Subject: [PATCH 263/281] fix: tim3 is 16 bit, tim5 is 32 bit + start of pin af checking --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 153 ++++++++++++++++++- 1 file changed, 151 insertions(+), 2 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index a80dd52a8..ba6cac120 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -104,12 +104,12 @@ enum TimerRequest : uint8_t { Advanced_8 = 8, GeneralPurpose32bit_2 = 2, - GeneralPurpose32bit_3 = 3, + GeneralPurpose32bit_5 = 5, GeneralPurpose32bit_23 = 23, GeneralPurpose32bit_24 = 24, + GeneralPurpose_3 = 3, GeneralPurpose_4 = 4, - GeneralPurpose_5 = 5, SlaveTimer_12 = 12, SlaveTimer_13 = 13, @@ -563,7 +563,156 @@ struct TimerDomain { static consteval void check_pins(std::span requests) { /* good luck n_n */ + for(std::size_t i = 0; i < requests.size(); i++) { + const Entry &e = requests[i]; + + switch(e.request) { + case TimerRequest::AnyGeneralPurpose: + case TimerRequest::Any32bit: { + if(e.pin_count > 0) { + ST_LIB::compile_error("Any* timers can't use pins"); + } + } break; + + case TimerRequest::Advanced_1: { + // 4 capture-compare channels + // complementary output + + /* TIM1 pins + * PE6: + * - TIM1_BKIN2: AF1 + * - TIM1_BKIN2_COMP12: AF12 + * PA6: + * - TIM1_BKIN: AF1 + * - TIM1_BKIN_COMP12: AF11 + * PA7: + * - TIM1_CH1N: AF1 + * PB0: + * - TIM1_CH2N: AF1 + * PB1: + * - TIM1_CH3N: AF1 + * PE7: + * - TIM1_ETR: AF1 + * PE8: + * - TIM1_CH1N: AF1 + * PE9: + * - TIM1_CH1: AF1 + * PE10: + * - TIM1_CH2N: AF1 + * PE11: + * - TIM1_CH2: AF1 + * PE12: + * - TIM1_CH3N: AF1 + * PE13: + * - TIM1_CH3: AF1 + * PE14: + * - TIM1_CH4: AF1 + * PE15: + * - TIM1_BKIN: AF1 + * - TIM1_BKIN_COMP12: AF13 + * PB12: + * - TIM1_BKIN: AF1 + * - TIM1_BKIN_COMP12: AF13 + * PB13: + * - TIM1_CH1N: AF1 + * PB14: + * - TIM1_CH2N: AF1 + * PB15: + * - TIM1_CH3N: AF1 + * PG4: + * - TIM1_BKIN2: AF1 + * - TIM1_BKIN2_COMP12: AF11 + * PG5: + * - TIM1_ETR: AF1 + * PA8: + * - TIM1_CH1: AF1 + * PA9: + * - TIM1_CH2: AF1 + * PA10: + * - TIM1_CH3: AF1 + * PA11: + * - TIM1_CH4: AF1 + * PA12: + * - TIM1_ETR: AF1 + * - TIM1_BKIN2: AF12 + * + */ + } break; + + case TimerRequest::GeneralPurpose32bit_2: { + // 4 capture-compare channels + + } break; + + case TimerRequest::GeneralPurpose_3: { + // 4 capture-compare channels + + } break; + + case TimerRequest::GeneralPurpose_4: { + // 4 capture-compare channels + + } break; + + case TimerRequest::GeneralPurpose32bit_5: { + // 4 capture-compare channels + + } break; + + case TimerRequest::Basic_6: + case TimerRequest::Basic_7: { + if(e.pin_count > 0) { + ST_LIB::compile_error("Basic timers can't use pins"); + } + } break; + + case TimerRequest::Advanced_8: { + // 4 capture-compare channels + // complementary output + + } break; + + case TimerRequest::SlaveTimer_12: { + // 2 capture-compare channels + + } break; + + case TimerRequest::SlaveTimer_13: { + // 1 capture-compare channel + + } break; + + case TimerRequest::SlaveTimer_14: { + // 1 capture-compare channel + + } break; + + case TimerRequest::GeneralPurpose_15: { + // 2 capture-compare channels + } break; + + case TimerRequest::GeneralPurpose_16: { + // 1 capture-compare channel + + } break; + + case TimerRequest::GeneralPurpose_17: { + // 1 capture-compare channel + + } break; + + case TimerRequest::GeneralPurpose32bit_23: { + // 4 capture-compare channels + + } break; + + case TimerRequest::GeneralPurpose32bit_24: { + // 4 capture-compare channels + + } break; + } + } } }; } // namespace ST_LIB From dc73412d2c7bf166395e603c88041a0ef9867033 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 16 Jan 2026 22:28:59 +0100 Subject: [PATCH 264/281] More timer pin afs --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 67 ++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ba6cac120..6876d261e 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -642,16 +642,83 @@ struct TimerDomain { case TimerRequest::GeneralPurpose32bit_2: { // 4 capture-compare channels + /* TIM2 pins + * PA0: + * - TIM2_CH1: AF1 + * - TIM2_ETR: AF1 + * PA1: + * - TIM2_CH2: AF1 + * PA2: + * - TIM2_CH3: AF1 + * PA3: + * - TIM2_CH4: AF1 + * PA5: + * - TIM2_CH1: AF1 + * - TIM2_ETR: AF1 + * PA15: + * - TIM2_CH1: AF1 + * - TIM2_ETR: AF1 + * PB3: + * - TIM2_CH2: AF1 + * PB10: + * - TIM2_CH3: AF1 + * PB11: + * - TIM2_CH4: AF1 + */ } break; case TimerRequest::GeneralPurpose_3: { // 4 capture-compare channels + /* TIM3 pins: + * PA6: + * - TIM3_CH1: AF2 + * PA7: + * - TIM3_CH2: AF2 + * PB0: + * - TIM3_CH3: AF2 + * PB1: + * - TIM3_CH4: AF2 + * PB4: + * - TIM3_CH1: AF2 + * PB5: + * - TIM3_CH2: AF2 + * PC6: + * - TIM3_CH1: AF2 + * PC7: + * - TIM3_CH2: AF2 + * PC8: + * - TIM3_CH3: AF2 + * PC9: + * - TIM3_CH4: AF2 + * PD2: + * - TIM3_ETR: AF2 + */ } break; case TimerRequest::GeneralPurpose_4: { // 4 capture-compare channels + /* TIM4 pins: + * PB6: + * - TIM4_CH1: AF2 + * PB7: + * - TIM4_CH2: AF2 + * PB8: + * - TIM4_CH3: AF2 + * PB9: + * - TIM4_CH4: AF2 + * PD12: + * - TIM4_CH1: AF2 + * PD13: + * - TIM4_CH2: AF2 + * PD14: + * - TIM4_CH3: AF2 + * PD15: + * - TIM4_CH4: AF2 + * PE0: + * - TIM4_ETR: AF2 + */ } break; case TimerRequest::GeneralPurpose32bit_5: { From 84b0857858f33f24c9cd6bf4afc72ef1123293be Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 19 Jan 2026 12:44:00 +0100 Subject: [PATCH 265/281] More pins, todo: tim23 and tim24 --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 112 +++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 6876d261e..aeb8b0776 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -724,6 +724,18 @@ struct TimerDomain { case TimerRequest::GeneralPurpose32bit_5: { // 4 capture-compare channels + /* TIM5 pins: + * PA0: + * - TIM5_CH1: AF2 + * PA1: + * - TIM5_CH2: AF2 + * PA2: + * - TIM5_CH3: AF2 + * PA3: + * - TIM5_CH4: AF2 + * PA4: + * - TIM5_ETR: AF2 + */ } break; case TimerRequest::Basic_6: @@ -737,36 +749,136 @@ struct TimerDomain { // 4 capture-compare channels // complementary output + /* TIM8 pins: + * PA0: + * - TIM8_ETR: AF3 + * PA5: + * - TIM8_CH1N: AF3 + * PA6: + * - TIM8_BKIN: AF3 + * - TIM8_BKIN_COMP12: AF10 + * PA7: + * - TIM8_CH1N: AF3 + * PA8: + * - TIM8_BKIN2: AF3 + * - TIM8_BKIN2_COMP12: AD12 + * PB0: + * - TIM8_CH2N: AF3 + * PB1: + * - TIM8_CH3N: AF3 + * PB14: + * - TIM8_CH2N: AF3 + * PB15: + * - TIM8_CH3N: AF3 + * PC6: + * - TIM8_CH1: AF3 + * PC7: + * - TIM8_CH2: AF3 + * PC8: + * - TIM8_CH3: AF3 + * PC9: + * - TIM8_CH4: AF3 + * PG2: + * - TIM8_BKIN: AF3 + * - TIM8_BKIN_COMP12: AF11 + * PG3: + * - TIM8_BKIN2: AF3 + * - TIM8_BKIN2_COMP12: AF11 + * PG8: + * - TIM8_ETR: AF3 + */ } break; case TimerRequest::SlaveTimer_12: { // 2 capture-compare channels + /* TIM12 pins: + * PB14: + * - TIM12_CH1: AF2 + * PB15: + * - TIM12_CH2: AF2 + */ } break; case TimerRequest::SlaveTimer_13: { // 1 capture-compare channel + /* TIM13 pins: + * PA6: + * - TIM13_CH1: AF9 + * PF8: + * - TIM13_CH1: AF9 + */ } break; case TimerRequest::SlaveTimer_14: { // 1 capture-compare channel + /* TIM14 pins: + * PA7: + * - TIM14_CH1: AF9 + * PF9: + * - TIM14_CH1: AF9 + */ } break; case TimerRequest::GeneralPurpose_15: { // 2 capture-compare channels + /* TIM15 pins: + * PA0: + * - TIM15_BKIN: AF4 + * PA1: + * - TIM15_CH1N: AF4 + * PA2: + * - TIM15_CH1: AF4 + * PA3: + * - TIM15_CH2: AF4 + * PC12: + * - TIM15_CH1: AF2 + * PD2: + * - TIM15_BKIN: AF4 + * PE3: + * - TIM15_BKIN: AF4 + * PE4: + * - TIM15_CH1N: AF4 + * PE5: + * - TIM15_CH1: AF4 + * PE6: + * - TIM15_CH2: AF4 + */ } break; case TimerRequest::GeneralPurpose_16: { // 1 capture-compare channel + /* TIM16 pins: + * PF6: + * - TIM16_CH1: AF1 + * PF8: + * - TIM16_CH1N: AF1 + * PF10: + * - TIM16_BKIN: AF1 + */ } break; case TimerRequest::GeneralPurpose_17: { // 1 capture-compare channel + /* TIM17 pins: + * PB5: + * - TIM17_BKIN: AF1 + * PB7: + * - TIM17_CH1N: AF1 + * PB9: + * - TIM17_CH1: AF1 + * PF7: + * - TIM17_CH1: AF1 + * PF9: + * - TIM17_CH1N: AF1 + * PG6: + * - TIM17_BKIN: AF1 + */ } break; case TimerRequest::GeneralPurpose32bit_23: { From 3447e3fd109d69f9a98325102f0d2c6cab17c444 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 19 Jan 2026 14:15:43 +0100 Subject: [PATCH 266/281] tim23, tim24 pins done, now programming time --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 42 ++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index aeb8b0776..c9006310b 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -884,11 +884,53 @@ struct TimerDomain { case TimerRequest::GeneralPurpose32bit_23: { // 4 capture-compare channels + /* TIM23 pins: + * PB2: + * - TIM23_ETR: AF13 + * PF0: + * - TIM23_CH1: AF13 + * PF1: + * - TIM23_CH2: AF13 + * PF2: + * - TIM23_CH3: AF13 + * PF3: + * - TIM23_CH4: AF13 + * PF6: + * - TIM23_CH1: AF13 + * PF7: + * - TIM23_CH2: AF13 + * PF8: + * - TIM23_CH3: AF13 + * PF9: + * - TIM23_CH4: AF13 + * PG3: + * - TIM23_ETR: AF13 + * PG12: + * - TIM23_CH1: AF13 + * PG13: + * - TIM23_CH2: AF13 + * PG14: + * - TIM23_CH3: AF13 + */ } break; case TimerRequest::GeneralPurpose32bit_24: { // 4 capture-compare channels + /* TIM24 pins: + * PB3: + * - TIM24_ETR: AF14 + * PF11: + * - TIM24_CH1: AF14 + * PF12: + * - TIM24_CH2: AF14 + * PF13: + * - TIM24_CH3: AF14 + * PF14: + * - TIM24_CH4: AF14 + * PG2: + * - TIM24_ETR: AF14 + */ } break; } } From 6856aefbefacafd61bd6d48ce409acb9b0420a31 Mon Sep 17 00:00:00 2001 From: victhor Date: Mon, 19 Jan 2026 21:09:31 +0100 Subject: [PATCH 267/281] next step: compile time check_pins --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 640 ++++++++----------- Inc/HALAL/Services/Time/TimerWrapper.hpp | 3 +- 2 files changed, 276 insertions(+), 367 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index c9006310b..28354c751 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -562,376 +562,284 @@ struct TimerDomain { static consteval void check_pins(std::span requests) { + enum TimerAF_Use { + Channel_1, + Channel_2, + Channel_3, + Channel_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; + }; + 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}, + }; + 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}, + }; + + struct TimerPossiblePinSlice { + std::span pins; + int pin_count; + }; + + TimerPossiblePinSlice tim_pins[25]; + tim_pins[TimerRequest::Advanced_1] = + {std::span(tim1pins), ARRAY_LENGTH(tim1pins)}; + tim_pins[TimerRequest::GeneralPurpose32bit_2] = + {std::span(tim2pins), ARRAY_LENGTH(tim2pins)}; + tim_pins[TimerRequest::GeneralPurpose_3] = + {std::span(tim3pins), ARRAY_LENGTH(tim3pins)}; + tim_pins[TimerRequest::GeneralPurpose_4] = + {std::span(tim4pins), ARRAY_LENGTH(tim4pins)}; + tim_pins[TimerRequest::GeneralPurpose32bit_5] = + {std::span(tim5pins), ARRAY_LENGTH(tim5pins)}; + /* TIM6, TIM7 have no associated pins */ + tim_pins[TimerRequest::Advanced_8] = + {std::span(tim8pins), ARRAY_LENGTH(tim8pins)}; + tim_pins[TimerRequest::SlaveTimer_12] = + {std::span(tim12pins), ARRAY_LENGTH(tim12pins)}; + tim_pins[TimerRequest::SlaveTimer_13] = + {std::span(tim13pins), ARRAY_LENGTH(tim13pins)}; + tim_pins[TimerRequest::SlaveTimer_14] = + {std::span(tim14pins), ARRAY_LENGTH(tim14pins)}; + tim_pins[TimerRequest::GeneralPurpose_15] = + {std::span(tim15pins), ARRAY_LENGTH(tim15pins)}; + tim_pins[TimerRequest::GeneralPurpose_16] = + {std::span(tim16pins), ARRAY_LENGTH(tim16pins)}; + tim_pins[TimerRequest::GeneralPurpose_17] = + {std::span(tim17pins), ARRAY_LENGTH(tim17pins)}; + tim_pins[TimerRequest::GeneralPurpose32bit_23] = + {std::span(tim23pins), ARRAY_LENGTH(tim23pins)}; + tim_pins[TimerRequest::GeneralPurpose32bit_24] = + {std::span(tim24pins), ARRAY_LENGTH(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"); + } - switch(e.request) { - case TimerRequest::AnyGeneralPurpose: - case TimerRequest::Any32bit: { - if(e.pin_count > 0) { - ST_LIB::compile_error("Any* timers can't use pins"); - } - } break; - - case TimerRequest::Advanced_1: { - // 4 capture-compare channels - // complementary output - - /* TIM1 pins - * PE6: - * - TIM1_BKIN2: AF1 - * - TIM1_BKIN2_COMP12: AF12 - * PA6: - * - TIM1_BKIN: AF1 - * - TIM1_BKIN_COMP12: AF11 - * PA7: - * - TIM1_CH1N: AF1 - * PB0: - * - TIM1_CH2N: AF1 - * PB1: - * - TIM1_CH3N: AF1 - * PE7: - * - TIM1_ETR: AF1 - * PE8: - * - TIM1_CH1N: AF1 - * PE9: - * - TIM1_CH1: AF1 - * PE10: - * - TIM1_CH2N: AF1 - * PE11: - * - TIM1_CH2: AF1 - * PE12: - * - TIM1_CH3N: AF1 - * PE13: - * - TIM1_CH3: AF1 - * PE14: - * - TIM1_CH4: AF1 - * PE15: - * - TIM1_BKIN: AF1 - * - TIM1_BKIN_COMP12: AF13 - * PB12: - * - TIM1_BKIN: AF1 - * - TIM1_BKIN_COMP12: AF13 - * PB13: - * - TIM1_CH1N: AF1 - * PB14: - * - TIM1_CH2N: AF1 - * PB15: - * - TIM1_CH3N: AF1 - * PG4: - * - TIM1_BKIN2: AF1 - * - TIM1_BKIN2_COMP12: AF11 - * PG5: - * - TIM1_ETR: AF1 - * PA8: - * - TIM1_CH1: AF1 - * PA9: - * - TIM1_CH2: AF1 - * PA10: - * - TIM1_CH3: AF1 - * PA11: - * - TIM1_CH4: AF1 - * PA12: - * - TIM1_ETR: AF1 - * - TIM1_BKIN2: AF12 - * - */ - } break; - - case TimerRequest::GeneralPurpose32bit_2: { - // 4 capture-compare channels - - /* TIM2 pins - * PA0: - * - TIM2_CH1: AF1 - * - TIM2_ETR: AF1 - * PA1: - * - TIM2_CH2: AF1 - * PA2: - * - TIM2_CH3: AF1 - * PA3: - * - TIM2_CH4: AF1 - * PA5: - * - TIM2_CH1: AF1 - * - TIM2_ETR: AF1 - * PA15: - * - TIM2_CH1: AF1 - * - TIM2_ETR: AF1 - * PB3: - * - TIM2_CH2: AF1 - * PB10: - * - TIM2_CH3: AF1 - * PB11: - * - TIM2_CH4: AF1 - */ - } break; - - case TimerRequest::GeneralPurpose_3: { - // 4 capture-compare channels - - /* TIM3 pins: - * PA6: - * - TIM3_CH1: AF2 - * PA7: - * - TIM3_CH2: AF2 - * PB0: - * - TIM3_CH3: AF2 - * PB1: - * - TIM3_CH4: AF2 - * PB4: - * - TIM3_CH1: AF2 - * PB5: - * - TIM3_CH2: AF2 - * PC6: - * - TIM3_CH1: AF2 - * PC7: - * - TIM3_CH2: AF2 - * PC8: - * - TIM3_CH3: AF2 - * PC9: - * - TIM3_CH4: AF2 - * PD2: - * - TIM3_ETR: AF2 - */ - } break; - - case TimerRequest::GeneralPurpose_4: { - // 4 capture-compare channels - - /* TIM4 pins: - * PB6: - * - TIM4_CH1: AF2 - * PB7: - * - TIM4_CH2: AF2 - * PB8: - * - TIM4_CH3: AF2 - * PB9: - * - TIM4_CH4: AF2 - * PD12: - * - TIM4_CH1: AF2 - * PD13: - * - TIM4_CH2: AF2 - * PD14: - * - TIM4_CH3: AF2 - * PD15: - * - TIM4_CH4: AF2 - * PE0: - * - TIM4_ETR: AF2 - */ - } break; - - case TimerRequest::GeneralPurpose32bit_5: { - // 4 capture-compare channels - - /* TIM5 pins: - * PA0: - * - TIM5_CH1: AF2 - * PA1: - * - TIM5_CH2: AF2 - * PA2: - * - TIM5_CH3: AF2 - * PA3: - * - TIM5_CH4: AF2 - * PA4: - * - TIM5_ETR: AF2 - */ - } break; - - case TimerRequest::Basic_6: - case TimerRequest::Basic_7: { - if(e.pin_count > 0) { - ST_LIB::compile_error("Basic timers can't use pins"); - } - } break; - - case TimerRequest::Advanced_8: { - // 4 capture-compare channels - // complementary output - - /* TIM8 pins: - * PA0: - * - TIM8_ETR: AF3 - * PA5: - * - TIM8_CH1N: AF3 - * PA6: - * - TIM8_BKIN: AF3 - * - TIM8_BKIN_COMP12: AF10 - * PA7: - * - TIM8_CH1N: AF3 - * PA8: - * - TIM8_BKIN2: AF3 - * - TIM8_BKIN2_COMP12: AD12 - * PB0: - * - TIM8_CH2N: AF3 - * PB1: - * - TIM8_CH3N: AF3 - * PB14: - * - TIM8_CH2N: AF3 - * PB15: - * - TIM8_CH3N: AF3 - * PC6: - * - TIM8_CH1: AF3 - * PC7: - * - TIM8_CH2: AF3 - * PC8: - * - TIM8_CH3: AF3 - * PC9: - * - TIM8_CH4: AF3 - * PG2: - * - TIM8_BKIN: AF3 - * - TIM8_BKIN_COMP12: AF11 - * PG3: - * - TIM8_BKIN2: AF3 - * - TIM8_BKIN2_COMP12: AF11 - * PG8: - * - TIM8_ETR: AF3 - */ - } break; - - case TimerRequest::SlaveTimer_12: { - // 2 capture-compare channels - - /* TIM12 pins: - * PB14: - * - TIM12_CH1: AF2 - * PB15: - * - TIM12_CH2: AF2 - */ - } break; - - case TimerRequest::SlaveTimer_13: { - // 1 capture-compare channel - - /* TIM13 pins: - * PA6: - * - TIM13_CH1: AF9 - * PF8: - * - TIM13_CH1: AF9 - */ - } break; - - case TimerRequest::SlaveTimer_14: { - // 1 capture-compare channel - - /* TIM14 pins: - * PA7: - * - TIM14_CH1: AF9 - * PF9: - * - TIM14_CH1: AF9 - */ - } break; - - case TimerRequest::GeneralPurpose_15: { - // 2 capture-compare channels - - /* TIM15 pins: - * PA0: - * - TIM15_BKIN: AF4 - * PA1: - * - TIM15_CH1N: AF4 - * PA2: - * - TIM15_CH1: AF4 - * PA3: - * - TIM15_CH2: AF4 - * PC12: - * - TIM15_CH1: AF2 - * PD2: - * - TIM15_BKIN: AF4 - * PE3: - * - TIM15_BKIN: AF4 - * PE4: - * - TIM15_CH1N: AF4 - * PE5: - * - TIM15_CH1: AF4 - * PE6: - * - TIM15_CH2: AF4 - */ - } break; - - case TimerRequest::GeneralPurpose_16: { - // 1 capture-compare channel - - /* TIM16 pins: - * PF6: - * - TIM16_CH1: AF1 - * PF8: - * - TIM16_CH1N: AF1 - * PF10: - * - TIM16_BKIN: AF1 - */ - } break; - - case TimerRequest::GeneralPurpose_17: { - // 1 capture-compare channel - - /* TIM17 pins: - * PB5: - * - TIM17_BKIN: AF1 - * PB7: - * - TIM17_CH1N: AF1 - * PB9: - * - TIM17_CH1: AF1 - * PF7: - * - TIM17_CH1: AF1 - * PF9: - * - TIM17_CH1N: AF1 - * PG6: - * - TIM17_BKIN: AF1 - */ - } break; - - case TimerRequest::GeneralPurpose32bit_23: { - // 4 capture-compare channels - - /* TIM23 pins: - * PB2: - * - TIM23_ETR: AF13 - * PF0: - * - TIM23_CH1: AF13 - * PF1: - * - TIM23_CH2: AF13 - * PF2: - * - TIM23_CH3: AF13 - * PF3: - * - TIM23_CH4: AF13 - * PF6: - * - TIM23_CH1: AF13 - * PF7: - * - TIM23_CH2: AF13 - * PF8: - * - TIM23_CH3: AF13 - * PF9: - * - TIM23_CH4: AF13 - * PG3: - * - TIM23_ETR: AF13 - * PG12: - * - TIM23_CH1: AF13 - * PG13: - * - TIM23_CH2: AF13 - * PG14: - * - TIM23_CH3: AF13 - */ - } break; - - case TimerRequest::GeneralPurpose32bit_24: { - // 4 capture-compare channels - - /* TIM24 pins: - * PB3: - * - TIM24_ETR: AF14 - * PF11: - * - TIM24_CH1: AF14 - * PF12: - * - TIM24_CH2: AF14 - * PF13: - * - TIM24_CH3: AF14 - * PF14: - * - TIM24_CH4: AF14 - * PG2: - * - TIM24_ETR: AF14 - */ - } break; + TimerPossiblePinSlice curr_pins = tim_pins[(int)e.request]; + for(int j = 0; j < curr_pins.pin_count; j++) { + // TODO } } } diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 756704303..7802a88a6 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -12,6 +12,7 @@ #include "HALAL/Models/TimerDomain/TimerDomain.hpp" #include "HALAL/Services/PWM/PWM/NewPWM.hpp" #include "HALAL/Models/GPIO.hpp" +#include "HALAL/Models/Pin.hpp" #include "ErrorHandler/ErrorHandler.hpp" @@ -29,7 +30,7 @@ struct TimerWrapper { static constexpr bool bits32timer = ( dev.e.request == TimerRequest::GeneralPurpose32bit_2 || - dev.e.request == TimerRequest::GeneralPurpose32bit_3 || + dev.e.request == TimerRequest::GeneralPurpose32bit_5 || dev.e.request == TimerRequest::GeneralPurpose32bit_23 || dev.e.request == TimerRequest::GeneralPurpose32bit_24 || dev.e.request == TimerRequest::Any32bit From 448b002573cde8910752860c0017383dcf35110e Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 20 Jan 2026 21:11:25 +0100 Subject: [PATCH 268/281] feat: Finish implementing check_pins --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 106 +++++++++++-------- Inc/HALAL/Services/PWM/PWM/NewPWM.hpp | 59 ++++++----- Inc/HALAL/Services/Time/TimerWrapper.hpp | 15 ++- 3 files changed, 110 insertions(+), 70 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 28354c751..ca04dc49e 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -13,6 +13,7 @@ #ifdef HAL_TIM_MODULE_ENABLED #include "HALAL/Models/GPIO.hpp" +#include "HALAL/Models/Pin.hpp" #include #include @@ -127,12 +128,24 @@ enum TimerRequest : uint8_t { enum class TimerAF { None, PWM, + InputCapture, + BreakInput, + BreakInputCompare, +}; + +enum class TimerChannel : uint8_t { + CHANNEL_1 = 1, + CHANNEL_2 = 2, + CHANNEL_3 = 3, + CHANNEL_4 = 4, + CHANNEL_5 = 5, + CHANNEL_6 = 6, }; struct TimerPin { - TimerAF af; + ST_LIB::TimerAF af; ST_LIB::GPIODomain::Pin pin; - uint8_t channel; + ST_LIB::TimerChannel channel; }; constexpr std::array create_timer_idxmap() { @@ -563,10 +576,10 @@ struct TimerDomain { static consteval void check_pins(std::span requests) { enum TimerAF_Use { - Channel_1, - Channel_2, - Channel_3, - Channel_4, + Channel_1 = 1, + Channel_2 = 2, + Channel_3 = 3, + Channel_4 = 4, ExternalTriggerFilter, /* ETR */ BreakInput_1, BreakInput_2, @@ -621,7 +634,7 @@ struct TimerDomain { {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}, + {ST_LIB::PA12, (ST_LIB::GPIODomain::AlternateFunction)12, BreakInput_2}, // comprobar }; TimerPossiblePin tim2pins[] = { // 4 capture-compare channels @@ -786,41 +799,22 @@ struct TimerDomain { {ST_LIB::PG2, (ST_LIB::GPIODomain::AlternateFunction)14, ExternalTriggerFilter}, }; - struct TimerPossiblePinSlice { - std::span pins; - int pin_count; - }; - - TimerPossiblePinSlice tim_pins[25]; - tim_pins[TimerRequest::Advanced_1] = - {std::span(tim1pins), ARRAY_LENGTH(tim1pins)}; - tim_pins[TimerRequest::GeneralPurpose32bit_2] = - {std::span(tim2pins), ARRAY_LENGTH(tim2pins)}; - tim_pins[TimerRequest::GeneralPurpose_3] = - {std::span(tim3pins), ARRAY_LENGTH(tim3pins)}; - tim_pins[TimerRequest::GeneralPurpose_4] = - {std::span(tim4pins), ARRAY_LENGTH(tim4pins)}; - tim_pins[TimerRequest::GeneralPurpose32bit_5] = - {std::span(tim5pins), ARRAY_LENGTH(tim5pins)}; + 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), ARRAY_LENGTH(tim8pins)}; - tim_pins[TimerRequest::SlaveTimer_12] = - {std::span(tim12pins), ARRAY_LENGTH(tim12pins)}; - tim_pins[TimerRequest::SlaveTimer_13] = - {std::span(tim13pins), ARRAY_LENGTH(tim13pins)}; - tim_pins[TimerRequest::SlaveTimer_14] = - {std::span(tim14pins), ARRAY_LENGTH(tim14pins)}; - tim_pins[TimerRequest::GeneralPurpose_15] = - {std::span(tim15pins), ARRAY_LENGTH(tim15pins)}; - tim_pins[TimerRequest::GeneralPurpose_16] = - {std::span(tim16pins), ARRAY_LENGTH(tim16pins)}; - tim_pins[TimerRequest::GeneralPurpose_17] = - {std::span(tim17pins), ARRAY_LENGTH(tim17pins)}; - tim_pins[TimerRequest::GeneralPurpose32bit_23] = - {std::span(tim23pins), ARRAY_LENGTH(tim23pins)}; - tim_pins[TimerRequest::GeneralPurpose32bit_24] = - {std::span(tim24pins), ARRAY_LENGTH(tim24pins)}; + 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++) { @@ -837,9 +831,33 @@ struct TimerDomain { ST_LIB::compile_error("Basic timers can't use pins"); } - TimerPossiblePinSlice curr_pins = tim_pins[(int)e.request]; - for(int j = 0; j < curr_pins.pin_count; j++) { - // TODO + 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"); + } } } } diff --git a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp index 20276eb91..23618d94b 100644 --- a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp +++ b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp @@ -28,25 +28,34 @@ struct PWMData { template class PWM { - static constexpr size_t channel_to_CCR[7] = { - 0, - offsetof(TIM_TypeDef, CCR1), - offsetof(TIM_TypeDef, CCR2), - offsetof(TIM_TypeDef, CCR3), - offsetof(TIM_TypeDef, CCR4), - offsetof(TIM_TypeDef, CCR5), - offsetof(TIM_TypeDef, CCR6) - }; - - static constexpr uint32_t channel_to_channel_state_idx[7] = { - 0, - 0, 1, 2, 3, 4, 5, - }; - - static constexpr uint32_t channel_to_channelmul4[7] = { - 0, - 0x0, 0x4, 0x8, 0xC, 0x10, 0x14 - }; + static consteval uint8_t get_channel_state_idx(const ST_LIB::TimerChannel ch) { + switch(ch) { + case TimerChannel::CHANNEL_1: + case TimerChannel::CHANNEL_2: + case TimerChannel::CHANNEL_3: + case TimerChannel::CHANNEL_4: + case TimerChannel::CHANNEL_5: + case TimerChannel::CHANNEL_6: + return static_cast(ch) - 1; + + default: ST_LIB::compile_error("unreachable"); + return 0; + } + } + + static consteval uint8_t get_channel_mul4(const ST_LIB::TimerChannel ch) { + switch(ch) { + case TimerChannel::CHANNEL_1: return 0x00; + case TimerChannel::CHANNEL_2: return 0x04; + case TimerChannel::CHANNEL_3: return 0x08; + case TimerChannel::CHANNEL_4: return 0x0C; + case TimerChannel::CHANNEL_5: return 0x10; + case TimerChannel::CHANNEL_6: return 0x14; + + default: ST_LIB::compile_error("unreachable"); + return 0; + } + } 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; @@ -69,16 +78,16 @@ class PWM { if(is_on) return; // if(HAL_TIM_PWM_Start(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } - HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[channel_to_channel_state_idx[pin.channel]]; + HAL_TIM_ChannelStateTypeDef *state = &timer.htim.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 << (channel_to_channelmul4[pin.channel] & 0x1FU); /* 0x1FU = 31 bits max shift */ + 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 << (channel_to_channelmul4[pin.channel] & 0x1FU))); + SET_BIT(timer.tim->CCER, (uint32_t)(TIM_CCx_ENABLE << (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)) @@ -105,7 +114,7 @@ class PWM { if(!is_on) return; // if(HAL_TIM_PWM_Stop(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } - SET_BIT(timer.tim->CCER, (uint32_t)(TIM_CCx_DISABLE << (channel_to_channelmul4[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)) @@ -116,7 +125,7 @@ class PWM { __HAL_TIM_DISABLE(timer.htim); - HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[channel_to_channel_state_idx[pin.channel]]; + HAL_TIM_ChannelStateTypeDef *state = &timer.htim.ChannelState[get_channel_state_idx(pin.channel)]; *state = HAL_TIM_CHANNEL_STATE_READY; is_on = false; @@ -125,7 +134,7 @@ class PWM { 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) + channel_to_CCR[pin.channel]) = raw_duty; + *(uint16_t*)((uint8_t*)(timer->tim) + timer.get_CCR_offset(pin.channel)) = raw_duty; this->duty_cycle = duty_cycle; } diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 7802a88a6..40b37dc01 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -12,7 +12,6 @@ #include "HALAL/Models/TimerDomain/TimerDomain.hpp" #include "HALAL/Services/PWM/PWM/NewPWM.hpp" #include "HALAL/Models/GPIO.hpp" -#include "HALAL/Models/Pin.hpp" #include "ErrorHandler/ErrorHandler.hpp" @@ -160,6 +159,20 @@ struct TimerWrapper { 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; From b3340b25e975ede021deb82edab2a5af7426cacd Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 20 Jan 2026 22:03:04 +0100 Subject: [PATCH 269/281] Add tests for TimerWrapper, not running them yet --- Inc/HALAL/Services/Time/TimerWrapper.hpp | 16 +--- Tests/Time/timer_wrapper_test.cpp | 107 +++++++++++++++++++++++ 2 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 Tests/Time/timer_wrapper_test.cpp diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 40b37dc01..b875cc869 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -110,19 +110,19 @@ struct TimerWrapper { inline void break_interrupt_enable() { static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); - ErrorHandler("Break interrupt is not allowed currently because gp timers {TIM12, TIM13, TIM14} use the same interrupt callback"); + SET_BIT(instance.tim->DIER, TIM_DIER_BIE); } inline void break_interrupt_disable() { static_assert(dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8, "Error: Break interrupt enable only allowed in advanced timers {TIM1, TIM8}"); - SET_BIT(instance.tim->DIER, TIM_DIER_BIE); + CLEAR_BIT(instance.tim->DIER, TIM_DIER_BIE); } /* interrupt gets called only once, counter needs to be reenabled */ inline void set_one_pulse_mode() { SET_BIT(instance.tim->CR1, TIM_CR1_OPM); } - inline void multi_interrupt() { + inline void set_multi_interrupt_mode() { CLEAR_BIT(instance.tim->CR1, TIM_CR1_OPM); } @@ -181,16 +181,6 @@ struct TimerWrapper { return instance.tim->ARR; } -#if 0 - if constexpr (dev.e.request == TimerRequest::Advanced_1 || dev.e.request == TimerRequest::Advanced_8) { - // advanced specific functions - } - - if constexpr (dev.e.request != TimerRequest::Basic_6 && dev.e.request != TimerRequest::Basic_7) { - // general purpose and advanced functions - } -#endif - /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ template inline void set_mode(void) { diff --git a/Tests/Time/timer_wrapper_test.cpp b/Tests/Time/timer_wrapper_test.cpp new file mode 100644 index 000000000..284168eca --- /dev/null +++ b/Tests/Time/timer_wrapper_test.cpp @@ -0,0 +1,107 @@ +#include +#include +#include + +#include "HALAL/Services/Timer/TimerWrapper.hpp" +#include "ST-LIB.hpp" + +class TimerWrapperTests : public ::testing::Test { +protected: + void SetUp() override { + // Reset global callback task count + count = 0; + + // Reset Timer + TIM1_BASE->CNT = 0; + TIM1_BASE->ARR = 0; + TIM1_BASE->SR = 0; + TIM1_BASE->CR1 = 0; + TIM1_BASE->DIER = 0; + } +}; + +constexpr ST_LIB::TimerDomain::Timer tim1{{ + .request = ST_LIB::TimerRequest::Advanced_1, +}}; + +TEST_F(TimerWrapperTests, Counter_EnabledDisabled) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.counter_enable(); + EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_CEN, TIM_CR1_CEN); + tim2.counter_disable(); + EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_CEN, 0); +} + +TEST_F(TimerWrapperTests, UpdateInterrupt_EnabledDisabled) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.enable_update_interrupt(); + EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_UIE, TIM_DIER_UIE); + tim2.disable_update_interrupt(); + EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_UIE, 0); +} + +TEST_F(TimerWrapperTests, NVIC_EnabledDisabled) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.enable_nvic(); + EXPECT_EQ(NVIC_GetEnableIRQ(TIM2_IRQn), 1); + tim2.disable_nvic(); + EXPECT_EQ(NVIC_GetEnableIRQ(TIM2_IRQn), 0); +} + +TEST_F(TimerWrapperTests, UpdateEvent_EnabledDisabled) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.enable_update_event(); + EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_UDIS, 0); + tim2.disable_update_event(); + EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_UDIS, TIM_CR1_UDIS); +} + +TEST_F(TimerWrapperTests, BreakInterrupt_EnabledDisabled) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.break_interrupt_enable(); + EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_BIE, TIM_DIER_BIE); + tim2.break_interrupt_disable(); + EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_BIE, 0); +} + +TEST_F(TimerWrapperTests, BreakInterrupt_EnabledDisabled) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.set_one_pulse_mode(); + EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_OPM, TIM_CR1_OPM); + tim2.set_multi_interrupt_mode(); + EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_OPM, 0); +} + +void callback(void *raw) {} + +TEST_F(TimerWrapperTests, ConfigureTimer) { + auto testBoard = ST_LIB::Board; + testBoard.init(); + +#define PRESCALER_VAL 200 +#define PERIOD 1000 + auto tim2 = get_timer_instance(testBoard, tim2); + tim2.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 */ +} + From 5bde564e641fe228a8d7e416670bd4617dc44434 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 21 Jan 2026 01:03:39 +0100 Subject: [PATCH 270/281] Almost implement all wrappers for TimerDomain tests --- Inc/HALAL/Models/PinModel/Pin.hpp | 2 +- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 63 ++------------ Inc/HALAL/Services/Time/Scheduler.hpp | 2 + Inc/HALAL/Services/Time/TimerWrapper.hpp | 8 +- Inc/MockedDrivers/common.hpp | 14 +-- Inc/MockedDrivers/compiler_specific.hpp | 2 +- Inc/MockedDrivers/mocked_ll_tim.hpp | 64 +++++++++++--- Inc/MockedDrivers/stm32h723xx_wrapper.h | 11 ++- Inc/MockedDrivers/stm32h7xx_hal_wrapper.h | 14 +++ Inc/MockedDrivers/stm32h7xx_ll_adc_wrapper.h | 15 ++++ Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h | 2 - Src/MockedDrivers/mocked_ll_tim.cpp | 11 ++- Tests/CMakeLists.txt | 1 + Tests/Time/timer_wrapper_test.cpp | 92 ++++++++++---------- 14 files changed, 172 insertions(+), 129 deletions(-) create mode 100644 Inc/MockedDrivers/stm32h7xx_hal_wrapper.h create mode 100644 Inc/MockedDrivers/stm32h7xx_ll_adc_wrapper.h diff --git a/Inc/HALAL/Models/PinModel/Pin.hpp b/Inc/HALAL/Models/PinModel/Pin.hpp index 579bf05bd..9a2ab4895 100644 --- a/Inc/HALAL/Models/PinModel/Pin.hpp +++ b/Inc/HALAL/Models/PinModel/Pin.hpp @@ -112,7 +112,7 @@ struct hash { using std::string; return ((hash()(k.gpio_pin) ^ - (hash()((uint32_t)(k.port)) << 1)) >> + (hash()((size_t)(k.port)) << 1)) >> 1); } }; diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index ca04dc49e..c0a157983 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -7,8 +7,11 @@ #pragma once +#ifndef TESTING_ENV #include "stm32h7xx_hal.h" -//#include "stm32h7xx_hal_tim.h" +#else +#include "MockedDrivers/stm32h7xx_hal_wrapper.h" +#endif #ifdef HAL_TIM_MODULE_ENABLED @@ -195,12 +198,6 @@ struct TimerDomain { CENTER_ALIGNED_INTERRUPT_BOTH = 4, }; - enum Kind : uint8_t { - Basic, - GeneralPurpose, - Advanced, - }; - struct Entry { std::array name; /* max length = 7 */ TimerRequest request; @@ -213,8 +210,6 @@ struct TimerDomain { }; struct Config { - char name[8]; /* "Timerxx\0" */ - TimerDomain::Kind kind; uint16_t timer_idx; TimerDomain::CountingMode counting_mode; uint32_t deadtime; @@ -235,6 +230,9 @@ struct TimerDomain { &htim1, &htim8 }; +#ifdef TESTING_ENV + static TIM_TypeDef *cmsis_timers[16]; +#else static constexpr TIM_TypeDef *cmsis_timers[16] = { // general purpose timers TIM2, TIM3, TIM4, TIM5, TIM23, TIM24, @@ -247,6 +245,7 @@ struct TimerDomain { // advanced control timers TIM1, TIM8 }; +#endif static constexpr IRQn_Type timer_irqn[] = { // general purpose timers 1 @@ -277,21 +276,6 @@ struct TimerDomain { static constexpr Config DoTimer(const Entry request, int reqint, int reqidx) { Config cfg; - if(request.name[0] == '\0') { - /* "Timer" + tostring(reqint) */ - cfg.name[0] = 'T'; - cfg.name[1] = 'i'; - cfg.name[2] = 'm'; - cfg.name[3] = 'e'; - cfg.name[4] = 'r'; - cfg.name[5] = (reqint/10) + '0'; - cfg.name[6] = (reqint%10) + '0'; - cfg.name[7] = '\0'; - } else { - for(int si = 0; si < 8; si++) { - cfg.name[si] = request.name[si]; - } - } cfg.timer_idx = timer_idxmap[reqint]; cfg.deadtime = request.deadtime; cfg.polarity = request.polarity; @@ -307,26 +291,6 @@ struct TimerDomain { } } - if(request.request == Basic_6 || request.request == Basic_7) { - // basic timers - cfg.kind = TimerDomain::Kind::Basic; - } else if(request.request == Advanced_1 || request.request == Advanced_8) { - // advanced timers - cfg.kind = TimerDomain::Kind::Advanced; - } else { - if(cfg.timer_idx >= 0 && cfg.timer_idx <= 5) { - // general purpose timers 1 - } else if(cfg.timer_idx >= 6 && cfg.timer_idx <= 8) { - // general purpose timers 2 - } else if(cfg.timer_idx >= 9 && cfg.timer_idx <= 11) { - // general purpose timers 3 - } else { - ST_LIB::compile_error("Unknown timer idx"); - } - - cfg.kind = TimerDomain::Kind::GeneralPurpose; - } - return cfg; } @@ -510,10 +474,8 @@ struct TimerDomain { // Runtime object struct Instance { - char name[8]; TIM_TypeDef *tim; TIM_HandleTypeDef *hal_tim; - TimerDomain::Kind kind; uint16_t timer_idx; }; @@ -558,15 +520,6 @@ struct TimerDomain { Instance *inst = &instances[i]; inst->tim = tim; inst->hal_tim = handle; - inst->name[0] = e.name[0]; - inst->name[1] = e.name[1]; - inst->name[2] = e.name[2]; - inst->name[3] = e.name[3]; - inst->name[4] = e.name[4]; - inst->name[5] = e.name[5]; - inst->name[6] = e.name[6]; - inst->name[7] = e.name[7]; - inst->kind = e.kind; inst->timer_idx = e.timer_idx; __NOP(); } diff --git a/Inc/HALAL/Services/Time/Scheduler.hpp b/Inc/HALAL/Services/Time/Scheduler.hpp index 3c15f27b1..0983199ef 100644 --- a/Inc/HALAL/Services/Time/Scheduler.hpp +++ b/Inc/HALAL/Services/Time/Scheduler.hpp @@ -22,8 +22,10 @@ # define SCHEDULER_TIMER_IDX 2 #endif +#ifndef glue #define glue_(a,b) a ## b #define glue(a,b) glue_(a,b) +#endif #define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE)) // Used to reserve a TimerPeripheral diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index b875cc869..71abc4f02 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -7,6 +7,12 @@ #pragma once +#ifndef TESTING_ENV +#include "stm32h7xx_hal.h" +#else +#include "MockedDrivers/stm32h7xx_hal_wrapper.h" +#endif + #ifdef HAL_TIM_MODULE_ENABLED #include "HALAL/Models/TimerDomain/TimerDomain.hpp" @@ -15,8 +21,6 @@ #include "ErrorHandler/ErrorHandler.hpp" -#include "stm32h7xx_hal.h" - #define get_timer_instance(board, timer_type) \ ST_LIB::TimerWrapper(board::instance_of()) diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index def8838ec..91b8da9f8 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -1,17 +1,11 @@ #pragma once -#include "MockedDrivers/compiler_specific.hpp" -#ifdef __cplusplus - #define __I volatile /*!< Defines 'read only' permissions */ -#else - #define __I volatile const /*!< Defines 'read only' permissions */ + +#ifndef glue +#define glue_(a,b) a##b +#define glue(a,b) glue_(a,b) #endif -#define __O volatile /*!< Defines 'write only' permissions */ -#define __IO volatile /*!< Defines 'read / write' permissions */ /* following defines should be used for structure members */ -#define __IM volatile const /*! Defines 'read only' structure member permissions */ -#define __OM volatile /*! Defines 'write only' structure member permissions */ -#define __IOM volatile /*! Defines 'read / write' structure member permissions */ #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) diff --git a/Inc/MockedDrivers/compiler_specific.hpp b/Inc/MockedDrivers/compiler_specific.hpp index bca6c858c..c841e35d3 100644 --- a/Inc/MockedDrivers/compiler_specific.hpp +++ b/Inc/MockedDrivers/compiler_specific.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include /* * This file contains implementations or alternate names for diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index eb5a8b3bf..66f13872b 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -1,11 +1,11 @@ #pragma once -#include +#include #include "MockedDrivers/stm32h723xx_wrapper.h" #include "stm32h7xx.h" #include "MockedDrivers/common.hpp" #include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/Register.hpp" -#include +#include enum class TimReg { Reg_CR1, Reg_CR2, Reg_SMCR, Reg_DIER, Reg_SR, Reg_EGR, Reg_CCMR1, Reg_CCMR2, Reg_CCER, Reg_CNT, Reg_PSC, Reg_ARR, Reg_RCR, @@ -14,8 +14,6 @@ enum class TimReg { }; using enum TimReg; - - template class TimerRegister : public RegisterBase { public: @@ -23,6 +21,28 @@ class TimerRegister : public RegisterBase { using RegisterBase::operator=; }; +// temp until scheduler uses TimerDomain +#ifndef TimerXList +#define TimerXList \ + X(2, APB1LENR) \ + X(3, APB1LENR) \ + X(4, APB1LENR) \ + X(5, APB1LENR) \ + X(6, APB1LENR) \ + X(7, APB1LENR) \ + X(12, APB1LENR) \ + X(13, APB1LENR) \ + X(14, APB1LENR) \ + \ + X(23, APB1HENR) \ + X(24, APB1HENR) \ + \ + X(1, APB2ENR) \ + X(8, APB2ENR) \ + X(15, APB2ENR) \ + X(16, APB2ENR) \ + X(17, APB2ENR) +#endif static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); @@ -96,7 +116,7 @@ struct TIM_TypeDef{ // 1. Check if Counter is Enabled if (!(CR1 & CR1_CEN)) { - std::cout<<"TIMER IS NOT ENABLED!!\n"; + printf("TIMER IS NOT ENABLED!!\n"); return false; } // 2. Prescaler Logic @@ -135,15 +155,35 @@ struct RegisterTraits { */ #define DECLARE_TIMER(TIM_IDX) \ - extern TIM_TypeDef* TIM_IDX##_BASE; \ + extern TIM_TypeDef* glue(TIM, glue(TIM_IDX, _BASE)); \ extern "C"{ \ - void TIM_IDX##_IRQHandler(void); \ + void glue(TIM, glue(TIM_IDX, _IRQHandler))(void); \ } + #define INSTANTIATE_TIMER(TIM_IDX) \ - TIM_TypeDef __htim##TIM_IDX{TIM_IDX##_IRQHandler,TIM_IDX##_IRQn}; \ - TIM_TypeDef* TIM_IDX##_BASE = &__htim##TIM_IDX; + TIM_TypeDef __htim##TIM_IDX { \ + glue(TIM, glue(TIM_IDX, _IRQHandler)), \ + glue(TIM, glue(TIM_IDX, _IRQn)) \ + }; \ + TIM_TypeDef *glue(TIM, glue(TIM_IDX, _BASE)) = &__htim##TIM_IDX; -#undef TIM1_BASE -DECLARE_TIMER(TIM1) #undef TIM2_BASE -DECLARE_TIMER(TIM2) +#undef TIM3_BASE +#undef TIM4_BASE +#undef TIM5_BASE +#undef TIM6_BASE +#undef TIM7_BASE +#undef TIM12_BASE +#undef TIM13_BASE +#undef TIM14_BASE +#undef TIM23_BASE +#undef TIM24_BASE +#undef TIM1_BASE +#undef TIM8_BASE +#undef TIM15_BASE +#undef TIM16_BASE +#undef TIM17_BASE + +#define X(n, ignore) DECLARE_TIMER(n) +TimerXList +#undef X diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index 6d5850340..b83fba014 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -11,12 +11,19 @@ # error :) #endif +#ifndef __I #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permissions */ #else #define __I volatile const /*!< Defines 'read only' permissions */ #endif -#define __IO volatile +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ #define __RBIT __RBIT__CMSIS #define TIM_TypeDef TIM_TypeDef__CMSIS @@ -31,4 +38,6 @@ #undef RCC extern RCC_TypeDef *RCC; +#include "MockedDrivers/compiler_specific.hpp" + #endif // STM32H723xx_WRAPPER_H diff --git a/Inc/MockedDrivers/stm32h7xx_hal_wrapper.h b/Inc/MockedDrivers/stm32h7xx_hal_wrapper.h new file mode 100644 index 000000000..a7b546ed8 --- /dev/null +++ b/Inc/MockedDrivers/stm32h7xx_hal_wrapper.h @@ -0,0 +1,14 @@ +#ifndef STM32H7xx_HAL_WRAPPER_H +#define STM32H7xx_HAL_WRAPPER_H + +#include "MockedDrivers/stm32h723xx_wrapper.h" + +#include "MockedDrivers/stm32h7xx_ll_adc_wrapper.h" +#include "MockedDrivers/stm32h7xx_ll_tim_wrapper.h" + +#include "stm32h7xx_hal.h" + + +#include "MockedDrivers/common.hpp" + +#endif // STM32H7xx_HAL_WRAPPER_H \ No newline at end of file diff --git a/Inc/MockedDrivers/stm32h7xx_ll_adc_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_adc_wrapper.h new file mode 100644 index 000000000..038455a4a --- /dev/null +++ b/Inc/MockedDrivers/stm32h7xx_ll_adc_wrapper.h @@ -0,0 +1,15 @@ +#ifndef STM32H7xx_LL_ADC_WRAPPER_H +#define STM32H7xx_LL_ADC_WRAPPER_H + +#include + +#include "MockedDrivers/stm32h723xx_wrapper.h" +//#include "MockedDrivers/mocked_ll_adc.hpp" + +#define uint32_t size_t +#include "stm32h7xx_ll_adc.h" +#undef uint32_t + +#include "MockedDrivers/common.hpp" + +#endif // STM32H7xx_LL_ADC_WRAPPER_H diff --git a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h index 904f5bb5f..31e724d12 100644 --- a/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h +++ b/Inc/MockedDrivers/stm32h7xx_ll_tim_wrapper.h @@ -5,8 +5,6 @@ #include "MockedDrivers/stm32h723xx_wrapper.h" -#include "stm32h7xx.h" - #include "MockedDrivers/mocked_ll_tim.hpp" #define uint32_t size_t diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index 2d1dd0edb..8afd2f4db 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -2,7 +2,16 @@ #include -INSTANTIATE_TIMER(TIM2) +#define TIM1_IRQn TIM1_UP_IRQn +#define TIM6_IRQn TIM6_DAC_IRQn +#define TIM8_IRQn TIM8_UP_TIM13_IRQn +#define TIM12_IRQn TIM8_BRK_TIM12_IRQn +#define TIM13_IRQn TIM8_UP_TIM13_IRQn +#define TIM14_IRQn TIM8_TRG_COM_TIM14_IRQn + +#define X(n, ignore) INSTANTIATE_TIMER(n) +TimerXList +#undef X void TIM_TypeDef::generate_update() { active_PSC = PSC; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 979dead33..116173e62 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -16,6 +16,7 @@ message(STATUS "Generating test executable for ST-LIB") add_executable(${STLIB_TEST_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/Time/scheduler_test.cpp + ${CMAKE_CURRENT_LIST_DIR}/Time/timer_wrapper_test.cpp ) set_target_properties(${STLIB_TEST_EXECUTABLE} PROPERTIES diff --git a/Tests/Time/timer_wrapper_test.cpp b/Tests/Time/timer_wrapper_test.cpp index 284168eca..b3311725e 100644 --- a/Tests/Time/timer_wrapper_test.cpp +++ b/Tests/Time/timer_wrapper_test.cpp @@ -2,104 +2,108 @@ #include #include -#include "HALAL/Services/Timer/TimerWrapper.hpp" -#include "ST-LIB.hpp" +#include "HALAL/Services/Time/TimerWrapper.hpp" class TimerWrapperTests : public ::testing::Test { protected: void SetUp() override { - // Reset global callback task count - count = 0; - // Reset Timer TIM1_BASE->CNT = 0; TIM1_BASE->ARR = 0; TIM1_BASE->SR = 0; TIM1_BASE->CR1 = 0; TIM1_BASE->DIER = 0; + + ST_LIB::TimerDomain::cmsis_timers[0] = TIM2_BASE; + ST_LIB::TimerDomain::cmsis_timers[1] = TIM3_BASE; + ST_LIB::TimerDomain::cmsis_timers[2] = TIM4_BASE; + ST_LIB::TimerDomain::cmsis_timers[3] = TIM5_BASE; + ST_LIB::TimerDomain::cmsis_timers[4] = TIM23_BASE; + ST_LIB::TimerDomain::cmsis_timers[5] = TIM24_BASE; + ST_LIB::TimerDomain::cmsis_timers[6] = TIM12_BASE; + ST_LIB::TimerDomain::cmsis_timers[7] = TIM13_BASE; + ST_LIB::TimerDomain::cmsis_timers[8] = TIM14_BASE; + ST_LIB::TimerDomain::cmsis_timers[9] = TIM15_BASE; + ST_LIB::TimerDomain::cmsis_timers[10] = TIM16_BASE; + ST_LIB::TimerDomain::cmsis_timers[11] = TIM17_BASE; + ST_LIB::TimerDomain::cmsis_timers[12] = TIM6_BASE; + ST_LIB::TimerDomain::cmsis_timers[13] = TIM7_BASE; + ST_LIB::TimerDomain::cmsis_timers[14] = TIM1_BASE; + ST_LIB::TimerDomain::cmsis_timers[15] = TIM8_BASE; } }; -constexpr ST_LIB::TimerDomain::Timer tim1{{ +constexpr ST_LIB::TimerDomain::Timer tim1_decl{{ .request = ST_LIB::TimerRequest::Advanced_1, }}; +ST_LIB::TimerDomain::Instance tim1_inst { + .tim = TIM1_BASE, + .hal_tim = 0, + .timer_idx = 14, +}; TEST_F(TimerWrapperTests, Counter_EnabledDisabled) { - auto testBoard = ST_LIB::Board; - testBoard.init(); + ST_LIB::TimerWrapper tim1(tim1_inst); - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.counter_enable(); + tim1.counter_enable(); EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_CEN, TIM_CR1_CEN); - tim2.counter_disable(); + tim1.counter_disable(); EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_CEN, 0); } TEST_F(TimerWrapperTests, UpdateInterrupt_EnabledDisabled) { - auto testBoard = ST_LIB::Board; - testBoard.init(); + ST_LIB::TimerWrapper tim1(tim1_inst); - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.enable_update_interrupt(); + tim1.enable_update_interrupt(); EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_UIE, TIM_DIER_UIE); - tim2.disable_update_interrupt(); + tim1.disable_update_interrupt(); EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_UIE, 0); } TEST_F(TimerWrapperTests, NVIC_EnabledDisabled) { - auto testBoard = ST_LIB::Board; - testBoard.init(); - - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.enable_nvic(); - EXPECT_EQ(NVIC_GetEnableIRQ(TIM2_IRQn), 1); - tim2.disable_nvic(); - EXPECT_EQ(NVIC_GetEnableIRQ(TIM2_IRQn), 0); + ST_LIB::TimerWrapper tim1(tim1_inst); + + tim1.enable_nvic(); + EXPECT_EQ(NVIC_GetEnableIRQ(TIM1_UP_IRQn), 1); + tim1.disable_nvic(); + EXPECT_EQ(NVIC_GetEnableIRQ(TIM1_UP_IRQn), 0); } TEST_F(TimerWrapperTests, UpdateEvent_EnabledDisabled) { - auto testBoard = ST_LIB::Board; - testBoard.init(); + ST_LIB::TimerWrapper tim1(tim1_inst); - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.enable_update_event(); + tim1.enable_update_event(); EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_UDIS, 0); - tim2.disable_update_event(); + tim1.disable_update_event(); EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_UDIS, TIM_CR1_UDIS); } TEST_F(TimerWrapperTests, BreakInterrupt_EnabledDisabled) { - auto testBoard = ST_LIB::Board; - testBoard.init(); + ST_LIB::TimerWrapper tim1(tim1_inst); - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.break_interrupt_enable(); + tim1.break_interrupt_enable(); EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_BIE, TIM_DIER_BIE); - tim2.break_interrupt_disable(); + tim1.break_interrupt_disable(); EXPECT_EQ(TIM1_BASE->DIER & TIM_DIER_BIE, 0); } -TEST_F(TimerWrapperTests, BreakInterrupt_EnabledDisabled) { - auto testBoard = ST_LIB::Board; - testBoard.init(); +TEST_F(TimerWrapperTests, OnePulseMode_EnabledDisabled) { + ST_LIB::TimerWrapper tim1(tim1_inst); - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.set_one_pulse_mode(); + tim1.set_one_pulse_mode(); EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_OPM, TIM_CR1_OPM); - tim2.set_multi_interrupt_mode(); + tim1.set_multi_interrupt_mode(); EXPECT_EQ(TIM1_BASE->CR1 & TIM_CR1_OPM, 0); } void callback(void *raw) {} TEST_F(TimerWrapperTests, ConfigureTimer) { - auto testBoard = ST_LIB::Board; - testBoard.init(); + ST_LIB::TimerWrapper tim1(tim1_inst); #define PRESCALER_VAL 200 #define PERIOD 1000 - auto tim2 = get_timer_instance(testBoard, tim2); - tim2.configure16bit(callback, 0, PERIOD); + 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 */ From e7692cce98c84440cad7fd6d26d0ebc8afa766a7 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 21 Jan 2026 01:11:48 +0100 Subject: [PATCH 271/281] Add TimerDomain.cpp to simulator --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57955f586..a730486b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -242,6 +242,7 @@ add_library(${STLIB_LIBRARY} STATIC $<$:${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/HALAL/Services/Time/Scheduler.cpp> + $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/HALAL/Models/TimerDomain/TimerDomain.cpp> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/mocked_ll_tim.cpp> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/mocked_system_stm32h7xx.c> $<$>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h723xx_wrapper.c> From 44395e856664934c58f5ea6adcf45733a072a630 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 21 Jan 2026 01:25:46 +0100 Subject: [PATCH 272/281] Further fix compile errors --- Inc/MockedDrivers/mocked_ll_tim.hpp | 72 +++++++++++++---------------- Src/MockedDrivers/mocked_ll_tim.cpp | 42 +++++++++++++---- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 66f13872b..0ce554094 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -21,29 +21,6 @@ class TimerRegister : public RegisterBase { using RegisterBase::operator=; }; -// temp until scheduler uses TimerDomain -#ifndef TimerXList -#define TimerXList \ - X(2, APB1LENR) \ - X(3, APB1LENR) \ - X(4, APB1LENR) \ - X(5, APB1LENR) \ - X(6, APB1LENR) \ - X(7, APB1LENR) \ - X(12, APB1LENR) \ - X(13, APB1LENR) \ - X(14, APB1LENR) \ - \ - X(23, APB1HENR) \ - X(24, APB1HENR) \ - \ - X(1, APB2ENR) \ - X(8, APB2ENR) \ - X(15, APB2ENR) \ - X(16, APB2ENR) \ - X(17, APB2ENR) -#endif - static_assert(sizeof(TimerRegister) == sizeof(uint32_t) ); @@ -154,19 +131,6 @@ struct RegisterTraits { }; */ -#define DECLARE_TIMER(TIM_IDX) \ - extern TIM_TypeDef* glue(TIM, glue(TIM_IDX, _BASE)); \ - extern "C"{ \ - void glue(TIM, glue(TIM_IDX, _IRQHandler))(void); \ - } - -#define INSTANTIATE_TIMER(TIM_IDX) \ - TIM_TypeDef __htim##TIM_IDX { \ - glue(TIM, glue(TIM_IDX, _IRQHandler)), \ - glue(TIM, glue(TIM_IDX, _IRQn)) \ - }; \ - TIM_TypeDef *glue(TIM, glue(TIM_IDX, _BASE)) = &__htim##TIM_IDX; - #undef TIM2_BASE #undef TIM3_BASE #undef TIM4_BASE @@ -184,6 +148,36 @@ struct RegisterTraits { #undef TIM16_BASE #undef TIM17_BASE -#define X(n, ignore) DECLARE_TIMER(n) -TimerXList -#undef X +extern TIM_TypeDef* TIM2_BASE; +extern "C"{ void TIM2_IRQHandler(void); } +extern TIM_TypeDef* TIM3_BASE; +extern "C"{ void TIM3_IRQHandler(void); } +extern TIM_TypeDef* TIM4_BASE; +extern "C"{ void TIM4_IRQHandler(void); } +extern TIM_TypeDef* TIM5_BASE; +extern "C"{ void TIM5_IRQHandler(void); } +extern TIM_TypeDef* TIM6_BASE; +extern "C"{ void TIM6_DAC_IRQHandler(void); } +extern TIM_TypeDef* TIM7_BASE; +extern "C"{ void TIM7_IRQHandler(void); } + +extern TIM_TypeDef* TIM12_BASE; +extern "C"{ void TIM8_BRK_TIM12_IRQHandler(void); } +extern TIM_TypeDef* TIM13_BASE; +extern TIM_TypeDef* TIM14_BASE; +extern "C"{ void TIM8_TRG_COM_TIM14_IRQHandler(void); } + +extern TIM_TypeDef* TIM23_BASE; +extern "C"{ void TIM23_IRQHandler(void); } +extern TIM_TypeDef* TIM24_BASE; +extern "C"{ void TIM24_IRQHandler(void); } +extern TIM_TypeDef* TIM1_BASE; +extern "C"{ void TIM1_UP_IRQHandler(void); } +extern TIM_TypeDef* TIM8_BASE; +extern "C"{ void TIM8_UP_TIM13_IRQHandler(void); } +extern TIM_TypeDef* TIM15_BASE; +extern "C"{ void TIM15_IRQHandler(void); } +extern TIM_TypeDef* TIM16_BASE; +extern "C"{ void TIM16_IRQHandler(void); } +extern TIM_TypeDef* TIM17_BASE; +extern "C"{ void TIM17_IRQHandler(void); } diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index 8afd2f4db..c4122b307 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -2,16 +2,38 @@ #include -#define TIM1_IRQn TIM1_UP_IRQn -#define TIM6_IRQn TIM6_DAC_IRQn -#define TIM8_IRQn TIM8_UP_TIM13_IRQn -#define TIM12_IRQn TIM8_BRK_TIM12_IRQn -#define TIM13_IRQn TIM8_UP_TIM13_IRQn -#define TIM14_IRQn TIM8_TRG_COM_TIM14_IRQn - -#define X(n, ignore) INSTANTIATE_TIMER(n) -TimerXList -#undef X +TIM_TypeDef __htim2{TIM2_IRQHandler, TIM2_IRQn}; +TIM_TypeDef *TIM2_BASE = &__htim2; +TIM_TypeDef __htim3{TIM3_IRQHandler, TIM3_IRQn}; +TIM_TypeDef *TIM3_BASE = &__htim3; +TIM_TypeDef __htim4{TIM4_IRQHandler, TIM4_IRQn}; +TIM_TypeDef *TIM4_BASE = &__htim4; +TIM_TypeDef __htim5{TIM5_IRQHandler, TIM5_IRQn}; +TIM_TypeDef *TIM5_BASE = &__htim5; +TIM_TypeDef __htim6{TIM6_DAC_IRQHandler, TIM6_DAC_IRQn}; +TIM_TypeDef *TIM6_BASE = &__htim6; +TIM_TypeDef __htim7{TIM7_IRQHandler, TIM7_IRQn}; +TIM_TypeDef *TIM7_BASE = &__htim7; +TIM_TypeDef __htim12{TIM8_BRK_TIM12_IRQHandler, TIM8_BRK_TIM12_IRQn}; +TIM_TypeDef *TIM12_BASE = &__htim12; +TIM_TypeDef __htim13{TIM8_UP_TIM13_IRQHandler, TIM8_UP_TIM13_IRQn}; +TIM_TypeDef *TIM13_BASE = &__htim13; +TIM_TypeDef __htim14{TIM8_TRG_COM_TIM14_IRQHandler, TIM8_TRG_COM_TIM14_IRQn}; +TIM_TypeDef *TIM14_BASE = &__htim14; +TIM_TypeDef __htim23{TIM23_IRQHandler, TIM23_IRQn}; +TIM_TypeDef *TIM23_BASE = &__htim23; +TIM_TypeDef __htim24{TIM24_IRQHandler, TIM24_IRQn}; +TIM_TypeDef *TIM24_BASE = &__htim24; +TIM_TypeDef __htim1{TIM1_UP_IRQHandler, TIM1_UP_IRQn}; +TIM_TypeDef *TIM1_BASE = &__htim1; +TIM_TypeDef __htim8{TIM8_UP_TIM13_IRQHandler, TIM8_UP_TIM13_IRQn}; +TIM_TypeDef *TIM8_BASE = &__htim8; +TIM_TypeDef __htim15{TIM15_IRQHandler, TIM15_IRQn}; +TIM_TypeDef *TIM15_BASE = &__htim15; +TIM_TypeDef __htim16{TIM16_IRQHandler, TIM16_IRQn}; +TIM_TypeDef *TIM16_BASE = &__htim16; +TIM_TypeDef __htim17{TIM17_IRQHandler, TIM17_IRQn}; +TIM_TypeDef *TIM17_BASE = &__htim17; void TIM_TypeDef::generate_update() { active_PSC = PSC; From f3ca9fc2c701a0ab2af9b0650c7c39a5784ec1fe Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 21 Jan 2026 12:36:38 +0100 Subject: [PATCH 273/281] Fix tests compilation! --- .vscode/settings.json | 8 ++-- Inc/MockedDrivers/common.hpp | 3 ++ Inc/MockedDrivers/mocked_ll_tim.hpp | 1 + Inc/MockedDrivers/stm32h723xx_wrapper.h | 18 ++++----- Inc/ST-LIB_LOW/ErrorHandler/ErrorHandler.hpp | 5 ++- Src/HALAL/Services/Time/Scheduler.cpp | 37 ++++++++---------- Src/MockedDrivers/mocked_ll_tim.cpp | 4 +- Tests/CMakeLists.txt | 1 + Tests/Time/common_tests.cpp | 18 +++++++++ Tests/Time/timer_wrapper_test.cpp | 40 +++++++++++--------- 10 files changed, 80 insertions(+), 55 deletions(-) create mode 100644 Tests/Time/common_tests.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index cdd4cde8a..46afc1dca 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,8 +7,10 @@ "C_Cpp.clang_format_sortIncludes": true, "C_Cpp.intelliSenseCacheSize": 0, "files.associations": { - "mem.h": "c", - "tinydir.h": "c", - "dirent.h": "c", + "*.embeddedhtml": "html", + "mem.h": "c", + "tinydir.h": "c", + "dirent.h": "c", + "initializer_list": "cpp" } } diff --git a/Inc/MockedDrivers/common.hpp b/Inc/MockedDrivers/common.hpp index 91b8da9f8..57a62719d 100644 --- a/Inc/MockedDrivers/common.hpp +++ b/Inc/MockedDrivers/common.hpp @@ -5,6 +5,9 @@ #define glue(a,b) glue_(a,b) #endif +#undef __I +#undef __I + /* following defines should be used for structure members */ #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index 0ce554094..e6901553e 100644 --- a/Inc/MockedDrivers/mocked_ll_tim.hpp +++ b/Inc/MockedDrivers/mocked_ll_tim.hpp @@ -6,6 +6,7 @@ #include "MockedDrivers/NVIC.hpp" #include "MockedDrivers/Register.hpp" #include + enum class TimReg { Reg_CR1, Reg_CR2, Reg_SMCR, Reg_DIER, Reg_SR, Reg_EGR, Reg_CCMR1, Reg_CCMR2, Reg_CCER, Reg_CNT, Reg_PSC, Reg_ARR, Reg_RCR, diff --git a/Inc/MockedDrivers/stm32h723xx_wrapper.h b/Inc/MockedDrivers/stm32h723xx_wrapper.h index b83fba014..f4a7d29c8 100644 --- a/Inc/MockedDrivers/stm32h723xx_wrapper.h +++ b/Inc/MockedDrivers/stm32h723xx_wrapper.h @@ -11,19 +11,19 @@ # error :) #endif -#ifndef __I #ifdef __cplusplus - #define __I volatile /*!< Defines 'read only' permissions */ +# define STM__I volatile /*!< Defines 'read only' permissions */ #else - #define __I volatile const /*!< Defines 'read only' permissions */ +# define STM__I volatile const /*!< Defines 'read only' permissions */ #endif -#endif -#define __O volatile /*!< Defines 'write only' permissions */ -#define __IO volatile /*!< Defines 'read / write' permissions */ -#define __IM volatile const /*! Defines 'read only' structure member permissions */ -#define __OM volatile /*! Defines 'write only' structure member permissions */ -#define __IOM volatile /*! Defines 'read / write' structure member permissions */ +#define __I STM__I +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ #define __RBIT __RBIT__CMSIS #define TIM_TypeDef TIM_TypeDef__CMSIS diff --git a/Inc/ST-LIB_LOW/ErrorHandler/ErrorHandler.hpp b/Inc/ST-LIB_LOW/ErrorHandler/ErrorHandler.hpp index 2db36f0fd..dfbd14b95 100644 --- a/Inc/ST-LIB_LOW/ErrorHandler/ErrorHandler.hpp +++ b/Inc/ST-LIB_LOW/ErrorHandler/ErrorHandler.hpp @@ -8,6 +8,8 @@ #pragma once #include "C++Utilities/CppUtils.hpp" + +#ifndef TESTING_ENV #ifndef SIM_ON #include "HALAL/Services/Time/Time.hpp" #include "HALAL/Services/Communication/UART/UART.hpp" @@ -15,7 +17,8 @@ #include "HALALMock/Services/Time/Time.hpp" #include "HALALMock/Services/Communication/UART/UART.hpp" #include "HALALMock/Services/Logger/Logger.hpp" -#endif +#endif // SIM_ON +#endif // !defined(TESTING_ENV) class ErrorHandlerModel { private: diff --git a/Src/HALAL/Services/Time/Scheduler.cpp b/Src/HALAL/Services/Time/Scheduler.cpp index c4909b3d5..81aa1f781 100644 --- a/Src/HALAL/Services/Time/Scheduler.cpp +++ b/Src/HALAL/Services/Time/Scheduler.cpp @@ -5,27 +5,21 @@ * Author: Victor (coauthor Stephan) */ #include "HALAL/Services/Time/Scheduler.hpp" +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" +#include "ErrorHandler/ErrorHandler.hpp" -#ifndef TESTING_ENV - // This is needed to register a TimerPeripheral - #include "HALAL/Models/TimerPeripheral/TimerPeripheral.hpp" -#endif -#include -#include - +#include /* NOTE(vic): Pido perdón a Boris pero es la mejor manera que se me ha ocurrido hacer esto */ #define SCHEDULER_RCC_TIMER_ENABLE \ glue(glue(RCC_APB1LENR_TIM, SCHEDULER_TIMER_IDX), EN) #define SCHEDULER_GLOBAL_TIMER_IRQn \ glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQn)) -#define SCHEDULER_GLOBAL_TIMER_CALLBACK() \ - extern "C" void glue(TIM, glue(SCHEDULER_TIMER_IDX, _IRQHandler))(void) #define Scheduler_global_timer ((TIM_TypeDef*)SCHEDULER_TIMER_BASE) namespace { constexpr uint64_t kMaxIntervalUs = - static_cast(std::numeric_limits::max())/2 + 1ULL; + static_cast(UINT32_MAX)/2 + 1ULL; } std::array Scheduler::tasks_{}; @@ -70,6 +64,12 @@ inline void Scheduler::global_timer_enable() { } // ---------------------------- +void scheduler_global_timer_callback(void *raw) { + (void)raw; + Scheduler::on_timer_update(); +} +// ---------------------------- + void Scheduler::start() { static_assert((Scheduler::FREQUENCY % 1'000'000) == 0u, "frequenct must be a multiple of 1MHz"); @@ -114,20 +114,15 @@ void Scheduler::start() { // TODO: Fault when any of the next 2 static asserts happen (needs to be runtime bcos of SystemCoreClock) if(prescaler == 0 || prescaler > 0xFFFF) { - // error here + ErrorHandler("Invalid prescaler value: %u", prescaler); } //static_assert(prescaler < 0xFFFF, "Prescaler is 16 bit, so it must be in that range"); //static_assert(prescaler != 0, "Prescaler must be in the range [1, 65535]"); #ifndef TESTING_ENV - - // Register a TimerPeripheral so it's not used anywhere else - // hopefully we can move to something better than TimerPeripheral - TimerPeripheral::InitData init_data(TimerPeripheral::BASE); - TimerPeripheral perif_reserve(&SCHEDULER_HAL_TIM, std::move(init_data), (std::string)"timer2"); - RCC->APB1LENR |= SCHEDULER_RCC_TIMER_ENABLE; #endif + Scheduler_global_timer->PSC = (uint16_t)prescaler; Scheduler_global_timer->ARR = 0; Scheduler_global_timer->DIER |= LL_TIM_DIER_UIE; @@ -136,6 +131,9 @@ void Scheduler::start() { // LL_TIM_DisableExternalClock(Scheduler_global_timer); // |-> does this: Scheduler_global_timer->SMCR &= ~TIM_SMCR_ECE; /* Disable external clock */ + // Temporary solution for TimerDomain + ST_LIB::TimerDomain::callbacks[ST_LIB::timer_idxmap[SCHEDULER_TIMER_IDX]] = scheduler_global_timer_callback; + Scheduler_global_timer->CNT = 0; /* Clear counter value */ NVIC_EnableIRQ(SCHEDULER_GLOBAL_TIMER_IRQn); @@ -144,11 +142,6 @@ void Scheduler::start() { Scheduler::schedule_next_interval(); } -SCHEDULER_GLOBAL_TIMER_CALLBACK() { - CLEAR_BIT(Scheduler_global_timer->SR, TIM_SR_UIF); - Scheduler::on_timer_update(); -} - void Scheduler::update() { while(ready_bitmap_ != 0u) { uint32_t bit_index = static_cast(__builtin_ctz(ready_bitmap_)); diff --git a/Src/MockedDrivers/mocked_ll_tim.cpp b/Src/MockedDrivers/mocked_ll_tim.cpp index c4122b307..143237473 100644 --- a/Src/MockedDrivers/mocked_ll_tim.cpp +++ b/Src/MockedDrivers/mocked_ll_tim.cpp @@ -1,6 +1,6 @@ #include "MockedDrivers/mocked_ll_tim.hpp" -#include +#include TIM_TypeDef __htim2{TIM2_IRQHandler, TIM2_IRQn}; TIM_TypeDef *TIM2_BASE = &__htim2; @@ -58,7 +58,7 @@ void simulate_ticks(TIM_TypeDef* tim){ // Check for Overflow if (tim->CNT > current_limit) { - std::cout<<"timer overflow\n"; + printf("timer overflow\n"); tim->CNT = 0; // Rollover main counter // 4. Repetition Counter & Update Event Logic diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 116173e62..628ec53cc 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -17,6 +17,7 @@ message(STATUS "Generating test executable for ST-LIB") add_executable(${STLIB_TEST_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/Time/scheduler_test.cpp ${CMAKE_CURRENT_LIST_DIR}/Time/timer_wrapper_test.cpp + ${CMAKE_CURRENT_LIST_DIR}/Time/common_tests.cpp ) set_target_properties(${STLIB_TEST_EXECUTABLE} PROPERTIES diff --git a/Tests/Time/common_tests.cpp b/Tests/Time/common_tests.cpp new file mode 100644 index 000000000..d384f7d11 --- /dev/null +++ b/Tests/Time/common_tests.cpp @@ -0,0 +1,18 @@ +#include +#include "ErrorHandler/ErrorHandler.hpp" + +std::string ErrorHandlerModel::line; +std::string ErrorHandlerModel::func; +std::string ErrorHandlerModel::file; + +void ErrorHandlerModel::SetMetaData(int line, const char * func, const char * file){ + ErrorHandlerModel::line = to_string(line); + ErrorHandlerModel::func = string(func); + ErrorHandlerModel::file = string(file); +} + +void ErrorHandlerModel::ErrorHandlerTrigger(string format, ... ){ + EXPECT_EQ(1, 0); +} + +void ErrorHandlerModel::ErrorHandlerUpdate(){} diff --git a/Tests/Time/timer_wrapper_test.cpp b/Tests/Time/timer_wrapper_test.cpp index b3311725e..681f7a904 100644 --- a/Tests/Time/timer_wrapper_test.cpp +++ b/Tests/Time/timer_wrapper_test.cpp @@ -1,9 +1,29 @@ #include -#include -#include +//#include +//#include +#include "HALAL/Models/TimerDomain/TimerDomain.hpp" #include "HALAL/Services/Time/TimerWrapper.hpp" +TIM_TypeDef *ST_LIB::TimerDomain::cmsis_timers[16] = { + [0] = TIM2_BASE, + [1] = TIM3_BASE, + [2] = TIM4_BASE, + [3] = TIM5_BASE, + [4] = TIM23_BASE, + [5] = TIM24_BASE, + [6] = TIM12_BASE, + [7] = TIM13_BASE, + [8] = TIM14_BASE, + [9] = TIM15_BASE, + [10] = TIM16_BASE, + [11] = TIM17_BASE, + [12] = TIM6_BASE, + [13] = TIM7_BASE, + [14] = TIM1_BASE, + [15] = TIM8_BASE, +}; + class TimerWrapperTests : public ::testing::Test { protected: void SetUp() override { @@ -14,22 +34,6 @@ class TimerWrapperTests : public ::testing::Test { TIM1_BASE->CR1 = 0; TIM1_BASE->DIER = 0; - ST_LIB::TimerDomain::cmsis_timers[0] = TIM2_BASE; - ST_LIB::TimerDomain::cmsis_timers[1] = TIM3_BASE; - ST_LIB::TimerDomain::cmsis_timers[2] = TIM4_BASE; - ST_LIB::TimerDomain::cmsis_timers[3] = TIM5_BASE; - ST_LIB::TimerDomain::cmsis_timers[4] = TIM23_BASE; - ST_LIB::TimerDomain::cmsis_timers[5] = TIM24_BASE; - ST_LIB::TimerDomain::cmsis_timers[6] = TIM12_BASE; - ST_LIB::TimerDomain::cmsis_timers[7] = TIM13_BASE; - ST_LIB::TimerDomain::cmsis_timers[8] = TIM14_BASE; - ST_LIB::TimerDomain::cmsis_timers[9] = TIM15_BASE; - ST_LIB::TimerDomain::cmsis_timers[10] = TIM16_BASE; - ST_LIB::TimerDomain::cmsis_timers[11] = TIM17_BASE; - ST_LIB::TimerDomain::cmsis_timers[12] = TIM6_BASE; - ST_LIB::TimerDomain::cmsis_timers[13] = TIM7_BASE; - ST_LIB::TimerDomain::cmsis_timers[14] = TIM1_BASE; - ST_LIB::TimerDomain::cmsis_timers[15] = TIM8_BASE; } }; From c828d2c658cdcc61598eadabe52ee9c82e83359d Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 21 Jan 2026 14:01:18 +0100 Subject: [PATCH 274/281] NVIC ICER now clears the bit in NVIC ISER --- Inc/MockedDrivers/NVIC.hpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Inc/MockedDrivers/NVIC.hpp b/Inc/MockedDrivers/NVIC.hpp index 4694f9011..bb85c5ee0 100644 --- a/Inc/MockedDrivers/NVIC.hpp +++ b/Inc/MockedDrivers/NVIC.hpp @@ -4,12 +4,34 @@ #include "MockedDrivers/common.hpp" #include "MockedDrivers/compiler_specific.hpp" +#include "MockedDrivers/Register.hpp" + +enum class NVICReg { + Reg_ISER, Reg_ICER, Reg_ISPR, Reg_ICPR, Reg_IABR, Reg_IP, +}; + +template +class NVICRegister : public RegisterBase { +public: + using RegisterBase::RegisterBase; + using RegisterBase::operator=; +}; + + class NVIC_Type { + struct ICER_Register : public RegisterBase { + ICER_Register& operator=(uint32_t val) { + volatile uint32_t *ISER_offset = (volatile uint32_t*)((volatile uint8_t*)&this->reg - offsetof(NVIC_Type, ICER)); + *ISER_offset = *ISER_offset & ~val; + return *this; + } + }; + public: volatile uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ uint32_t RESERVED0[24U]; - volatile uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + ICER_Register ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ uint32_t RESERVED1[24U]; volatile uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ uint32_t RESERVED2[24U]; From 888d8dc976d4e3bafd029b3d092e04ca33c4be59 Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 23 Jan 2026 17:06:19 +0100 Subject: [PATCH 275/281] fix: TimerDomain pins --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 31 +++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 28677a3ce..3c9628567 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" @@ -296,11 +295,11 @@ struct TimerDomain { static constexpr std::array EMPTY_TIMER_NAME = {0,0,0,0, 0,0,0,0}; - template struct Timer { using domain = TimerDomain; Entry e; + template consteval Timer(TimerRequest request = TimerRequest::AnyGeneralPurpose, TimerDomain::CountingMode counting_mode = CountingMode::UP, std::array name = EMPTY_TIMER_NAME, uint32_t deadtime = 0, @@ -317,15 +316,21 @@ struct TimerDomain { e.polarity = polarity; e.negated_polarity = negated_polarity; - e.pin_count = sizeof...(pinargs); - if(e.pin_count > 4) { + if(sizeof...(pinargs) > 4) { ST_LIB::compile_error("Max 4 pins per timer"); } + int i = 0; - ((e.pins[i++] = pinargs), ...); + ((this->e.pins[i++] = pinargs), ...); + for(; i < 4; i++) { + this->e.pins[i] = { + .af = ST_LIB::TimerAF::None, + }; + } } - // anything not initialized will be 0 + // anything uninitialized will be 0 + template consteval Timer(Entry e, T... pinargs) { static_assert((std::is_same_v && ...), "All template arguments must be of type TimerPin"); @@ -336,16 +341,22 @@ struct TimerDomain { this->e.deadtime = e.deadtime; this->e.polarity = e.polarity; this->e.negated_polarity = e.negated_polarity; - e.pin_count = sizeof...(pinargs); - if(e.pin_count == 0) { + this->e.pin_count = sizeof...(pinargs); + if(sizeof...(pinargs) == 0) { this->e.pin_count = e.pin_count; this->e.pins = e.pins; } else { - if(e.pin_count > 4) { + if(sizeof...(pinargs) > 4) { ST_LIB::compile_error("Max 4 pins per timer"); } + int i = 0; - ((e.pins[i++] = pinargs), ...); + ((this->e.pins[i++] = pinargs), ...); + for(; i < 4; i++) { + this->e.pins[i] = { + .af = ST_LIB::TimerAF::None, + }; + } } } From 2f22eb5c9a1928ab295304356466555e9e7a523b Mon Sep 17 00:00:00 2001 From: victhor Date: Fri, 23 Jan 2026 18:26:58 +0100 Subject: [PATCH 276/281] hotfix! pwm compilation --- Inc/HALAL/Services/PWM/PWM/NewPWM.hpp | 39 +++++++++++----------- Inc/HALAL/Services/Time/TimerWrapper.hpp | 41 ++++++++++++------------ Inc/MockedDrivers/mocked_ll_tim.hpp | 2 +- 3 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp index 23618d94b..d1a07855f 100644 --- a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp +++ b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp @@ -60,7 +60,7 @@ 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; + TimerWrapper *timer; TimerPin pin; uint32_t frequency; float duty_cycle; @@ -68,17 +68,16 @@ class PWM { 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); + PWM(TimerWrapper *tim, TimerPin pin) : timer(tim) { + this->is_center_aligned = ((timer->instance.tim->CR1 & TIM_CR1_CMS) != 0); this->pin = pin; } void turn_on() { if(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); } + 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"); } @@ -87,24 +86,24 @@ class PWM { // 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))); + SET_BIT(timer->tim->CCER, (uint32_t)(TIM_CCx_ENABLE << (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)) { // Main Output Enable - SET_BIT(timer.tim->BDTR, TIM_BDTR_MOE); + SET_BIT(timer->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; + uint32_t tmpsmcr = timer->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(); } is_on = true; @@ -112,20 +111,20 @@ class PWM { void turn_off() { if(!is_on) return; - // if(HAL_TIM_PWM_Stop(timer.htim, channel) != HAL_OK) { ErrorHandler("", 0); } + // 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)) { // 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_DISABLE(timer->instance.hal_tim); - 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; @@ -133,8 +132,8 @@ class PWM { 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; + //__HAL_TIM_SET_COMPARE(timer->instance.hal_tim, pin.channel, raw_duty); + *(uint16_t*)((uint8_t*)(timer->tim) + timer->get_CCR_offset(pin.channel)) = raw_duty; this->duty_cycle = duty_cycle; } @@ -143,7 +142,7 @@ class PWM { frequency = 2*frequency; } this->frequency = frequency; - timer.tim->ARR = (HAL_RCC_GetPCLK1Freq() * 2 / (timer.tim->PSC + 1)) / frequency; + timer->tim->ARR = (HAL_RCC_GetPCLK1Freq() * 2 / (timer->tim->PSC + 1)) / frequency; set_duty_cycle(duty_cycle); } @@ -174,7 +173,7 @@ class PWM { sBreakDeadTimeConfig.Break2Polarity = TIM_BREAK2POLARITY_HIGH; sBreakDeadTimeConfig.Break2Filter = 0; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; - HAL_TIMEx_ConfigBreakDeadTime(timer->htim, &sBreakDeadTimeConfig); + HAL_TIMEx_ConfigBreakDeadTime(timer->instance.hal_tim, &sBreakDeadTimeConfig); SET_BIT(timer->tim->BDTR, TIM_BDTR_MOE); } }; diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 71abc4f02..b6d0e5b53 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -40,29 +40,30 @@ struct TimerWrapper { ); template - inline PWM get_pwm(uint8_t channel) { + inline PWM get_pwm() { 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) { + 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, 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); - } - - 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); - } - - 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); + } 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, pin); + } 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, pin); + } 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, pin); + } + } + + } } } diff --git a/Inc/MockedDrivers/mocked_ll_tim.hpp b/Inc/MockedDrivers/mocked_ll_tim.hpp index e6901553e..1aa234952 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} From c478fcbcd515261f7679fb815d4632757c68f801 Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 27 Jan 2026 20:50:15 +0100 Subject: [PATCH 277/281] Huge cleanup of TimerDomain, TimerWrapper + NewPWM now starts up the timer channel should work now? Also removed Wpedantic because I hate it --- CMakeLists.txt | 1 - Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 871 ++++++++++--------- Inc/HALAL/Services/PWM/PWM/NewPWM.hpp | 92 +- Inc/HALAL/Services/Time/TimerWrapper.hpp | 285 +++++- 4 files changed, 745 insertions(+), 504 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a730486b6..e661c7b5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -282,7 +282,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 3c9628567..cef456b10 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -50,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: @@ -65,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 @@ -150,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; @@ -177,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 @@ -200,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] = { @@ -273,96 +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::OUTPUT_OPENDRAIN; + 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::Up; - static constexpr std::array EMPTY_TIMER_NAME = {0,0,0,0, 0,0,0,0}; + case TimerAF::PWM: return GPIODomain::Pull::Up; + case TimerAF::InputCapture: return GPIODomain::Pull::Up; + + case TimerAF::BreakInput: return GPIODomain::Pull::Up; + case TimerAF::BreakInputCompare: return GPIODomain::Pull::Up; + } + } - 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::High; + 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, - T... 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)) { static_assert((std::is_same_v && ...), "All template arguments must be of type TimerPin"); - - e.name = name; - e.request = request; - e.counting_mode = counting_mode; - e.deadtime = deadtime; - e.polarity = polarity; - e.negated_polarity = negated_polarity; - if(sizeof...(pinargs) > 4) { ST_LIB::compile_error("Max 4 pins per timer"); } - - int i = 0; - ((this->e.pins[i++] = pinargs), ...); - for(; i < 4; i++) { - this->e.pins[i] = { - .af = ST_LIB::TimerAF::None, - }; - } } // anything uninitialized will be 0 template - consteval Timer(Entry e, T... pinargs) { + 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"); - - 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; - this->e.pin_count = sizeof...(pinargs); - if(sizeof...(pinargs) == 0) { - this->e.pin_count = e.pin_count; - this->e.pins = e.pins; - } else { - if(sizeof...(pinargs) > 4) { - ST_LIB::compile_error("Max 4 pins per timer"); - } - - int i = 0; - ((this->e.pins[i++] = pinargs), ...); - for(; i < 4; i++) { - this->e.pins[i] = { - .af = ST_LIB::TimerAF::None, - }; - } + 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); } }; @@ -376,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; @@ -402,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) @@ -430,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 @@ -477,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; } @@ -488,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*); @@ -501,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; @@ -511,375 +533,358 @@ 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.. - 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 - static consteval void check_pins(std::span requests) +#undef X + + 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 d1a07855f..f7dbd7277 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) { @@ -61,44 +61,51 @@ class PWM { static constexpr float clock_period_ns = (1.0f/CLOCK_FREQ_MHZ_WITHOUT_PRESCALER)*1000.0f; TimerWrapper *timer; - TimerPin pin; uint32_t frequency; float duty_cycle; bool is_on = false; bool is_center_aligned; public: - PWM(TimerWrapper *tim, TimerPin pin) : timer(tim) { + PWM(TimerWrapper *tim, uint32_t polarity, uint32_t negated_polarity) : timer(tim) { this->is_center_aligned = ((timer->instance.tim->CR1 & TIM_CR1_CMS) != 0); - this->pin = pin; + + 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->instance.hal_tim, channel) != HAL_OK) { ErrorHandler("", 0); } - HAL_TIM_ChannelStateTypeDef *state = &timer->instance.hal_tim.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(); } @@ -106,34 +113,40 @@ class PWM { timer->counter_enable(); } - is_on = true; + this->is_on = true; } void turn_off() { - if(!is_on) return; + 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))); - // 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); } - __HAL_TIM_DISABLE(timer->instance.hal_tim); - 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); + 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); - *(uint16_t*)((uint8_t*)(timer->tim) + timer->get_CCR_offset(pin.channel)) = raw_duty; + *(uint16_t*)((uint8_t*)(timer->instance.tim) + timer->get_CCR_offset(pin.channel)) = raw_duty; this->duty_cycle = duty_cycle; } @@ -142,10 +155,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); + *(uint16_t*)((uint8_t*)(timer->instance.tim) + timer->get_CCR_offset(pin.channel)) = raw_duty; + this->duty_cycle = duty_cycle; + } + void set_dead_time(int64_t dead_time_ns) { TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; @@ -174,7 +202,11 @@ class PWM { sBreakDeadTimeConfig.Break2Filter = 0; sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE; HAL_TIMEx_ConfigBreakDeadTime(timer->instance.hal_tim, &sBreakDeadTimeConfig); - SET_BIT(timer->tim->BDTR, TIM_BDTR_MOE); + + 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 b6d0e5b53..8c9f48250 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -31,38 +31,87 @@ 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 + ); + + /* 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); + + case TimerRequest::GeneralPurpose_15: + case TimerRequest::GeneralPurpose_16: + case TimerRequest::GeneralPurpose_17: + return ch == TimerChannel::CHANNEL_1; + + default: + return false; + } + return false; + } template - inline PWM get_pwm() { + 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, pin); + 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, pin); + 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, pin); + 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, pin); + return PWM(this, polarity, negated_polarity); } } - } } } @@ -138,32 +187,212 @@ 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(); } + /* WARNING: The counter _must_ be disabled to switch from edge-aligned to center-aligned mode */ + template + inline void set_counting_mode(void) { + constexpr uint8_t reqint = static_cast(dev.e.request); + 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) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter + } else if constexpr (mode == TimerDomain::CountingMode::DOWN) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); + SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { + MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); + } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { + 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]"); + } + static consteval size_t get_CCR_offset(const ST_LIB::TimerChannel ch) { switch(ch) { case TimerChannel::CHANNEL_1: return offsetof(TIM_TypeDef, CCR1); @@ -185,30 +414,6 @@ struct TimerWrapper { 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) { - 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), - "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) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); - CLEAR_BIT(instance.tim->CR1, TIM_CR1_DIR); // upcounter - } else if constexpr (mode == TimerDomain::CountingMode::DOWN) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, 0); - SET_BIT(instance.tim->CR1, TIM_CR1_DIR); // downcounter - } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_DOWN) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_0); - } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_UP) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, TIM_CR1_CMS_1); - } else if constexpr (mode == TimerDomain::CountingMode::CENTER_ALIGNED_INTERRUPT_BOTH) { - MODIFY_REG(instance.tim->CR1, TIM_CR1_CMS, (TIM_CR1_CMS_0 | TIM_CR1_CMS_1)); - } - } }; } // namespace ST_LIB From e0e81b1769774d08b9a5e54d49cb355c83d530cf Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 27 Jan 2026 21:12:12 +0100 Subject: [PATCH 278/281] Keep TimerPeripheral behaviour - default psc = 5 --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index cef456b10..0660e2b35 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -550,6 +550,8 @@ struct TimerDomain { rcc_enable_timer(tim); + tim->PSC = 5; // was default in TimerPeripheral.cpp + Instance *inst = &instances[i]; inst->tim = tim; inst->hal_tim = handle; From c0bb8ad7f15c8ac386cebffac4220477931da18b Mon Sep 17 00:00:00 2001 From: victhor Date: Tue, 27 Jan 2026 21:14:40 +0100 Subject: [PATCH 279/281] fix test --- Tests/Time/timer_wrapper_test.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Tests/Time/timer_wrapper_test.cpp b/Tests/Time/timer_wrapper_test.cpp index 681f7a904..88c8b1168 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 */ From 3a06f230ce2f0e44edeaf453f8a2589984ccb726 Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 28 Jan 2026 00:23:12 +0100 Subject: [PATCH 280/281] get_CCR_offset -> set_capture_compare --- Inc/HALAL/Services/PWM/PWM/NewPWM.hpp | 18 ++++++++++++++-- Inc/HALAL/Services/Time/TimerWrapper.hpp | 27 +++++++++++++----------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp index f7dbd7277..99134bbc3 100644 --- a/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp +++ b/Inc/HALAL/Services/PWM/PWM/NewPWM.hpp @@ -113,6 +113,20 @@ class PWM { 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); + } + this->is_on = true; } @@ -146,7 +160,7 @@ class PWM { void set_duty_cycle(float 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); - *(uint16_t*)((uint8_t*)(timer->instance.tim) + timer->get_CCR_offset(pin.channel)) = raw_duty; + timer->template set_capture_compare(raw_duty); this->duty_cycle = duty_cycle; } @@ -170,7 +184,7 @@ class PWM { //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); - *(uint16_t*)((uint8_t*)(timer->instance.tim) + timer->get_CCR_offset(pin.channel)) = raw_duty; + timer->template set_capture_compare(raw_duty); this->duty_cycle = duty_cycle; } diff --git a/Inc/HALAL/Services/Time/TimerWrapper.hpp b/Inc/HALAL/Services/Time/TimerWrapper.hpp index 8c9f48250..fc5c4472b 100644 --- a/Inc/HALAL/Services/Time/TimerWrapper.hpp +++ b/Inc/HALAL/Services/Time/TimerWrapper.hpp @@ -393,18 +393,21 @@ struct TimerWrapper { } else ST_LIB::compile_error("Unknown timer channel, there are only 6 channels [1..6]"); } - 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; - } + 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? From d39cc96688187e040ccf14d4e4c67b675129b02d Mon Sep 17 00:00:00 2001 From: victhor Date: Wed, 28 Jan 2026 00:52:50 +0100 Subject: [PATCH 281/281] fix gpio operation mode --- Inc/HALAL/Models/TimerDomain/TimerDomain.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp index 0660e2b35..2fece23f7 100644 --- a/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp +++ b/Inc/HALAL/Models/TimerDomain/TimerDomain.hpp @@ -288,7 +288,7 @@ struct TimerDomain { switch(af) { case TimerAF::None: return GPIODomain::OperationMode::INPUT; - case TimerAF::PWM: return GPIODomain::OperationMode::OUTPUT_OPENDRAIN; + case TimerAF::PWM: return GPIODomain::OperationMode::ALT_PP; case TimerAF::InputCapture: return GPIODomain::OperationMode::OUTPUT_OPENDRAIN; case TimerAF::BreakInput: return GPIODomain::OperationMode::OUTPUT_OPENDRAIN; @@ -300,13 +300,13 @@ struct TimerDomain { static consteval GPIODomain::Pull get_pull(ST_LIB::TimerAF af) { switch(af) { - case TimerAF::None: return GPIODomain::Pull::Up; + case TimerAF::None: return GPIODomain::Pull::None; - case TimerAF::PWM: return GPIODomain::Pull::Up; + case TimerAF::PWM: return GPIODomain::Pull::None; case TimerAF::InputCapture: return GPIODomain::Pull::Up; - case TimerAF::BreakInput: return GPIODomain::Pull::Up; - case TimerAF::BreakInputCompare: return GPIODomain::Pull::Up; + case TimerAF::BreakInput: return GPIODomain::Pull::None; + case TimerAF::BreakInputCompare: return GPIODomain::Pull::None; } } @@ -316,7 +316,7 @@ struct TimerDomain { switch(af) { case TimerAF::None: return GPIODomain::Speed::Low; - case TimerAF::PWM: return GPIODomain::Speed::High; + case TimerAF::PWM: return GPIODomain::Speed::Medium; case TimerAF::InputCapture: return GPIODomain::Speed::High; case TimerAF::BreakInput: return GPIODomain::Speed::Medium;