Skip to content

Commit fc00a32

Browse files
victor-Lopez25g0nz4I0jorgesg82StefanCostea
authored
Scheduler implementation (#534)
* Add initial implementation of scheduler * Try to fix -Wuninitialized warning * Try to remove Wuninitialized warning temporarily * Remove unnecessary clear of task element * fix: Readability and todo for validation * fix: allocate_slot * Add explenation of sorted_task_ids_, static_assert for the bitmaps * Remove long_wait_remaining_us_ * fix: better get_at * fix: better front_id Compiler would've probably optimized it but it's better to make it explicit * fix: endianness in pop_front * Added unlikely to release_slot conditional * fix: Correct comment explenation * No bit field insert, it annoyed me * No more diagnostic ignore * fix: loss in accuracy by not adding 1: #534 (comment) * fix: Moved active_task_count_ modification * Actually set used_bitmap_ in allocate_slot * only include sources when cross-compiling * modify CMakeLists inside Tests * feat: use ugly ifdef guards for host testing purposes * add sample tests for Scheduler * add emulated ticking * test for execution count * fix: CI * fix: expected result in test case + explanation * add compiler specific and CoreMacros * copy files from LL and CMSIS for TIM Registers * bridge between LL MMIO Timer and user defined TIMER * reduce the number of ugly macros * compile the new mock file * update test * enable debugging of tests with TestMate C++ extension * feat: add DSB and ISB intructions in x86_64 * feat: add NVIC * add NVIC logic * feat: use NVIC and remove print * fix: move extern"C" block to allow using <iostream> * add Register class to allow for side effects * feat: use newly created Register class for side effects, neat trick in CNT write * feat: be as realistic as possible in test, by using CNT++ * feat: remove unnecessary include * feat: add an __RBIT impl for x86_64 * fix: compilation * fix: used_bitmap_ -> free_bitmap_ * Added tests check in CI/CD * fix(ci/cd): output folder * Added ARM specific instructions to be able to compile in ARM hosts (Mac) * Fix: compiler barrier for msvc, hopefully works * Fix: Try to fix -Wchanges-meaning warning * Fix typo * Update Inc/MockedDrivers/common.hpp #534 (comment) Co-authored-by: Jorge Sáez <125664643+jorgesg82@users.noreply.github.com> * Actually do the change github didn't do :/ * Fix typo p2 * Fix another typo * Fix unsigned long - 64bit when testing using LL functions * Minor fixes to scheduler Rebased from remotes/origin/MockTim * Fix: uint32_t* cast of a word instead of the ptr * Fix: remove active_task_count_ decrement in pop_front() #534 (comment) * Try fix Wstrict-aliasing in front_id * Try fix Wstrict-aliasing again * Fix typo in allocate_slot * fix: test UsedBitmap -> FreeBitmap * used_bitmap_ -> free_bitmap_ in test part 2 * fixed tests discovery * fix: set_timeout() test * Add a test, fix the error (kind of) * Fix: underflow in schedule_next_interval * Fix: call schedule_next_interval() in start() * Fix: invert condition, that was stupid * feat: add test showcasing possible usage within StateMachine logic * fix: Calculate correct prescaler & add to HALAL.hpp * Try to fix tests * try to fix tests part 2 * Try to fix tests part 3 * part 4 - add the wrapper.c to cmake, will this work? * part 5 - fix cmake stm32h723xx_wrapper.c path * fix: try to fix tests part 6 * fix: volatile warnings * fix: active_PSC is now set when PSC is set * fix: remove outdated comment * fix: tests part 7, should work now * fix: remove unecessary if, return if cancelled in cancel_timeout * Pop all due tasks, several might be due in the same tick * Revert force-push * fix: off by one error + configure_timer_for_interval should use uint32_t * fix: off by one error in schedule_next_interval() * All 15 tasks in MultipleTasks test, and it works * Add SameTaskMultipleTimes test, does all 16 tasks too * larger NUM_TICKS just in case * fix bug mentioned in previous cancel_timeout() * fix: id uint32_t -> uint16_t + bug fix * fix: remove TimerPeripheral::start and Time::start from HALAL::start * try to fix ci/cd * try to fix ci/cd part 2 * try to fix ci/cd part 3 * clean up ci/cd fix * Remove unnecessary warning ignore * fix: use wrapper instead of interface for stm32h7xx_ll_tim.h * fix ci/cd and add the other submodule to be automatically added * fix: actually add stm32h7xx_ll_tim_wrapper.h * try to fix ci/cd warning * try fix warnings again * fix: add ignore Woverflow to stm32h7xx_ll_tim * fix: remove need to ignore Woverflow warnings * fix: Remove tim_register_definitions.hpp We're already including them in stm32h723xx_wrapper * Fix overflow calculation and a test * Add link to wiki * fix: revert .vscode settings change * revert .vscode settings change part 2 * finish reverting change --------- Co-authored-by: Gonzalo Sánchez <gonzalosmoya24@gmail.com> Co-authored-by: Jorge Sáez <jorgeesg82@gmail.com> Co-authored-by: Jorge Sáez <125664643+jorgesg82@users.noreply.github.com> Co-authored-by: StefanCostea <stefanxenadu@gmail.com>
1 parent 726639b commit fc00a32

20 files changed

Lines changed: 1355 additions & 8 deletions

.github/workflows/tests.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Run tests
2+
3+
on:
4+
workflow_dispatch:
5+
pull_request:
6+
branches: [ development ]
7+
8+
jobs:
9+
tests:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout repository
14+
uses: actions/checkout@v4
15+
16+
- name: Install build dependencies
17+
run: |
18+
sudo apt-get update
19+
sudo apt-get install -y cmake ninja-build build-essential
20+
21+
- name: Configure (CMake)
22+
run: |
23+
cmake --preset simulator
24+
25+
- name: Build
26+
run: |
27+
cmake --build out/build/simulator
28+
29+
- name: Run tests (ctest)
30+
working-directory: out/build/simulator
31+
run: |
32+
ctest --output-on-failure

.vscode/settings.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@
1111
"tinydir.h": "c",
1212
"dirent.h": "c"
1313
}
14-
}
15-
14+
}

CMakeLists.txt

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,28 @@ message(STATUS "${PROJECT_NAME} Ethernet: ${USE_ETHERNET}")
2121
message(STATUS "${PROJECT_NAME} Nucleo: ${TARGET_NUCLEO}")
2222
message(STATUS "${PROJECT_NAME} Crosscompiling: ${CMAKE_CROSSCOMPILING}")
2323

24+
if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers)
25+
execute_process(
26+
COMMAND git submodule update --init --depth 1
27+
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
28+
)
29+
endif()
30+
31+
if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7/Drivers/CMSIS/Device/ST/STM32H7xx/Include)
32+
execute_process(
33+
COMMAND git submodule update --init --depth 1 Drivers/CMSIS/Device/ST/STM32H7xx Drivers/STM32H7xx_HAL_Driver
34+
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7
35+
)
36+
endif()
2437

2538
if(NOT CMAKE_CROSSCOMPILING)
2639
message(STATUS "Compiling for simulator")
2740
add_subdirectory(Tests)
41+
else()
42+
execute_process(
43+
COMMAND git submodule update --init --depth 1 Drivers/BSP/Components/lan8742
44+
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/STM32CubeH7
45+
)
2846
endif()
2947

3048
# ============================
@@ -222,6 +240,12 @@ add_library(${STLIB_LIBRARY} STATIC
222240
$<$<AND:$<BOOL:${CMAKE_CROSSCOMPILING}>,$<BOOL:${USE_ETHERNET}>>:${STLIB_HIGH_CPP_ETH}>
223241

224242
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${CMAKE_CURRENT_LIST_DIR}/Src/ST-LIB.cpp>
243+
244+
$<$<NOT:$<BOOL:${CMAKE_CROSSCOMPILING}>>:${CMAKE_CURRENT_LIST_DIR}/Src/HALAL/Services/Time/Scheduler.cpp>
245+
$<$<NOT:$<BOOL:${CMAKE_CROSSCOMPILING}>>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/mocked_ll_tim.cpp>
246+
$<$<NOT:$<BOOL:${CMAKE_CROSSCOMPILING}>>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/mocked_system_stm32h7xx.c>
247+
$<$<NOT:$<BOOL:${CMAKE_CROSSCOMPILING}>>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/stm32h723xx_wrapper.c>
248+
$<$<NOT:$<BOOL:${CMAKE_CROSSCOMPILING}>>:${CMAKE_CURRENT_LIST_DIR}/Src/MockedDrivers/NVIC.cpp>
225249
)
226250

227251
set_target_properties(${STLIB_LIBRARY} PROPERTIES
@@ -268,10 +292,13 @@ target_compile_options(${STLIB_LIBRARY} PRIVATE
268292

269293
target_include_directories(${STLIB_LIBRARY} PUBLIC
270294
# CMSIS + HAL
271-
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include>
272-
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/CMSIS/Include>
295+
#$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include>
296+
#$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/CMSIS/Include>
297+
${STM32CUBEH7}/Drivers/CMSIS/Device/ST/STM32H7xx/Include
298+
${STM32CUBEH7}/Drivers/CMSIS/Include
273299
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/CMSIS/Core_A/Include>
274-
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc>
300+
#$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc>
301+
${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc
275302
$<$<BOOL:${CMAKE_CROSSCOMPILING}>:${STM32CUBEH7}/Drivers/STM32H7xx_HAL_Driver/Inc/Legacy>
276303

277304
# LWIP includes

Inc/HALAL/HALAL.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "HALAL/Services/PWM/DualPhasedPWM/DualPhasedPWM.hpp"
2222

2323
#include "HALAL/Services/Time/Time.hpp"
24+
#include "HALAL/Services/Time/Scheduler.hpp"
2425
#include "HALAL/Services/Time/RTC.hpp"
2526

2627
#include "HALAL/Services/InputCapture/InputCapture.hpp"
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Scheduler.hpp
3+
*
4+
* Created on: 17 nov. 2025
5+
* Author: Victor (coauthor Stephan)
6+
*/
7+
#pragma once
8+
9+
/* Uso del scheduler, descrito en la wiki: https://wiki.hyperloopupv.com/es/firmware/Timing/Scheduler */
10+
11+
#ifndef TESTING_ENV
12+
#include "stm32h7xx_ll_tim.h"
13+
#else
14+
#include "MockedDrivers/stm32h7xx_ll_tim_wrapper.h"
15+
#endif
16+
#include <array>
17+
#include <cstdint>
18+
#include <functional>
19+
20+
/* NOTE(vic): Esto cambiará pronto */
21+
#ifndef SCHEDULER_TIMER_IDX
22+
# define SCHEDULER_TIMER_IDX 2
23+
#endif
24+
25+
#define glue_(a,b) a ## b
26+
#define glue(a,b) glue_(a,b)
27+
#define SCHEDULER_TIMER_BASE glue(TIM, glue(SCHEDULER_TIMER_IDX, _BASE))
28+
29+
// Used to reserve a TimerPeripheral
30+
#ifndef TESTING_ENV
31+
#include "stm32h7xx_hal_tim.h"
32+
#define SCHEDULER_HAL_TIM glue(htim, SCHEDULER_TIMER_IDX)
33+
extern TIM_HandleTypeDef SCHEDULER_HAL_TIM;
34+
#endif
35+
36+
struct Scheduler {
37+
using callback_t = void (*)();
38+
static constexpr uint32_t INVALID_ID = 0xFFu;
39+
40+
static void start();
41+
static void update();
42+
static inline uint64_t get_global_tick();
43+
44+
static uint16_t register_task(uint32_t period_us, callback_t func);
45+
static bool unregister_task(uint16_t id);
46+
47+
static uint16_t set_timeout(uint32_t microseconds, callback_t func);
48+
static bool cancel_timeout(uint16_t id);
49+
50+
// static void global_timer_callback();
51+
52+
// Have to be public because SCHEDULER_GLOBAL_TIMER_CALLBACK won't work otherwise
53+
//static const uint32_t global_timer_base = SCHEDULER_TIMER_BASE;
54+
static void on_timer_update();
55+
56+
#ifndef TESTING_ENV
57+
private:
58+
#endif
59+
struct Task {
60+
uint32_t next_fire_us{0};
61+
callback_t callback{};
62+
uint32_t period_us{0};
63+
uint16_t id;
64+
bool repeating{false};
65+
};
66+
67+
static constexpr std::size_t kMaxTasks = 16;
68+
static_assert((kMaxTasks & (kMaxTasks - 1)) == 0, "kMaxTasks must be a power of two");
69+
static constexpr uint32_t FREQUENCY = 1'000'000u; // 1 MHz -> 1us precision
70+
71+
static std::array<Task, kMaxTasks> tasks_;
72+
static_assert(kMaxTasks == 16, "kMaxTasks must be 16, if more is needed, sorted_task_ids_ must change");
73+
/* sorted_task_ids_ is a sorted queue with 4bits for each id in the scheduler's current ids */
74+
static uint64_t sorted_task_ids_;
75+
76+
static uint32_t active_task_count_;
77+
static_assert(kMaxTasks <= 32, "kMaxTasks must be <= 32, if more is needed, the bitmaps must change");
78+
static uint32_t ready_bitmap_;
79+
static uint32_t free_bitmap_;
80+
static uint64_t global_tick_us_;
81+
static uint32_t current_interval_us_;
82+
static uint16_t timeout_idx_;
83+
84+
static inline uint8_t allocate_slot();
85+
static inline void release_slot(uint8_t id);
86+
static void insert_sorted(uint8_t id);
87+
static void remove_sorted(uint8_t id);
88+
static void schedule_next_interval();
89+
static inline void configure_timer_for_interval(uint32_t microseconds);
90+
91+
// helpers
92+
static inline uint8_t get_at(uint8_t idx);
93+
static inline void set_at(uint8_t idx, uint8_t id);
94+
static inline void pop_front();
95+
static inline uint8_t front_id();
96+
97+
static inline void global_timer_disable();
98+
static inline void global_timer_enable();
99+
};

Inc/MockedDrivers/NVIC.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include "stm32h723xx_wrapper.h"
4+
#include "MockedDrivers/common.hpp"
5+
#include "MockedDrivers/compiler_specific.hpp"
6+
7+
class NVIC_Type
8+
{
9+
public:
10+
volatile uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */
11+
uint32_t RESERVED0[24U];
12+
volatile uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */
13+
uint32_t RESERVED1[24U];
14+
volatile uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */
15+
uint32_t RESERVED2[24U];
16+
volatile uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */
17+
uint32_t RESERVED3[24U];
18+
volatile uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */
19+
uint32_t RESERVED4[56U];
20+
volatile uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */
21+
uint32_t RESERVED5[644U];
22+
volatile uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */
23+
};
24+
25+
extern NVIC_Type* NVIC;
26+
27+
extern "C"{
28+
void NVIC_EnableIRQ(IRQn_Type IRQn);
29+
30+
uint32_t NVIC_GetEnableIRQ(IRQn_Type IRQn);
31+
32+
void NVIC_DisableIRQ(IRQn_Type IRQn);
33+
34+
}

Inc/MockedDrivers/Register.hpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
#include <cstdint>
3+
#include <iostream>
4+
5+
6+
template<typename EnumType, EnumType Reg>
7+
struct RegisterTraits {
8+
static void write(uint32_t& target, uint32_t val) {
9+
target = val;
10+
}
11+
};
12+
13+
14+
template<typename EnumType, EnumType Reg>
15+
class RegisterBase {
16+
public:
17+
uint32_t reg = 0;
18+
19+
RegisterBase() = default;
20+
RegisterBase(uint32_t val) : reg(val) {}
21+
22+
RegisterBase& operator=(uint32_t val) {
23+
set(val);
24+
return *this;
25+
}
26+
RegisterBase& operator+=(uint32_t val){
27+
set(reg+val);
28+
return *this;
29+
}
30+
RegisterBase& operator-=(uint32_t val){
31+
set(reg-val);
32+
return *this;
33+
}
34+
35+
RegisterBase& operator&=(uint32_t mask) {
36+
set(reg & mask);
37+
return *this;
38+
}
39+
40+
RegisterBase& operator|=(uint32_t mask) {
41+
set(reg | mask);
42+
return *this;
43+
}
44+
45+
RegisterBase& operator^=(uint32_t mask) {
46+
set(reg ^ mask);
47+
return *this;
48+
}
49+
RegisterBase& operator<<=(int shift) {
50+
set(reg << shift); // Triggers Traits
51+
return *this;
52+
}
53+
54+
RegisterBase& operator>>=(int shift) {
55+
set(reg >> shift); // Triggers Traits
56+
return *this;
57+
}
58+
59+
// --- Shift Read (Does NOT modify Register) ---
60+
// Usage: uint32_t val = REG >> 4;
61+
uint32_t operator<<(int shift) const {
62+
return reg << shift;
63+
}
64+
65+
uint32_t operator>>(int shift) const {
66+
return reg >> shift;
67+
}
68+
RegisterBase& operator++() {
69+
set(reg + 1);
70+
return *this;
71+
}
72+
73+
// --- Postfix Increment (REG++) ---
74+
// int argument is a dummy flag for C++ to distinguish postfix
75+
uint32_t operator++(int) {
76+
uint32_t old_val = reg;
77+
set(reg + 1);
78+
return old_val;
79+
}
80+
81+
RegisterBase& operator--() {
82+
set(reg - 1);
83+
return *this;
84+
}
85+
86+
uint32_t operator--(int) {
87+
uint32_t old_val = reg;
88+
set(reg - 1);
89+
return old_val;
90+
}
91+
/**
92+
* COMPARISON
93+
*/
94+
bool operator!=(uint32_t val) const {
95+
return reg != val;
96+
}
97+
bool operator==(uint32_t val) const {
98+
return reg == val;
99+
}
100+
/**
101+
* BITWISE COMPARISONS
102+
*/
103+
operator uint32_t(){
104+
return reg;
105+
}
106+
operator uint32_t() const volatile {
107+
return reg;
108+
}
109+
operator uint32_t() const {
110+
return reg;
111+
}
112+
113+
protected:
114+
void set(uint32_t val) {
115+
RegisterTraits<EnumType, Reg>::write(this->reg, val);
116+
}
117+
};

0 commit comments

Comments
 (0)