diff --git a/.gitignore b/.gitignore
index ab749f6..41eff4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,5 +4,5 @@ projectfiles
 *.py*
 BUILD
 mbed-os
-DISCO_h747i
+DISCO_H747I
 advdembsof_library
diff --git a/.mbedignore b/.mbedignore
index ef3cf8a..a4c7376 100644
--- a/.mbedignore
+++ b/.mbedignore
@@ -14,4 +14,5 @@ mbed-os/features/FEATURE_BOOTLOADER/*
 mbed-os/features/frameworks/mbed-client-cli/*
 mbed-os/features/frameworks/COMPONENT_FPGA_CI_TEST_SHIELD/*
 mbed-os/platform/randlib/*
-mbed-os/storage/kvstore/*
\ No newline at end of file
+mbed-os/storage/kvstore/*
+mbed-os-bootloader/*
\ No newline at end of file
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 0e8a5e3..f568f65 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,4 +1,4 @@
-files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS
+files: ^main.cpp|^static_scheduling|^static_scheduling_with_event|^TESTS|^multi_tasking|^common
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
     rev: v4.3.0
diff --git a/README.md b/README.md
index f919c9e..4d7a5f6 100644
--- a/README.md
+++ b/README.md
@@ -23,25 +23,27 @@ Test sensor libraries :
 mbed test -m DISCO_H747I -t GCC_ARM -n advdembsof_library-tests-sensors-hdc1000 --compile --run
 ```
 
-## Run static scheduling 
+## Run static scheduling
 On `.mbedignore` put at the end of the file
 ```
 static_scheduling_with_event/*
+multi_tasking/*
 ```
 
-On main.cpp include `"static_scheduling/bike_system.hpp"` and use : 
+On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
 ```cpp
 static_scheduling::BikeSystem bikeSystem;
 bikeSystem.start();
 ```
 
 ## Run static scheduling with event queue
-On `.mbedignore` put at the end of the file : 
+On `.mbedignore` put at the end of the file :
 ```
 static_scheduling_with_event/*
+multi_tasking/*
 ```
 
-On main.cpp include `"static_scheduling/bike_system.hpp"` and use : 
+On main.cpp include `"static_scheduling/bike_system.hpp"` and use :
 ```cpp
 static_scheduling::BikeSystem bikeSystem;
 bikeSystem.startWithEventQueue();
@@ -51,9 +53,23 @@ bikeSystem.startWithEventQueue();
 On `.mbedignore` put at the end of the file
 ```
 static_scheduling/*
+static_scheduling_with_event/*
 ```
 
-On main.cpp include `"static_scheduling_with_event/bike_system.hpp"` and use : 
+On main.cpp include `"multi_tasking/bike_system.hpp"` and use :
+```cpp
+multi_tasking::BikeSystem bikeSystem;
+bikeSystem.start();
+```
+
+## Run multi-tasking
+On `.mbedignore` put at the end of the file
+```
+static_scheduling/*
+multi_tasking/*
+```
+
+On main.cpp include `"static_scheduling_with_event/bike_system.hpp"` and use :
 ```cpp
 static_scheduling_with_event::BikeSystem bikeSystem;
 bikeSystem.start();
@@ -63,7 +79,7 @@ bikeSystem.start();
 ## Question 1
 `If you print CPU statistics at the end of every major cycle (in the super-loop), what CPU usage do you observe? How can you explain the observed CPU uptime?`
 
-We observe a 100% usage because on each CPU cycle it compare if time is done. 
+We observe a 100% usage because on each CPU cycle it compare if time is done.
 
 ## Question 2
 `If you run the program after the change from busy wait to sleep calls, what CPU usage do you observe? How can you explain the observed CPU uptime?`
@@ -73,7 +89,7 @@ We can observe only a usage of 75% because the CPU is more on Idle with Thread s
 ## Question 3
 `If you run the static_scheduling_with_event program, what CPU usage do you observe? How can you explain the observed CPU uptime?`
 
-We observe a light usage of 1% of CPU. The CPU is now sleeping all the time and doing small task only on event. 
+We observe a light usage of 1% of CPU. The CPU is now sleeping all the time and doing small task only on event.
 
 ## Question 4
 `When you run multiple tests for computing the response time of the reset event, what do you observe? Is there an improvement as compared to the static_scheduling::BikeSystem implementation?`
@@ -84,7 +100,22 @@ We observe a light usage of 1% of CPU. The CPU is now sleeping all the time and
 
 We notice, that we miss such less event when is event driven (or not at all). But with a static scheduling the response time is still long because the reset task is call with a certain period.
 
+# Multi-tasking
+
+## Question 1
+We have computed the elapsed time between the event is sent by the interruption until it is executed :
+
+|Rtos priority            |time   |
+|---|---|
+|osPriorityBelowNormal    |13 usecs   |
+|osPriorityNormal         |13 usecs   |
+|osPriorityAboveNormal    |13 usecs   |
+
+To abtain these values, we have to consider that there is a isr thread. He dispatchs all the events from the gear device and the reset device. The rest is processed by the main thread.
+
+Main of the time, it meares these values. But sometimes, higher values can appear. These values doesn't change because there isn't often more than one event in the queue.
+
 # Issues
 When compile with GCC, the full loop of static scheduling is 2 to 3 ms faster than expected.
 This problem doesn't occur if we compile with ARMC6.
-As the acceptable delta is 2ms and the teacher test is done with GCC, we modify the delta on the test to be 3ms
\ No newline at end of file
+As the acceptable delta is 2ms and the teacher test is done with GCC, we modify the delta on the test to be 3ms
diff --git a/TESTS/bike-computer/bike-system/main.cpp b/TESTS/bike-computer/bike-system/main.cpp
index 605f74c..f1c819f 100644
--- a/TESTS/bike-computer/bike-system/main.cpp
+++ b/TESTS/bike-computer/bike-system/main.cpp
@@ -23,15 +23,23 @@
  ***************************************************************************/
 
 #include <chrono>
+#include <cstdint>
 
+#include "gear_device.hpp"
 #include "greentea-client/test_env.h"
 #include "mbed.h"
+#include "mbed_trace.h"  // NOLINT
+#include "multi_tasking/bike_system.hpp"
 #include "static_scheduling/bike_system.hpp"
 #include "static_scheduling_with_event/bike_system.hpp"
 #include "task_logger.hpp"
 #include "unity/unity.h"
 #include "utest/utest.h"
 
+#if defined(MBED_CONF_MBED_TRACE_ENABLE)
+#define TRACE_GROUP "TEST_BIKE_SYSTEM"
+#endif  // MBED_CONF_MBED_TRACE_ENAB
+
 namespace utest {
 namespace v1 {
 
@@ -140,6 +148,235 @@ static void test_bike_system_with_event() {
     }
 }
 
+// test_multi_tasking_bike_system handler function
+static void test_multi_tasking_bike_system() {
+    tr_info("test multi tasking bike system");
+
+    // create the BikeSystem instance
+    multi_tasking::BikeSystem bikeSystem;
+
+    // run the bike system in a separate thread
+    Thread thread;
+    osStatus status =
+        thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start));
+
+    if (status != osOK) {
+        tr_error("Thread bike system is not OK !");
+    }
+
+    tr_info("bike system has started");
+
+    // let the bike system run for 20 secs
+    ThisThread::sleep_for(20s);
+
+    // check whether scheduling was correct
+    // Order is kGearTaskIndex, kSpeedTaskIndex, kTemperatureTaskIndex,
+    //          kResetTaskIndex, kDisplayTask1Index, kDisplayTask2Index
+    // When we use event handling, we do not check the computation time
+    constexpr std::chrono::microseconds taskPeriods[] = {
+        800000us, 400000us, 1600000us, 800000us, 1600000us, 1600000us};
+
+    // allow for 2 msecs offset (with EventQueue)
+    constexpr uint64_t kDeltaUs = 2000;
+
+    // stop the bike system
+    bikeSystem.stop();
+    thread.terminate();
+
+    tr_info("Threads have stopped");
+
+    TEST_ASSERT_UINT64_WITHIN(
+        kDeltaUs,
+        taskPeriods[advembsof::TaskLogger::kTemperatureTaskIndex].count(),
+        bikeSystem.getTaskLogger()
+            .getPeriod(advembsof::TaskLogger::kTemperatureTaskIndex)
+            .count());
+    TEST_ASSERT_UINT64_WITHIN(
+        kDeltaUs,
+        taskPeriods[advembsof::TaskLogger::kDisplayTask1Index].count(),
+        bikeSystem.getTaskLogger()
+            .getPeriod(advembsof::TaskLogger::kDisplayTask1Index)
+            .count());
+}
+
+// test_reset_multi_tasking_bike_system handler function
+Timer timer;
+static std::chrono::microseconds resetTime = std::chrono::microseconds::zero();
+static EventFlags eventFlags;
+static constexpr uint32_t kResetEventFlag = (1UL << 0);
+static void resetCallback() {
+    resetTime = timer.elapsed_time();
+    eventFlags.set(kResetEventFlag);
+}
+
+static void test_reset_multi_tasking_bike_system() {
+    tr_info("test reset multi tasking bike system");
+    // create the BikeSystem instance
+    multi_tasking::BikeSystem bikeSystem;
+
+    // run the bike system in a separate thread
+    Thread thread;
+    osStatus status =
+        thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start));
+
+    if (status != osOK) {
+        tr_error("Thread bike system is not OK !");
+    }
+
+    tr_info("Bike system has started");
+
+    // let the bike system run for 2 secs
+    ThisThread::sleep_for(2s);
+
+    // test reset on BikeSystem
+    bikeSystem.getSpeedometer().setOnResetCallback(resetCallback);
+
+    // start the timer instance
+    timer.start();
+
+    // check for reset response time
+    constexpr uint8_t kNbrOfResets             = 10;
+    std::chrono::microseconds lastResponseTime = std::chrono::microseconds::zero();
+    for (uint8_t i = 0; i < kNbrOfResets; i++) {
+        tr_info("Reset test N°%d", i);
+        // take time before reset
+        auto startTime = timer.elapsed_time();
+
+        // reset the BikeSystem
+        bikeSystem.onReset();
+
+        // wait for resetCallback to be called
+        eventFlags.wait_all(kResetEventFlag);
+
+        // get the response time and check it
+        auto responseTime = resetTime - startTime;
+
+        // cppcheck generates an internal error with 20us
+        constexpr std::chrono::microseconds kMaxExpectedResponseTime(20);
+
+        tr_info("Reset task: response time is %lld usecs\n, expected : %lld",
+                responseTime.count(),
+                kMaxExpectedResponseTime.count());
+
+        TEST_ASSERT_TRUE(responseTime.count() <= kMaxExpectedResponseTime.count());
+
+        // jitter of 20us is accepted
+        constexpr uint64_t kDeltaUs = 4;
+        constexpr std::chrono::microseconds kMaxExpectedJitter(3);
+        if (i > 0) {
+            auto jitter = responseTime - lastResponseTime;
+            tr_info("Reset task: jitter is %lld usecs\n", std::abs(jitter.count()));
+            TEST_ASSERT_UINT64_WITHIN(
+                kDeltaUs, kMaxExpectedJitter.count(), std::abs(jitter.count()));
+        }
+        lastResponseTime = responseTime;
+
+        // let the bike system run for 2 secs
+        ThisThread::sleep_for(2s);
+    }
+
+    // stop the bike system
+    bikeSystem.stop();
+    thread.terminate();
+    tr_info("Threads have stopped");
+    timer.stop();
+}
+
+Timer timerGear;
+static std::chrono::microseconds gearTime = std::chrono::microseconds::zero();
+static EventFlags eventGearFlags;
+static constexpr uint32_t kGearEventFlag = (1UL << 0);
+constexpr uint8_t kNbrOfGear             = 9;
+static void onGearChange() {
+    gearTime = timerGear.elapsed_time();
+    eventGearFlags.set(kGearEventFlag);
+    tr_info("Gear changed");
+}
+
+static void gearTest(Callback<void()> gearChange) {
+    // std::chrono::microseconds lastResponseTime = std::chrono::microseconds::zero();
+
+    for (uint8_t i = 1; i < kNbrOfGear; i++) {
+        tr_info("Gear test N°%d", i);
+        // take time before increase the gear
+        auto startTime = timerGear.elapsed_time();
+
+        // change the gear with the callback
+        tr_info("Change gear");
+        gearChange();
+
+        // wait flag
+        eventGearFlags.wait_all(kGearEventFlag);
+
+        // get the response time and check it
+        auto responseTime = gearTime - startTime;
+        constexpr std::chrono::microseconds kMaxExpectedResponseTime(100000);
+
+        tr_info("Change gear task: response time is %lld usecs\n, expected : %lld",
+                responseTime.count(),
+                kMaxExpectedResponseTime.count());
+
+        TEST_ASSERT_TRUE(responseTime.count() <= kMaxExpectedResponseTime.count());
+
+        // jitter of 20us is accepted
+        // constexpr uint64_t kDeltaUs = 2000;
+        // constexpr std::chrono::microseconds kMaxExpectedJitter(4000);
+        // if (i > 1) {
+        //     auto jitter = responseTime - lastResponseTime;
+        //     tr_info("Gear task: jitter is %lld usecs\n", std::abs(jitter.count()));
+        //     TEST_ASSERT_UINT64_WITHIN(
+        //         kDeltaUs, kMaxExpectedJitter.count(), std::abs(jitter.count()));
+        // }
+        // lastResponseTime = responseTime;
+
+        // let the bike system run for 2 secs
+        ThisThread::sleep_for(2s);
+    }
+}
+
+static void test_gear_multi_tasking_bike_system() {
+    tr_info("test reset multi tasking bike system");
+    // create the BikeSystem instance
+    multi_tasking::BikeSystem bikeSystem;
+
+    // run the bike system in a separate thread
+    Thread thread;
+    osStatus status =
+        thread.start(callback(&bikeSystem, &multi_tasking::BikeSystem::start));
+
+    if (status != osOK) {
+        tr_error("Thread bike system is not OK !");
+    }
+
+    tr_info("Bike system has started");
+
+    // let the bike system run for 2 secs
+    ThisThread::sleep_for(2s);
+
+    // get the gear device to call onUp and onDown functions
+    multi_tasking::GearDevice& gearDevice = bikeSystem.getGearDevice();
+
+    // set callback for response time measuring
+    bikeSystem.setCallbackGearChage(onGearChange);
+
+    // start the timer instance
+    timerGear.start();
+
+    // test timing incresing the gear
+    tr_info("Test incresing gear");
+    gearTest(callback(&gearDevice, &multi_tasking::GearDevice::onUp));
+
+    // test timing decreasing the gear
+    tr_info("Test decreasing gear");
+    gearTest(callback(&gearDevice, &multi_tasking::GearDevice::onDown));
+
+    // stop the bike system
+    bikeSystem.stop();
+    thread.terminate();
+    tr_info("Threads have stopped");
+    timerGear.stop();
+}
+
 static status_t greentea_setup(const size_t number_of_cases) {
     // Here, we specify the timeout (60s) and the host test (a built-in host test
     // or the name of our Python file)
@@ -152,7 +389,10 @@ static status_t greentea_setup(const size_t number_of_cases) {
 static Case cases[] = {
     Case("test bike system", test_bike_system),
     Case("test bike system with event queue", test_bike_system_event_queue),
-    Case("test bike system with event handling", test_bike_system_with_event),
+    Case("test bike system with event", test_bike_system_with_event),
+    Case("test multi-tasking bike system", test_multi_tasking_bike_system),
+    Case("test reset multi-tasking bike system", test_reset_multi_tasking_bike_system),
+    Case("test gear multi-tasking bike system", test_gear_multi_tasking_bike_system),
 };
 
 static Specification specification(greentea_setup, cases);
@@ -160,4 +400,9 @@ static Specification specification(greentea_setup, cases);
 };  // namespace v1
 };  // namespace utest
 
-int main() { return !utest::v1::Harness::run(utest::v1::specification); }
+int main() {
+#if defined(MBED_CONF_MBED_TRACE_ENABLE)
+    mbed_trace_init();
+#endif
+    return !utest::v1::Harness::run(utest::v1::specification);
+}
diff --git a/common/constants.hpp b/common/constants.hpp
index 859a210..8ba92e1 100644
--- a/common/constants.hpp
+++ b/common/constants.hpp
@@ -52,9 +52,8 @@ static constexpr std::chrono::milliseconds kMaxPedalRotationTime = 1500ms;
 static constexpr std::chrono::milliseconds kDeltaPedalRotationTime = 25ms;
 
 static constexpr uint32_t kNbrOfSteps = static_cast<uint32_t>(
-    (
-        bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime
-    ).count() / bike_computer::kDeltaPedalRotationTime.count()
-);
+    (bike_computer::kMaxPedalRotationTime - bike_computer::kMinPedalRotationTime)
+        .count() /
+    bike_computer::kDeltaPedalRotationTime.count());
 
-}  // namespace bike_computer
\ No newline at end of file
+}  // namespace bike_computer
diff --git a/common/sensor_device.cpp b/common/sensor_device.cpp
index 4aa7ef2..69d3344 100644
--- a/common/sensor_device.cpp
+++ b/common/sensor_device.cpp
@@ -1,21 +1,37 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file speedometer_device.cpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ *
+ * @brief WheelCounterDevice implementation (static scheduling)
+ *
+ * @date 2023-08-20
+ * @version 1.0.0
+ ***************************************************************************/
+
 #include "sensor_device.hpp"
 
 namespace bike_computer {
 
-SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11) 
-{}
+SensorDevice::SensorDevice() : _hdc1000(I2C_SDA, I2C_SCL, STMOD_11) {}
 
-bool SensorDevice::init() {
-    return this->_hdc1000.probe();
-}
+bool SensorDevice::init() { return this->_hdc1000.probe(); }
 
-float SensorDevice::readTemperature(void) {
-    return this->_hdc1000.getTemperature();
-}
+float SensorDevice::readTemperature(void) { return this->_hdc1000.getTemperature(); }
 
-float SensorDevice::readHumidity(void) {
-    return this->_hdc1000.getHumidity();
-}
-
-} // bike_computer
+float SensorDevice::readHumidity(void) { return this->_hdc1000.getHumidity(); }
 
+}  // namespace bike_computer
diff --git a/common/sensor_device.hpp b/common/sensor_device.hpp
index d6ead2c..37bc1f1 100644
--- a/common/sensor_device.hpp
+++ b/common/sensor_device.hpp
@@ -46,4 +46,4 @@ class SensorDevice {
     advembsof::HDC1000 _hdc1000;
 };
 
-}  // namespace bike_computer
\ No newline at end of file
+}  // namespace bike_computer
diff --git a/common/speedometer.cpp b/common/speedometer.cpp
index a24d685..2fbf212 100644
--- a/common/speedometer.cpp
+++ b/common/speedometer.cpp
@@ -24,9 +24,8 @@
 
 #include "speedometer.hpp"
 
-#include "static_scheduling/gear_device.hpp"
-
 #include <chrono>
+#include <cstddef>
 #include <ratio>
 
 // from disco_h747i/wrappers
@@ -80,7 +79,12 @@ float Speedometer::getDistance() {
 }
 
 void Speedometer::reset() {
-    // TODO : done
+#if defined(MBED_TEST_MODE)
+    if (_cbOnReset != NULL) {
+        _cbOnReset();
+    }
+#endif
+
     this->_totalDistanceMutex.lock();
     this->_totalDistance = 0.0f;
     this->_totalDistanceMutex.unlock();
@@ -96,6 +100,7 @@ float Speedometer::getTraySize() const { return kTraySize; }
 std::chrono::milliseconds Speedometer::getCurrentPedalRotationTime() const {
     return _pedalRotationTime;
 }
+void Speedometer::setOnResetCallback(mbed::Callback<void()> cb) { _cbOnReset = cb; }
 
 #endif  // defined(MBED_TEST_MODE)
 
@@ -107,11 +112,14 @@ void Speedometer::computeSpeed() {
     // = 6.99m If you ride at 80 pedal turns / min, you run a distance of 6.99 * 80 / min
     // ~= 560 m / min = 33.6 km/h
 
-    // TODO : done
-    //Distance run with one pedal turn = tray size / rear gear size * circumference of the wheel
+    // Distance run with one pedal turn = tray size / rear gear size * circumference of
+    // the wheel
     constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
-    float pedal_rotation_per_hour = ms_in_hour / std::chrono::duration_cast<std::chrono::milliseconds>(_pedalRotationTime).count();
-    float gear_ratio = static_cast<float>(kTraySize) / static_cast<float>(this->_gearSize);
+    float pedal_rotation_per_hour =
+        ms_in_hour /
+        std::chrono::duration_cast<std::chrono::milliseconds>(_pedalRotationTime).count();
+    float gear_ratio =
+        static_cast<float>(kTraySize) / static_cast<float>(this->_gearSize);
     float wheel_dist_km = static_cast<float>(this->kWheelCircumference) / 1000.0;
     this->_currentSpeed = gear_ratio * wheel_dist_km * pedal_rotation_per_hour;
 }
@@ -125,14 +133,13 @@ void Speedometer::computeDistance() {
     // ~= 560 m / min = 33.6 km/h. We then multiply the speed by the time for getting the
     // distance traveled.
 
-    // TODO : done
     Speedometer::computeSpeed();
     // compute distance
 
-    const std::chrono::microseconds timeNow = _timer.elapsed_time();
+    const std::chrono::microseconds timeNow  = _timer.elapsed_time();
     const std::chrono::microseconds timeDiff = timeNow - _lastTime;
-    constexpr float ms_in_hour = static_cast<float>(3600 * 1000);
-    float traveled_dist = _currentSpeed * timeDiff.count() / (ms_in_hour*1000.0/*μs*/);
+    constexpr float ms_in_hour               = static_cast<float>(3600 * 1000);
+    float traveled_dist = _currentSpeed * timeDiff.count() / (ms_in_hour * 1000.0 /*μs*/);
 
     this->_totalDistanceMutex.lock();
     this->_totalDistance += traveled_dist;
diff --git a/common/speedometer.hpp b/common/speedometer.hpp
index bbc1e6b..e831cb2 100644
--- a/common/speedometer.hpp
+++ b/common/speedometer.hpp
@@ -55,6 +55,7 @@ class Speedometer {
     float getTraySize() const;
     std::chrono::milliseconds getCurrentPedalRotationTime() const;
     void setOnResetCallback(mbed::Callback<void()> cb);
+    mbed::Callback<void()> _cbOnReset = NULL;
 #endif  // defined(MBED_TEST_MODE)
 
    private:
@@ -79,13 +80,11 @@ class Speedometer {
     float _currentSpeed = 0.0f;
     Mutex _totalDistanceMutex;
     float _totalDistance = 0.0f;
-    uint8_t _gearSize    = 1;
-
-    Thread _thread;
+    uint8_t _gearSize    = bike_computer::kMaxGearSize;
 
 #if defined(MBED_TEST_MODE)
     mbed::Callback<void()> _cb;
 #endif
 };
 
-}  // namespace bike_computer
\ No newline at end of file
+}  // namespace bike_computer
diff --git a/main.cpp b/main.cpp
index 222429a..45253da 100644
--- a/main.cpp
+++ b/main.cpp
@@ -5,10 +5,11 @@
 
 #if !MBED_TEST_MODE
 
-#include "mbed.h"  // NOLINT
-#include "mbed_trace.h"
+#include "mbed.h"        // NOLINT
+#include "mbed_trace.h"  // NOLINT
 // #include "static_scheduling/bike_system.hpp"
 #include "static_scheduling_with_event/bike_system.hpp"
+// #include "multi_tasking/bike_system.hpp"
 
 #if defined(MBED_CONF_MBED_TRACE_ENABLE)
 #define TRACE_GROUP "MAIN"
@@ -21,10 +22,12 @@ int main() {
 
     // static_scheduling::BikeSystem bikeSystem;
     // bikeSystem.start();
-    // bikeSystem.startWithEventQueue();
 
     static_scheduling_with_event::BikeSystem bikeSystem;
     bikeSystem.start();
+
+    // multi_tasking::BikeSystem bikeSystem;
+    // bikeSystem.start();
 }
 
 #endif  // MBED_TEST_MODE
diff --git a/mbed-os-bootloader/.clang-format b/mbed-os-bootloader/.clang-format
new file mode 100644
index 0000000..3e33698
--- /dev/null
+++ b/mbed-os-bootloader/.clang-format
@@ -0,0 +1,12 @@
+---
+BasedOnStyle: Google
+IndentWidth: 4
+---
+Language: Cpp
+ColumnLimit: 90
+AlignConsecutiveAssignments: true
+DerivePointerAlignment: false
+PointerAlignment: Left
+BinPackArguments: false
+BinPackParameters: false
+IndentAccessModifiers: false
\ No newline at end of file
diff --git a/mbed-os-bootloader/.gitignore b/mbed-os-bootloader/.gitignore
new file mode 100644
index 0000000..8641c54
--- /dev/null
+++ b/mbed-os-bootloader/.gitignore
@@ -0,0 +1,8 @@
+.build
+.mbed
+projectfiles
+*.py*
+mbed-os
+BUILD
+!BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin
+
diff --git a/mbed-os-bootloader/.mbedignore b/mbed-os-bootloader/.mbedignore
new file mode 100644
index 0000000..c45492f
--- /dev/null
+++ b/mbed-os-bootloader/.mbedignore
@@ -0,0 +1,17 @@
+mbed-os/drivers/device_key/*
+mbed-os/drivers/source/usb/USBMSD.cpp
+mbed-os/drivers/source/SFDP.cpp
+mbed-os/connectivity/cellular/*
+mbed-os/connectivity/drivers/*
+mbed-os/connectivity/FEATURE_BLE/*
+mbed-os/connectivity/libraries/*
+mbed-os/connectivity/lorawan/*
+mbed-os/connectivity/lwipstack/*
+mbed-os/connectivity/nanostack/*
+mbed-os/connectivity/netsocket/*
+mbed-os/connectivity/nfc/*
+mbed-os/features/FEATURE_BOOTLOADER/*
+mbed-os/features/frameworks/mbed-client-cli/*
+mbed-os/features/frameworks/COMPONENT_FPGA_CI_TEST_SHIELD/*
+mbed-os/platform/randlib/*
+mbed-os/storage/kvstore/*
diff --git a/mbed-os-bootloader/.pre-commit-config.yaml b/mbed-os-bootloader/.pre-commit-config.yaml
new file mode 100644
index 0000000..c6018cc
--- /dev/null
+++ b/mbed-os-bootloader/.pre-commit-config.yaml
@@ -0,0 +1,26 @@
+files: ^main.cpp
+repos:
+  - repo: https://github.com/pre-commit/pre-commit-hooks
+    rev: v4.3.0
+    hooks:
+      - id: check-yaml
+        args: [--allow-multiple-documents]
+      - id: end-of-file-fixer
+      - id: trailing-whitespace
+  - repo: https://github.com/pre-commit/mirrors-clang-format
+    rev: "v14.0.6"
+    hooks:
+      - id: clang-format
+  - repo: https://github.com/cpplint/cpplint
+    rev: "1.6.1"
+    hooks:
+      - id: cpplint
+        name: cpplint
+        entry: cpplint --linelength=90 --filter=-build/include_subdir,-whitespace/indent,-build/namespaces,-build/c++11
+  - repo: local
+    hooks:
+      - id: cppcheck
+        name: cppcheck
+        require_serial: true
+        entry: cppcheck --enable=all --suppress=missingInclude --inline-suppr -i mbed-os --std=c++14 --error-exitcode=1
+        language: system
diff --git a/mbed-os-bootloader/BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin b/mbed-os-bootloader/BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin
new file mode 100644
index 0000000..f1e18f4
Binary files /dev/null and b/mbed-os-bootloader/BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin differ
diff --git a/mbed-os-bootloader/main.cpp b/mbed-os-bootloader/main.cpp
new file mode 100644
index 0000000..f401e67
--- /dev/null
+++ b/mbed-os-bootloader/main.cpp
@@ -0,0 +1,35 @@
+#include "mbed.h"
+
+#include "mbed_trace.h"
+#if MBED_CONF_MBED_TRACE_ENABLE
+#define TRACE_GROUP "bootloader"
+#endif // MBED_CONF_MBED_TRACE_ENABLE
+
+#if MBED_CONF_MBED_TRACE_ENABLE
+static UnbufferedSerial g_uart(CONSOLE_TX, CONSOLE_RX);
+
+// Function that directly outputs to an unbuffered serial port in blocking mode.
+static void boot_debug(const char *s) {
+    size_t len = strlen(s);
+    g_uart.write(s, len);
+    g_uart.write("\r\n", 2);
+}
+#endif
+
+int main() {
+#if MBED_CONF_MBED_TRACE_ENABLE
+    mbed_trace_init();
+    mbed_trace_print_function_set(boot_debug);
+#endif // MBED_CONF_MBED_TRACE_ENABLE
+
+    tr_debug("BikeComputer bootloader\r\n");
+
+    // at this stage we directly branch to the main application
+    void *sp = *((void **) POST_APPLICATION_ADDR + 0);  // NOLINT(readability/casting)
+    void *pc = *((void **) POST_APPLICATION_ADDR + 1);  // NOLINT(readability/casting)
+    tr_debug("Starting application at address 0x%08x (sp 0x%08x, pc 0x%08x)\r\n", POST_APPLICATION_ADDR, (uint32_t) sp, (uint32_t) pc);
+
+    mbed_start_application(POST_APPLICATION_ADDR);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/mbed-os-bootloader/mbed-os.lib b/mbed-os-bootloader/mbed-os.lib
new file mode 100644
index 0000000..91bb263
--- /dev/null
+++ b/mbed-os-bootloader/mbed-os.lib
@@ -0,0 +1 @@
+https://github.com/ARMmbed/mbed-os.git#17dc3dc2e6e2817a8bd3df62f38583319f0e4fed
\ No newline at end of file
diff --git a/mbed-os-bootloader/mbed_app.json b/mbed-os-bootloader/mbed_app.json
new file mode 100644
index 0000000..9dd117b
--- /dev/null
+++ b/mbed-os-bootloader/mbed_app.json
@@ -0,0 +1,28 @@
+{
+    "macros": [
+      "MBED_CONF_MBED_TRACE_FEA_IPV6=0"
+    ],
+    "config": {
+      "main-stack-size": {
+       "value": 4096
+      }
+    },
+    "target_overrides": {
+      "*": {
+        "mbed-trace.enable": false,
+        "platform.stdio-convert-newlines": true,
+        "platform.stdio-baud-rate": 115200,
+        "platform.default-serial-baud-rate": 115200,
+        "platform.stdio-buffered-serial": true,
+        "platform.all-stats-enabled": true,
+        "target.printf_lib":"minimal-printf",
+        "platform.minimal-printf-enable-floating-point": true,
+        "platform.minimal-printf-set-floating-point-max-decimals": 2
+      },
+      "DISCO_H747I": {
+        "target.restrict_size": "0x20000",
+        "mbed-trace.enable": true,
+        "mbed-trace.max-level": "TRACE_LEVEL_DEBUG"
+      }
+    }
+  }
\ No newline at end of file
diff --git a/mbed_app.json b/mbed_app.json
index c42f542..44c1335 100644
--- a/mbed_app.json
+++ b/mbed_app.json
@@ -1,27 +1,27 @@
 {
-    "macros": [
-      "MBED_CONF_MBED_TRACE_FEA_IPV6=0"
-    ],
-    "config": {
-      "main-stack-size": {
-       "value": 4096
-      }
-    },
-    "target_overrides": {
-      "*": {
-        "mbed-trace.enable": false,
-        "platform.stdio-convert-newlines": true,
-        "platform.stdio-baud-rate": 115200,
-        "platform.default-serial-baud-rate": 115200,
-        "platform.stdio-buffered-serial": true,
-        "platform.all-stats-enabled": true,
-        "target.printf_lib":"minimal-printf",
-        "platform.minimal-printf-enable-floating-point": true,
-        "platform.minimal-printf-set-floating-point-max-decimals": 2
-      },
-      "DISCO_H747I": {
-        "mbed-trace.enable": true,
-        "mbed-trace.max-level": "TRACE_LEVEL_DEBUG"      
-      }
+  "macros": ["MBED_CONF_MBED_TRACE_FEA_IPV6=0"],
+  "config": {
+    "main-stack-size": {
+      "value": 8192
     }
-  }
\ No newline at end of file
+  },
+  "target_overrides": {
+    "*": {
+      "mbed-trace.enable": false,
+      "platform.stdio-convert-newlines": true,
+      "platform.stdio-baud-rate": 115200,
+      "platform.default-serial-baud-rate": 115200,
+      "platform.stdio-buffered-serial": true,
+      "platform.all-stats-enabled": true,
+      "target.printf_lib": "minimal-printf",
+      "platform.minimal-printf-enable-floating-point": true,
+      "platform.minimal-printf-set-floating-point-max-decimals": 2
+    },
+    "DISCO_H747I": {
+      "mbed-trace.enable": true,
+      "mbed-trace.max-level": "TRACE_LEVEL_DEBUG",
+      "target.bootloader_img": "./mbed-os-bootloader/BUILD/DISCO_H747I/GCC_ARM/mbed-os-bootloader.bin",
+      "target.app_offset": "0x20000"
+    }
+  }
+}
diff --git a/multi_tasking/bike_system.cpp b/multi_tasking/bike_system.cpp
new file mode 100644
index 0000000..112455d
--- /dev/null
+++ b/multi_tasking/bike_system.cpp
@@ -0,0 +1,406 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file bike_system.cpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief Bike System implementation (static scheduling)
+ *
+ * @date 2023-11-15
+ * @version 1.1.0
+ ***************************************************************************/
+
+#include "bike_system.hpp"
+
+#include <chrono>
+#include <cstdint>
+
+#include "cmsis_os.h"
+#include "common/constants.hpp"
+#include "mbed_trace.h"
+
+#if MBED_CONF_MBED_TRACE_ENABLE
+#define TRACE_GROUP "BikeSystem"
+#endif  // MBED_CONF_MBED_TRACE_ENABLE
+
+namespace multi_tasking {
+
+static constexpr std::chrono::milliseconds kGearTaskComputationTime          = 100ms;
+static constexpr std::chrono::milliseconds kSpeedDistanceTaskComputationTime = 200ms;
+static constexpr std::chrono::milliseconds kDisplayTask1Period               = 1600ms;
+static constexpr std::chrono::milliseconds kDisplayTask1Delay                = 300ms;
+static constexpr std::chrono::milliseconds kDisplayTask1ComputationTime      = 200ms;
+static constexpr std::chrono::milliseconds kTemperatureTaskPeriod            = 1600ms;
+static constexpr std::chrono::milliseconds kTemperatureTaskDelay             = 1100ms;
+static constexpr std::chrono::milliseconds kTemperatureTaskComputationTime   = 100ms;
+static constexpr std::chrono::milliseconds kCPUTaskPeriod                    = 1600ms;
+static constexpr std::chrono::milliseconds kCPUTaskDelay                     = 0ms;
+
+BikeSystem::BikeSystem()
+    : _timer(),
+      _isrEventQueue(),
+      _eventQueue(),
+      _mailPedalDevice(),
+      _mailGearDevice(),
+      _mutexGearSize(),
+      _mutexGear(),
+      _mutexSpeed(),
+      _mutexDistance(),
+      _mutexSpeedometer(),
+      _isrEventThread(osPriorityAboveNormal, OS_STACK_SIZE, nullptr, "ISR_Event"),
+      _speedDistanceThread(
+          osPriorityNormal, OS_STACK_SIZE, nullptr, "Speed_distance_Task"),
+      _gearTaskThread(osPriorityAboveNormal, OS_STACK_SIZE, nullptr, "Gear_Task"),
+      _gearDevice(&_mailGearDevice, _timer),
+      _pedalDevice(&_mailPedalDevice, _timer),
+      _resetDevice(callback(this, &BikeSystem::onReset)),
+      _displayDevice(),
+      _speedometer(_timer),
+      _sensorDevice(),
+      _taskLogger(),
+      _cpuLogger(_timer) {}
+
+#if defined(MBED_TEST_MODE)
+const advembsof::TaskLogger& BikeSystem::getTaskLogger() { return _taskLogger; }
+
+bike_computer::Speedometer& BikeSystem::getSpeedometer() {
+    // ENTER CRITICAL SECTION
+    _mutexSpeedometer.lock();
+    bike_computer::Speedometer& speedometer = _speedometer;
+    _mutexSpeedometer.unlock();
+    // END CRITICAL SECTION
+
+    return speedometer;
+}
+
+GearDevice& BikeSystem::getGearDevice() { return _gearDevice; }
+
+void BikeSystem::setCallbackGearChage(Callback<void()> cbGearChange) {
+    _cbGearChange = cbGearChange;
+}
+
+#endif  // defined(MBED_TEST_MODE)
+
+void BikeSystem::init() {
+    // start the timer
+    _timer.start();
+
+    // initialize the lcd display
+    disco::ReturnCode rc = _displayDevice.init();
+    if (rc != disco::ReturnCode::Ok) {
+        tr_error("Ffalseailed to initialized the lcd display: %d", static_cast<int>(rc));
+    }
+
+    // initialize the sensor device
+    bool present = _sensorDevice.init();
+    if (!present) {
+        tr_error("Sensor not present or initialization failed");
+    }
+
+    // enable/disable task logging
+    bool runTaskLogger = false;
+
+#if defined(MBED_TEST_MODE)
+    runTaskLogger = true;
+#endif
+
+    _taskLogger.enable(runTaskLogger);
+}
+
+void BikeSystem::start() {
+    init();
+
+    Event<void()> temperatureEvent(&_eventQueue,
+                                   callback(this, &BikeSystem::temperatureTask));
+    temperatureEvent.delay(kTemperatureTaskDelay);
+    temperatureEvent.period(kTemperatureTaskPeriod);
+    temperatureEvent.post();
+
+    Event<void()> displayEvent(&_eventQueue, callback(this, &BikeSystem::displayTask));
+    displayEvent.delay(kDisplayTask1Delay);
+    displayEvent.period(kDisplayTask1Period);
+    displayEvent.post();
+
+    osStatus status =
+        _isrEventThread.start(callback(this, &BikeSystem::dispatch_isr_events));
+    if (status != osOK) {
+        tr_error("Thread %s started with status %ld",
+                 _isrEventThread.get_name(),
+                 static_cast<int32_t>(status));
+    }
+
+    status =
+        _speedDistanceThread.start(callback(this, &BikeSystem::loop_speed_distance_task));
+    if (status != osOK) {
+        tr_error("Thread %s started with status %ld",
+                 _isrEventThread.get_name(),
+                 static_cast<int32_t>(status));
+    }
+
+    status = _gearTaskThread.start(callback(this, &BikeSystem::loop_gear_task));
+    if (status != osOK) {
+        tr_error("Thread %s started with status %ld",
+                 _gearTaskThread.get_name(),
+                 static_cast<int32_t>(status));
+    }
+
+#if !defined(MBED_TEST_MODE)
+    Event<void()> cpuEvent(&_eventQueue, callback(this, &BikeSystem::cpuTask));
+    cpuEvent.delay(kCPUTaskDelay);
+    cpuEvent.period(kCPUTaskPeriod);
+    cpuEvent.post();
+#endif
+
+    // dispatch the main queue in the main thread
+    dispatch_events();
+}
+
+void BikeSystem::stop() {
+    osStatus status = _isrEventThread.terminate();
+    status += _speedDistanceThread.terminate();
+    status += _gearTaskThread.terminate();
+    if (status != 0) {
+        tr_error("Stop thread error");
+    }
+    tr_info("Bike system has stopped !");
+}
+
+/* Callback from isr */
+
+void BikeSystem::onReset() {
+    _resetTime = _timer.elapsed_time();
+    Event<void()> resetEvent(&_isrEventQueue, callback(this, &BikeSystem::resetTask));
+    resetEvent.post();
+}
+
+// ISR thread functions
+
+void BikeSystem::resetTask() {
+#if !defined(MBED_TEST_MODE)
+    auto taskStartTime = _timer.elapsed_time();
+
+    std::chrono::microseconds responseTime = _timer.elapsed_time() - _resetTime;
+    tr_info("Reset task: response time is %" PRIu64 " usecs", responseTime.count());
+#endif
+    // ENTER CRITICAL SECTION
+    _mutexSpeedometer.lock();
+    _speedometer.reset();
+    _mutexSpeedometer.unlock();
+    // END CRITICAL SECTION
+
+#if !defined(MBED_TEST_MODE)
+    _taskLogger.logPeriodAndExecutionTime(
+        _timer, advembsof::TaskLogger::kResetTaskIndex, taskStartTime);
+#endif
+}
+
+// Speed distance thread functions
+
+void BikeSystem::speedDistanceTask() {
+    auto taskStartTime = _timer.elapsed_time();
+
+    pedalMail_t* currentStep = _mailPedalDevice.try_get();
+
+    if (currentStep != nullptr) {
+        const auto pedalRotationTime =
+            PedalDevice::getCurrentRotationTime(currentStep->step);
+
+        // ENTER CRITICAL SECTION
+        _mutexSpeedometer.lock();
+        _speedometer.setCurrentRotationTime(pedalRotationTime);
+        _mutexSpeedometer.unlock();
+        // END CRITICAL SECTION
+
+        std::chrono::microseconds responseTime =
+            _timer.elapsed_time() - currentStep->callTime;
+        tr_info("Speed distance task: response time is %" PRIu64 " usecs",
+                responseTime.count());
+
+        osStatus status = _mailPedalDevice.free(currentStep);
+        if (status != osOK) {
+            tr_error("free current step in the speed distance tasks doesn't work !");
+        }
+    }
+
+    // ENTER CRITICAL SECTION
+    _mutexSpeedometer.lock();
+    _speedometer.setGearSize(getCurrentGearSize());
+    _mutexSpeed.lock();
+    _currentSpeed = _speedometer.getCurrentSpeed();
+    _mutexSpeed.unlock();
+    _mutexDistance.lock();
+    _traveledDistance = _speedometer.getDistance();
+    _mutexDistance.unlock();
+    _mutexSpeedometer.unlock();
+    // END CRITICAL SECTION
+
+    ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
+        kSpeedDistanceTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
+
+    _taskLogger.logPeriodAndExecutionTime(
+        _timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime);
+}
+
+/* Gear thread functions */
+void BikeSystem::gearTask() {
+    auto taskStartTime = _timer.elapsed_time();
+
+    gearMail_t* currentGear = _mailGearDevice.try_get();
+
+    if (currentGear != nullptr) {
+#if !defined(MBED_TEST_MODE)
+        std::chrono::microseconds responseTime =
+            _timer.elapsed_time() - currentGear->callTime;
+        tr_info("Gear task: response time is %" PRIu64 " usecs", responseTime.count());
+#endif
+
+#if defined(MBED_TEST_MODE)
+        _cbGearChange();
+#endif
+
+        // ENTER CRITICAL SECTION
+        _mutexGear.lock();
+        _currentGear = currentGear->gear;
+        _mutexGear.unlock();
+        _mutexGearSize.lock();
+        _currentGearSize = bike_computer::kMaxGearSize - currentGear->gear;
+        _mutexGearSize.unlock();
+        // END CRITICAL SECTION
+
+        osStatus status = _mailGearDevice.free(currentGear);
+        if (status != osOK) {
+            tr_error("free current gear in the gear tasks doesn't work !");
+        }
+    }
+
+    ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
+        kGearTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
+
+    _taskLogger.logPeriodAndExecutionTime(
+        _timer, advembsof::TaskLogger::kGearTaskIndex, taskStartTime);
+}
+
+/* Main thread functions */
+
+void BikeSystem::temperatureTask() {
+    auto taskStartTime = _timer.elapsed_time();
+
+    // no need to protect access to data members (single threaded)
+    _currentTemperature = _sensorDevice.readTemperature();
+
+    ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(
+        kTemperatureTaskComputationTime - (_timer.elapsed_time() - taskStartTime)));
+
+    _taskLogger.logPeriodAndExecutionTime(
+        _timer, advembsof::TaskLogger::kTemperatureTaskIndex, taskStartTime);
+}
+
+void BikeSystem::displayTask() {
+    auto taskStartTime = _timer.elapsed_time();
+
+    // ENTER CRITICAL SECTION
+    _displayDevice.displayGear(getCurrentGear());
+    _displayDevice.displaySpeed(getCurrentSpeed());
+    _displayDevice.displayDistance(getCurrentDistance());
+    // END CRITICAL SECTION
+
+    _displayDevice.displayTemperature(_currentTemperature);
+
+    // ThisThread::sleep_for(std::chrono::duration_cast<std::chrono::milliseconds>(kDisplayTask1ComputationTime
+    // - (_timer.elapsed_time() - taskStartTime)));
+
+    _taskLogger.logPeriodAndExecutionTime(
+        _timer, advembsof::TaskLogger::kDisplayTask1Index, taskStartTime);
+}
+
+void BikeSystem::cpuTask() { _cpuLogger.printStats(); }
+
+void BikeSystem::dispatch_isr_events() {
+    tr_info("Start dispatching isr events");
+    _isrEventQueue.dispatch_forever();
+    tr_info("Stop dispatching isr events");
+}
+
+void BikeSystem::dispatch_events() {
+    tr_info("Start dispatching main events");
+    _eventQueue.dispatch_forever();
+    tr_info("Stop dispatching main events");
+}
+
+void BikeSystem::loop_speed_distance_task() {
+    tr_info("Start loop speed-distance calculation");
+    while (true) {
+        speedDistanceTask();
+    }
+}
+
+void BikeSystem::loop_gear_task() {
+    tr_info("Start loop gear calculation");
+    while (true) {
+        gearTask();
+    }
+}
+
+uint8_t BikeSystem::getCurrentGear() {
+    uint8_t currentGear;
+
+    // ENTER CRITICAL SECTION
+    _mutexGear.lock();
+    currentGear = _currentGear;
+    _mutexGear.unlock();
+    // END CRITICAL SECTION
+
+    return currentGear;
+}
+
+uint8_t BikeSystem::getCurrentGearSize() {
+    uint8_t currentGearSize;
+
+    // ENTER CRITICAL SECTION
+    _mutexGearSize.lock();
+    currentGearSize = _currentGearSize;
+    _mutexGearSize.unlock();
+    // END CRITICAL SECTION
+
+    return currentGearSize;
+}
+
+float BikeSystem::getCurrentSpeed() {
+    float currentSpeed;
+
+    // ENTER CRITICAL SECTION
+    _mutexSpeed.lock();
+    currentSpeed = _currentSpeed;
+    _mutexSpeed.unlock();
+    // END CRITICAL SECTION
+
+    return currentSpeed;
+}
+
+float BikeSystem::getCurrentDistance() {
+    float currentDistance;
+
+    // ENTER CRITICAL SECTION
+    _mutexDistance.lock();
+    currentDistance = _traveledDistance;
+    _mutexDistance.unlock();
+    // END CRITICAL SECTION
+
+    return currentDistance;
+}
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/bike_system.hpp b/multi_tasking/bike_system.hpp
new file mode 100644
index 0000000..41a1935
--- /dev/null
+++ b/multi_tasking/bike_system.hpp
@@ -0,0 +1,171 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file bike_system.hpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ *
+ * @brief Bike System header file (static scheduling)
+ *
+ * @date 2023-08-20
+ * @version 1.0.0
+ ***************************************************************************/
+
+#pragma once
+
+// from advembsof
+#include "cpu_logger.hpp"
+#include "display_device.hpp"
+#include "mbed.h"
+#include "task_logger.hpp"
+
+// from common
+#include "sensor_device.hpp"
+#include "speedometer.hpp"
+
+// local
+#include "gear_device.hpp"
+#include "pedal_device.hpp"
+#include "reset_device.hpp"
+
+namespace multi_tasking {
+
+class BikeSystem {
+   public:
+    // constructor
+    BikeSystem();
+
+    // make the class non copyable
+    BikeSystem(BikeSystem&)            = delete;
+    BikeSystem& operator=(BikeSystem&) = delete;
+
+    // method called in main() for starting the system
+    void start();
+
+    // method called for stopping the system
+    void stop();
+
+#if defined(MBED_TEST_MODE)
+    const advembsof::TaskLogger& getTaskLogger();
+    bike_computer::Speedometer& getSpeedometer();
+    GearDevice& getGearDevice();
+    void setCallbackGearChage(Callback<void()> cbGearChange);
+    Callback<void()> _cbGearChange;
+#endif  // defined(MBED_TEST_MODE)
+
+   private:
+    // private methods
+    void init();
+
+    // Main Thread
+    void temperatureTask();
+    void displayTask();
+    void cpuTask();
+
+// ISR Thread
+#if defined(MBED_TEST_MODE)
+
+   public:
+#endif
+    void onReset();
+#if defined(MBED_TEST_MODE)
+
+   private:
+#endif
+
+    void resetTask();
+
+    // gear Thread
+    void gearTask();
+
+    // Speed / Distance Thread
+    void speedDistanceTask();
+
+    // GETTER - SETTER
+    uint8_t getCurrentGear();
+    uint8_t getCurrentGearSize();
+    float getCurrentSpeed();
+    float getCurrentDistance();
+    void setCurrentGear(uint8_t gear);
+
+    // Thread functions
+    void dispatch_isr_events();
+    void dispatch_events();
+    void loop_speed_distance_task();
+    void loop_gear_task();
+
+    // timer instance used for loggint task time and used by ResetDevice
+    std::chrono::microseconds _resetTime      = std::chrono::microseconds::zero();
+    std::chrono::microseconds _onGearUpTime   = std::chrono::microseconds::zero();
+    std::chrono::microseconds _onGearDownTime = std::chrono::microseconds::zero();
+
+    Timer _timer;
+
+    // Event queues
+    EventQueue _isrEventQueue;
+    EventQueue _eventQueue;
+
+    // Mail
+    Mail<pedalMail_t, 16> _mailPedalDevice;
+    Mail<gearMail_t, 16> _mailGearDevice;
+
+    // mutex for shared resource
+    Mutex _mutexGearSize;
+    Mutex _mutexGear;
+    Mutex _mutexSpeed;
+    Mutex _mutexDistance;
+    Mutex _mutexSpeedometer;
+
+    // Tread for isr events
+    Thread _isrEventThread;
+    Thread _speedDistanceThread;
+    Thread _gearTaskThread;
+
+    // data member that represents the device for manipulating the gear
+    GearDevice _gearDevice;
+
+    //////////////////////////////////////////////////////////////
+    // shared resources between the main thread and the isr thread
+    uint8_t _currentGear     = bike_computer::kMinGear;
+    uint8_t _currentGearSize = bike_computer::kMaxGearSize;
+    //////////////////////////////////////////////////////////////
+
+    // data member that represents the device for manipulating the pedal rotation
+    // speed/time
+    PedalDevice _pedalDevice;
+
+    //////////////////////////////////////////////////////////////
+    // shared resources between the main thread and the isr thread
+    float _currentSpeed     = 0.0f;
+    float _traveledDistance = 0.0f;
+    //////////////////////////////////////////////////////////////
+
+    // data member that represents the device used for resetting
+    ResetDevice _resetDevice;
+    // data member that represents the device display
+    advembsof::DisplayDevice _displayDevice;
+    // data member that represents the device for counting wheel rotations
+    bike_computer::Speedometer _speedometer;
+    // data member that represents the sensor device
+    bike_computer::SensorDevice _sensorDevice;
+    float _currentTemperature = 0.0f;
+
+    // used for logging task info
+    advembsof::TaskLogger _taskLogger;
+
+    // cpu logger to measure cpu usage
+    advembsof::CPULogger _cpuLogger;
+};
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/gear_device.cpp b/multi_tasking/gear_device.cpp
new file mode 100644
index 0000000..e45a69c
--- /dev/null
+++ b/multi_tasking/gear_device.cpp
@@ -0,0 +1,74 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file gear_device.cpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief Gear Device implementation (static scheduling)
+ *
+ * @date 2023-11-17
+ * @version 1.1.0
+ ***************************************************************************/
+
+#include "gear_device.hpp"
+
+#include "bike_system.hpp"
+
+// from disco_h747i/wrappers
+
+#include "joystick.hpp"
+#include "mbed_atomic.h"
+#include "mbed_trace.h"
+
+#if MBED_CONF_MBED_TRACE_ENABLE
+#define TRACE_GROUP "GearDevice"
+#endif  // MBED_CONF_MBED_TRACE_ENABLE
+
+namespace multi_tasking {
+
+GearDevice::GearDevice(Mail<gearMail_t, 16>* mailBox, Timer& timer)
+    : _mailBox(mailBox), _timer(timer) {
+    disco::Joystick::getInstance().setUpCallback(callback(this, &GearDevice::onUp));
+    disco::Joystick::getInstance().setDownCallback(callback(this, &GearDevice::onDown));
+}
+
+void GearDevice::onUp() {
+    if (_currentGear < bike_computer::kMaxGear) {
+        core_util_atomic_incr_u8(&_currentGear, 1);
+        sendMail(core_util_atomic_load_u8(&_currentGear));
+    }
+}
+
+void GearDevice::onDown() {
+    if (_currentGear > bike_computer::kMinGear) {
+        core_util_atomic_decr_u8(&_currentGear, 1);
+        sendMail(core_util_atomic_load_u8(&_currentGear));
+    }
+}
+
+void GearDevice::sendMail(uint32_t data) {
+    if (_mailBox != nullptr) {
+        gearMail_t* currentGear = _mailBox->try_alloc();
+        if (currentGear != nullptr) {
+            currentGear->gear     = data;
+            currentGear->callTime = _timer.elapsed_time();
+            _mailBox->put(currentGear);
+        }
+    }
+}
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/gear_device.hpp b/multi_tasking/gear_device.hpp
new file mode 100644
index 0000000..5ec23c5
--- /dev/null
+++ b/multi_tasking/gear_device.hpp
@@ -0,0 +1,61 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file gear_device.hpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief Gear Device header file (static scheduling)
+ *
+ * @date 2023-11-17
+ * @version 1.1.0
+ ***************************************************************************/
+
+#pragma once
+
+#include "common/constants.hpp"
+#include "mbed.h"
+
+namespace multi_tasking {
+
+typedef struct gearMail {
+    uint8_t gear;
+    std::chrono::microseconds callTime;
+} gearMail_t;
+
+class GearDevice {
+   public:
+    explicit GearDevice(Mail<gearMail_t, 16>* mailBox,
+                        Timer& timer);  // NOLINT(runtime/references)
+
+    // make the class non copyable
+    GearDevice(GearDevice&)            = delete;
+    GearDevice& operator=(GearDevice&) = delete;
+
+    // method called for updating the bike system
+    void onUp();
+    void onDown();
+
+    void sendMail(uint32_t data);
+
+   private:
+    // data members
+    volatile uint8_t _currentGear = bike_computer::kMinGear;
+    Mail<gearMail_t, 16>* _mailBox;
+    Timer& _timer;
+};
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/pedal_device.cpp b/multi_tasking/pedal_device.cpp
new file mode 100644
index 0000000..29d600f
--- /dev/null
+++ b/multi_tasking/pedal_device.cpp
@@ -0,0 +1,85 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file pedal_device.cpp
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief Pedal Device implementation (static scheduling)
+ * @date 2024-11-17
+ * @version 1.1.0
+ ****************************************************************************/
+
+#include "pedal_device.hpp"
+
+// from disco_h747i/wrappers
+#include <chrono>
+
+#include "bike_system.hpp"
+#include "joystick.hpp"
+#include "mbed_trace.h"
+
+#if MBED_CONF_MBED_TRACE_ENABLE
+#define TRACE_GROUP "PedalDevice"
+#endif  // MBED_CONF_MBED_TRACE_ENABLE
+
+namespace multi_tasking {
+
+PedalDevice::PedalDevice(Mail<pedalMail_t, 16>* mailBox, Timer& timer)
+    : _mailBox(mailBox), _timer(timer) {
+    disco::Joystick::getInstance().setLeftCallback(callback(this, &PedalDevice::onLeft));
+    disco::Joystick::getInstance().setRightCallback(
+        callback(this, &PedalDevice::onRight));
+}
+
+void PedalDevice::increaseRotationSpeed() {
+    uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
+    if (currentStep > 0) {
+        core_util_atomic_decr_u32(&_currentStep, 1);
+        sendMail(core_util_atomic_load_u32(&_currentStep));
+    }
+}
+
+void PedalDevice::decreaseRotationSpeed() {
+    uint32_t currentStep = core_util_atomic_load_u32(&_currentStep);
+    if (currentStep < bike_computer::kNbrOfSteps) {
+        core_util_atomic_incr_u32(&_currentStep, 1);
+        sendMail(core_util_atomic_load_u32(&_currentStep));
+    }
+}
+
+void PedalDevice::onLeft() { decreaseRotationSpeed(); }
+
+void PedalDevice::onRight() { increaseRotationSpeed(); }
+
+void PedalDevice::sendMail(uint32_t data) {
+    if (_mailBox != nullptr) {
+        pedalMail_t* currentStep = _mailBox->try_alloc();
+        if (currentStep != nullptr) {
+            currentStep->step     = data;
+            currentStep->callTime = _timer.elapsed_time();
+            _mailBox->put(currentStep);
+        }
+    }
+}
+
+// static methods
+
+std::chrono::milliseconds PedalDevice::getCurrentRotationTime(uint32_t step) {
+    return bike_computer::kMinPedalRotationTime +
+           step * bike_computer::kDeltaPedalRotationTime;
+}
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/pedal_device.hpp b/multi_tasking/pedal_device.hpp
new file mode 100644
index 0000000..c6e014d
--- /dev/null
+++ b/multi_tasking/pedal_device.hpp
@@ -0,0 +1,69 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file pedal_device.hpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief Pedal System header file (static scheduling)
+ *
+ * @date 2023-11-17
+ * @version 1.1.0
+ ***************************************************************************/
+
+#pragma once
+
+#include "constants.hpp"
+#include "mbed.h"
+
+namespace multi_tasking {
+
+typedef struct pedalMail {
+    uint8_t step;
+    std::chrono::microseconds callTime;
+} pedalMail_t;
+
+class PedalDevice {
+   public:
+    explicit PedalDevice(Mail<pedalMail_t, 16>* mailBox,  // NOLINT (runtime/references)
+                         Timer& timer);                   // NOLINT (runtime/references)
+
+    // make the class non copyable
+    PedalDevice(PedalDevice&)            = delete;
+    PedalDevice& operator=(PedalDevice&) = delete;
+
+    // method called for updating the bike system
+    static std::chrono::milliseconds getCurrentRotationTime(uint32_t step);
+
+   private:
+    // private methods
+    void onLeft();
+    void onRight();
+    void increaseRotationSpeed();
+    void decreaseRotationSpeed();
+
+    void sendMail(uint32_t data);
+    // data members
+    volatile uint32_t _currentStep = static_cast<uint32_t>(
+        (bike_computer::kInitialPedalRotationTime - bike_computer::kMinPedalRotationTime)
+            .count() /
+        bike_computer::kDeltaPedalRotationTime.count());
+
+    Mail<pedalMail_t, 16>* _mailBox;
+    Timer& _timer;
+};
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/reset_device.cpp b/multi_tasking/reset_device.cpp
new file mode 100644
index 0000000..f4a1fdb
--- /dev/null
+++ b/multi_tasking/reset_device.cpp
@@ -0,0 +1,48 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file reset_device.cpp
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief Reset Device implementation (static scheduling with event)
+ * @date 2024-11-17
+ * @version 1.1.0
+ ****************************************************************************/
+
+#include "reset_device.hpp"
+
+// from disco_h747i/wrappers
+#include <chrono>
+
+#include "joystick.hpp"
+#include "mbed_trace.h"
+
+#if defined(TARGET_DISCO_H747I)
+#define PUSH_BUTTON BUTTON1
+static constexpr uint8_t kPolarityPressed = 1;
+#endif
+
+#if MBED_CONF_MBED_TRACE_ENABLE
+#define TRACE_GROUP "ResetDevice"
+#endif  // MBED_CONF_MBED_TRACE_ENABLE
+
+namespace multi_tasking {
+
+ResetDevice::ResetDevice(Callback<void()> cb) : _resetButton(PUSH_BUTTON) {
+    _resetButton.fall(cb);
+}
+
+}  // namespace multi_tasking
diff --git a/multi_tasking/reset_device.hpp b/multi_tasking/reset_device.hpp
new file mode 100644
index 0000000..c0a57a5
--- /dev/null
+++ b/multi_tasking/reset_device.hpp
@@ -0,0 +1,47 @@
+// Copyright 2022 Haute école d'ingénierie et d'architecture de Fribourg
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/****************************************************************************
+ * @file reset_device.hpp
+ * @author Serge Ayer <serge.ayer@hefr.ch>
+ * @author Rémi Heredero <remi@heredero.ch>
+ * @author Yann Sierro <yannsierro.pro@gmail.com>
+ *
+ * @brief ResetDevice header file (static scheduling with event)
+ *
+ * @date 2023-11-17
+ * @version 1.1.0
+ ***************************************************************************/
+
+#pragma once
+
+#include "mbed.h"
+
+namespace multi_tasking {
+
+class ResetDevice {
+   public:
+    explicit ResetDevice(Callback<void()> cb);  // NOLINT(runtime/references)
+
+    // make the class non copyable
+    ResetDevice(ResetDevice&)            = delete;
+    ResetDevice& operator=(ResetDevice&) = delete;
+
+   private:
+    // data members
+    // instance representing the reset button
+    InterruptIn _resetButton;
+};
+
+}  // namespace multi_tasking
diff --git a/static_scheduling/bike_system.hpp b/static_scheduling/bike_system.hpp
index 67fefd5..5e8ccf2 100644
--- a/static_scheduling/bike_system.hpp
+++ b/static_scheduling/bike_system.hpp
@@ -80,7 +80,7 @@ class BikeSystem {
     // data member that represents the device for manipulating the gear
     GearDevice _gearDevice;
     uint8_t _currentGear     = bike_computer::kMinGear;
-    uint8_t _currentGearSize = bike_computer::kMinGearSize;
+    uint8_t _currentGearSize = bike_computer::kMaxGearSize;
     // data member that represents the device for manipulating the pedal rotation
     // speed/time
     PedalDevice _pedalDevice;
diff --git a/static_scheduling_with_event/bike_system.cpp b/static_scheduling_with_event/bike_system.cpp
index e9416d5..ce87c29 100644
--- a/static_scheduling_with_event/bike_system.cpp
+++ b/static_scheduling_with_event/bike_system.cpp
@@ -62,7 +62,7 @@ static constexpr std::chrono::milliseconds kDisplayTask2ComputationTime = 100ms;
 static constexpr std::chrono::milliseconds kCPUTaskPeriod          = 1600ms;
 static constexpr std::chrono::milliseconds kCPUTaskDelay           = 1200ms;
 static constexpr std::chrono::milliseconds kCPUTaskComputationTime = 100ms;
-  
+
 BikeSystem::BikeSystem()
     : _gearDevice(),
       _pedalDevice(),
@@ -178,7 +178,7 @@ void BikeSystem::speedDistanceTask() {
     _taskLogger.logPeriodAndExecutionTime(
         _timer, advembsof::TaskLogger::kSpeedTaskIndex, taskStartTime);
 }
-  
+
 void BikeSystem::displayTask1() {
     auto taskStartTime = _timer.elapsed_time();
 
diff --git a/static_scheduling_with_event/bike_system.hpp b/static_scheduling_with_event/bike_system.hpp
index 8254f22..c51de14 100644
--- a/static_scheduling_with_event/bike_system.hpp
+++ b/static_scheduling_with_event/bike_system.hpp
@@ -85,7 +85,7 @@ class BikeSystem {
     // data member that represents the device for manipulating the gear
     GearDevice _gearDevice;
     uint8_t _currentGear     = bike_computer::kMinGear;
-    uint8_t _currentGearSize = bike_computer::kMinGearSize;
+    uint8_t _currentGearSize = bike_computer::kMaxGearSize;
     // data member that represents the device for manipulating the pedal rotation
     // speed/time
     PedalDevice _pedalDevice;