diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b3d1edb171..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -os: linux -dist: focal # Ubuntu 20.04LTS -arch: arm64 -#arch: arm64-graviton2 - -language: minimal - -before_install: - - sudo apt-get update - - sudo apt-get install -y python3 python3-pip scons cmake doxygen gcc-10 g++-10 build-essential libboost-all-dev libwiringpi-dev - - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 90 --slave /usr/bin/g++ g++ /usr/bin/g++-10 --slave /usr/bin/gcov gcov /usr/bin/gcov-10 - #- sudo apt-get install -y gcc-arm-none-eabi - - wget -qO- https://developer.arm.com/-/media/Files/downloads/gnu-rm/10-2020q4/gcc-arm-none-eabi-10-2020-q4-major-aarch64-linux.tar.bz2 | tar xvj -C /opt - - export PATH="/opt/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH" - - pip3 install modm - - export PATH="~/.local/bin:$PATH" - - uname -a - -script: - - (cd test && make run-hosted-linux) - - (cd examples && ../tools/scripts/examples_compile.py linux) - - (cd examples && ../tools/scripts/examples_compile.py stm32f1_discovery nucleo_f103rb olimexino_stm32 blue_pill_f103 black_pill_f103) - - (cd examples && ../tools/scripts/examples_compile.py rpi) diff --git a/examples/nucleo_f072rb/independend_watchdog/main.cpp b/examples/nucleo_f072rb/iwdg/main.cpp similarity index 94% rename from examples/nucleo_f072rb/independend_watchdog/main.cpp rename to examples/nucleo_f072rb/iwdg/main.cpp index a767c4d821..bd3d79f3e2 100644 --- a/examples/nucleo_f072rb/independend_watchdog/main.cpp +++ b/examples/nucleo_f072rb/iwdg/main.cpp @@ -13,6 +13,7 @@ #include using namespace Board; +using namespace std::chrono_literals; /** * If the button is pressed for more than 4 seconds, the MCU will be reset by the Watchdog. @@ -25,7 +26,7 @@ main() Board::initialize(); LedD13::setOutput(); // set the watchdog timeout to 4 seconds - Iwdg::initialize(Iwdg::Prescaler::Div32, 0x0FFFu); + Iwdg::initialize(); // Use the logging streams to print some messages. // Change MODM_LOG_LEVEL above to enable or disable these messages diff --git a/examples/nucleo_f072rb/independend_watchdog/project.xml b/examples/nucleo_f072rb/iwdg/project.xml similarity index 100% rename from examples/nucleo_f072rb/independend_watchdog/project.xml rename to examples/nucleo_f072rb/iwdg/project.xml diff --git a/examples/nucleo_l432kc/gyroscope/main.cpp b/examples/nucleo_l432kc/gyroscope/main.cpp index 5180cc25dd..f9fb23cb13 100644 --- a/examples/nucleo_l432kc/gyroscope/main.cpp +++ b/examples/nucleo_l432kc/gyroscope/main.cpp @@ -95,7 +95,7 @@ main() Board::initialize(); UartSpi::Master::connect(); - UartSpi::Master::initialize(); + UartSpi::Master::initialize(); while (true) { reader.update(); diff --git a/repo.lb b/repo.lb index ccecae382c..b72e6996b8 100644 --- a/repo.lb +++ b/repo.lb @@ -257,6 +257,7 @@ def init(repo): repo.add_filter("modm.posixify", posixify) repo.add_filter("modm.ord", lambda letter: ord(letter[0].lower()) - ord("a")) repo.add_filter("modm.chr", lambda num: chr(num + ord("A"))) + repo.add_filter("modm.digsep", lambda num: f"{num:,}".replace(",", "'")) # Compute the available data from modm-devices devices = DevicesCache() diff --git a/src/modm/architecture/interface/peripheral.hpp b/src/modm/architecture/interface/peripheral.hpp index 7277c9291e..ac122b7097 100644 --- a/src/modm/architecture/interface/peripheral.hpp +++ b/src/modm/architecture/interface/peripheral.hpp @@ -84,13 +84,21 @@ class PeripheralDriver * This method checks if the user requested baudrate is within error * tolerance of the system achievable baudrate. */ - template< baudrate_t available, baudrate_t requested, percent_t tolerance > + template< uint64_t available, uint64_t requested, percent_t tolerance > static void assertBaudrateInTolerance() { - static_assert(modm::Tolerance::isValueInTolerance(requested, available, tolerance), + static_assert(modm::isValueInTolerance(requested, available, tolerance), "The closest available baudrate exceeds the tolerance of the requested baudrate!"); } + + template< double available, double requested, percent_t tolerance > + static void + assertDurationInTolerance() + { + static_assert(modm::isValueInTolerance(requested, available, tolerance), + "The closest available duration exceeds the tolerance of the requested duration!"); + } }; } // namespace modm diff --git a/src/modm/board/black_pill_f103/board.hpp b/src/modm/board/black_pill_f103/board.hpp index b14554a88a..ea441ab6a9 100644 --- a/src/modm/board/black_pill_f103/board.hpp +++ b/src/modm/board/black_pill_f103/board.hpp @@ -57,6 +57,7 @@ struct SystemClock static constexpr uint32_t Timer4 = Apb1Timer; static constexpr uint32_t Usb = Ahb / 1.5; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/black_pill_f411/board.hpp b/src/modm/board/black_pill_f411/board.hpp index 64b4e2eb79..fce7c901ae 100644 --- a/src/modm/board/black_pill_f411/board.hpp +++ b/src/modm/board/black_pill_f411/board.hpp @@ -59,6 +59,7 @@ struct SystemClock static constexpr uint32_t Timer11 = Apb2Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/blue_pill_f103/board.hpp b/src/modm/board/blue_pill_f103/board.hpp index accd49906b..dcd053c20c 100644 --- a/src/modm/board/blue_pill_f103/board.hpp +++ b/src/modm/board/blue_pill_f103/board.hpp @@ -57,6 +57,7 @@ struct SystemClock static constexpr uint32_t Timer4 = Apb1Timer; static constexpr uint32_t Usb = Ahb / 1.5; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/devebox_stm32f4xx/board.hpp b/src/modm/board/devebox_stm32f4xx/board.hpp index e3867b6424..241df28de9 100644 --- a/src/modm/board/devebox_stm32f4xx/board.hpp +++ b/src/modm/board/devebox_stm32f4xx/board.hpp @@ -74,6 +74,7 @@ struct SystemClock static constexpr uint32_t Timer12 = Apb1Timer; static constexpr uint32_t Timer13 = Apb1Timer; static constexpr uint32_t Timer14 = Apb1Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/devebox_stm32h750vb/board.hpp b/src/modm/board/devebox_stm32h750vb/board.hpp index c8d74b25a1..721e1b73ba 100644 --- a/src/modm/board/devebox_stm32h750vb/board.hpp +++ b/src/modm/board/devebox_stm32h750vb/board.hpp @@ -94,6 +94,7 @@ struct SystemClock static constexpr uint32_t Timer17 = Apb2Timer; static constexpr uint32_t Usb = 48_MHz; // From PLL3Q + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f051r8/board.hpp b/src/modm/board/disco_f051r8/board.hpp index 4926dd561c..13db330f32 100644 --- a/src/modm/board/disco_f051r8/board.hpp +++ b/src/modm/board/disco_f051r8/board.hpp @@ -32,6 +32,7 @@ struct SystemClock static constexpr int Usart1 = Frequency; static constexpr int Usart2 = Frequency; static constexpr int Spi2 = Frequency; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f072rb/board.hpp b/src/modm/board/disco_f072rb/board.hpp index 60e7d69247..8d109ffc5c 100644 --- a/src/modm/board/disco_f072rb/board.hpp +++ b/src/modm/board/disco_f072rb/board.hpp @@ -59,6 +59,7 @@ struct SystemClock static constexpr uint32_t Timer17 = Apb; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f100rb/board.hpp b/src/modm/board/disco_f100rb/board.hpp index b84d3a314f..441e1042a8 100644 --- a/src/modm/board/disco_f100rb/board.hpp +++ b/src/modm/board/disco_f100rb/board.hpp @@ -67,6 +67,7 @@ struct SystemClock static constexpr uint32_t Timer15 = Apb2Timer; static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f303vc/board.hpp b/src/modm/board/disco_f303vc/board.hpp index 08b67f18d2..02ad1ef169 100644 --- a/src/modm/board/disco_f303vc/board.hpp +++ b/src/modm/board/disco_f303vc/board.hpp @@ -84,6 +84,7 @@ struct SystemClock static constexpr uint32_t Timer17 = Apb2Timer; static constexpr uint32_t Usb = Ahb / 1.5; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f401vc/board.hpp b/src/modm/board/disco_f401vc/board.hpp index ac0d118e38..5f73233742 100644 --- a/src/modm/board/disco_f401vc/board.hpp +++ b/src/modm/board/disco_f401vc/board.hpp @@ -67,6 +67,7 @@ struct SystemClock static constexpr uint32_t Timer11 = Apb2Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f407vg/board.hpp b/src/modm/board/disco_f407vg/board.hpp index da703b7abf..5cefecd167 100644 --- a/src/modm/board/disco_f407vg/board.hpp +++ b/src/modm/board/disco_f407vg/board.hpp @@ -78,6 +78,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb1Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f429zi/board.hpp b/src/modm/board/disco_f429zi/board.hpp index 2a859ac41e..020b8c3008 100644 --- a/src/modm/board/disco_f429zi/board.hpp +++ b/src/modm/board/disco_f429zi/board.hpp @@ -79,6 +79,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb1Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f469ni/board.hpp.in b/src/modm/board/disco_f469ni/board.hpp.in index ba3163135b..c65d59c136 100644 --- a/src/modm/board/disco_f469ni/board.hpp.in +++ b/src/modm/board/disco_f469ni/board.hpp.in @@ -81,6 +81,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb1Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f746ng/board.hpp b/src/modm/board/disco_f746ng/board.hpp index ce09a92b12..1556ab94e2 100644 --- a/src/modm/board/disco_f746ng/board.hpp +++ b/src/modm/board/disco_f746ng/board.hpp @@ -80,6 +80,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb1Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_f769ni/board.hpp b/src/modm/board/disco_f769ni/board.hpp index 4fa836888e..81eb1d2039 100644 --- a/src/modm/board/disco_f769ni/board.hpp +++ b/src/modm/board/disco_f769ni/board.hpp @@ -80,6 +80,7 @@ struct SystemClock static constexpr uint32_t Timer12 = Apb1Timer; static constexpr uint32_t Timer13 = Apb1Timer; static constexpr uint32_t Timer14 = Apb1Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_l152rc/board.hpp b/src/modm/board/disco_l152rc/board.hpp index 0f115fcb0c..c405981635 100644 --- a/src/modm/board/disco_l152rc/board.hpp +++ b/src/modm/board/disco_l152rc/board.hpp @@ -57,6 +57,7 @@ struct SystemClock static constexpr uint32_t Timer9 = Apb2Timer; static constexpr uint32_t Timer10 = Apb2Timer; static constexpr uint32_t Timer11 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/disco_l476vg/board.hpp b/src/modm/board/disco_l476vg/board.hpp index f8175e63b6..c5ae9096b4 100644 --- a/src/modm/board/disco_l476vg/board.hpp +++ b/src/modm/board/disco_l476vg/board.hpp @@ -43,6 +43,7 @@ struct SystemClock static constexpr uint32_t Usart3 = Apb1; static constexpr uint32_t Usart4 = Apb1; static constexpr uint32_t Usart5 = Apb1; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f031k6/board.hpp b/src/modm/board/nucleo_f031k6/board.hpp index 5f61a9cc01..c2decbfe28 100644 --- a/src/modm/board/nucleo_f031k6/board.hpp +++ b/src/modm/board/nucleo_f031k6/board.hpp @@ -48,6 +48,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb; static constexpr uint32_t Timer16 = Apb; static constexpr uint32_t Timer17 = Apb; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f042k6/board.hpp b/src/modm/board/nucleo_f042k6/board.hpp index 893406afa8..09f8aa93c7 100644 --- a/src/modm/board/nucleo_f042k6/board.hpp +++ b/src/modm/board/nucleo_f042k6/board.hpp @@ -51,6 +51,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb; static constexpr uint32_t Timer16 = Apb; static constexpr uint32_t Timer17 = Apb; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f072rb/board.hpp b/src/modm/board/nucleo_f072rb/board.hpp index 5f240f1218..17b9c1d2d5 100644 --- a/src/modm/board/nucleo_f072rb/board.hpp +++ b/src/modm/board/nucleo_f072rb/board.hpp @@ -59,6 +59,7 @@ struct SystemClock static constexpr uint32_t Timer17 = Apb; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f091rc/board.hpp b/src/modm/board/nucleo_f091rc/board.hpp index 0a839d0b94..15a568e159 100644 --- a/src/modm/board/nucleo_f091rc/board.hpp +++ b/src/modm/board/nucleo_f091rc/board.hpp @@ -58,6 +58,7 @@ struct SystemClock static constexpr uint32_t Timer17 = Apb; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f103rb/board.hpp b/src/modm/board/nucleo_f103rb/board.hpp index 787be72758..7ad9c9db30 100644 --- a/src/modm/board/nucleo_f103rb/board.hpp +++ b/src/modm/board/nucleo_f103rb/board.hpp @@ -62,6 +62,7 @@ struct SystemClock static constexpr uint32_t Timer6 = Apb1Timer; static constexpr uint32_t Timer7 = Apb1Timer; static constexpr uint32_t Timer8 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f303k8/board.hpp b/src/modm/board/nucleo_f303k8/board.hpp index c1079d8c13..53c933c586 100644 --- a/src/modm/board/nucleo_f303k8/board.hpp +++ b/src/modm/board/nucleo_f303k8/board.hpp @@ -59,6 +59,7 @@ struct SystemClock { static constexpr uint32_t Timer15 = Apb2Timer; static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f303re/board.hpp b/src/modm/board/nucleo_f303re/board.hpp index bffe378a96..4fd12154b0 100644 --- a/src/modm/board/nucleo_f303re/board.hpp +++ b/src/modm/board/nucleo_f303re/board.hpp @@ -62,6 +62,7 @@ struct SystemClock static constexpr uint32_t Timer15 = Apb2Timer; static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f334r8/board.hpp b/src/modm/board/nucleo_f334r8/board.hpp index 2d41cce544..80fde9d9b2 100644 --- a/src/modm/board/nucleo_f334r8/board.hpp +++ b/src/modm/board/nucleo_f334r8/board.hpp @@ -59,6 +59,7 @@ struct SystemClock static constexpr uint32_t Timer15 = Apb2Timer; static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f401re/board.hpp b/src/modm/board/nucleo_f401re/board.hpp index 7f28db9805..e5188b7e64 100644 --- a/src/modm/board/nucleo_f401re/board.hpp +++ b/src/modm/board/nucleo_f401re/board.hpp @@ -60,6 +60,7 @@ struct SystemClock static constexpr uint32_t Timer9 = Apb2Timer; static constexpr uint32_t Timer10 = Apb2Timer; static constexpr uint32_t Timer11 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f411re/board.hpp b/src/modm/board/nucleo_f411re/board.hpp index 2f8553e456..5fff5998fb 100644 --- a/src/modm/board/nucleo_f411re/board.hpp +++ b/src/modm/board/nucleo_f411re/board.hpp @@ -62,6 +62,7 @@ struct SystemClock static constexpr uint32_t Timer9 = Apb2Timer; static constexpr uint32_t Timer10 = Apb2Timer; static constexpr uint32_t Timer11 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f429zi/board.hpp b/src/modm/board/nucleo_f429zi/board.hpp index 256003a372..7fbd76ab26 100644 --- a/src/modm/board/nucleo_f429zi/board.hpp +++ b/src/modm/board/nucleo_f429zi/board.hpp @@ -78,6 +78,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb1Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f446re/board.hpp b/src/modm/board/nucleo_f446re/board.hpp index b4bd50cf2e..783fbb4cb6 100644 --- a/src/modm/board/nucleo_f446re/board.hpp +++ b/src/modm/board/nucleo_f446re/board.hpp @@ -69,6 +69,7 @@ struct SystemClock static constexpr uint32_t Timer9 = Apb2Timer; static constexpr uint32_t Timer10 = Apb2Timer; static constexpr uint32_t Timer11 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f446ze/board.hpp b/src/modm/board/nucleo_f446ze/board.hpp index 2014a8a881..ed745af920 100644 --- a/src/modm/board/nucleo_f446ze/board.hpp +++ b/src/modm/board/nucleo_f446ze/board.hpp @@ -70,6 +70,7 @@ struct SystemClock static constexpr uint32_t Timer11 = Apb2Timer; static constexpr uint32_t Usb = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f746zg/board.hpp b/src/modm/board/nucleo_f746zg/board.hpp index a83d8e1fd0..4d2c366447 100755 --- a/src/modm/board/nucleo_f746zg/board.hpp +++ b/src/modm/board/nucleo_f746zg/board.hpp @@ -83,6 +83,7 @@ struct SystemClock static constexpr uint32_t Timer12 = Apb1Timer; static constexpr uint32_t Timer13 = Apb1Timer; static constexpr uint32_t Timer14 = Apb1Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_f767zi/board.hpp b/src/modm/board/nucleo_f767zi/board.hpp index 766aecedd4..9f02baa432 100755 --- a/src/modm/board/nucleo_f767zi/board.hpp +++ b/src/modm/board/nucleo_f767zi/board.hpp @@ -81,6 +81,7 @@ struct SystemClock static constexpr uint32_t Timer12 = Apb1Timer; static constexpr uint32_t Timer13 = Apb1Timer; static constexpr uint32_t Timer14 = Apb1Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_g070rb/board.hpp b/src/modm/board/nucleo_g070rb/board.hpp deleted file mode 100644 index 91957c0e92..0000000000 --- a/src/modm/board/nucleo_g070rb/board.hpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2019, Niklas Hauser - * Copyright (c) 2023, Christopher Durand - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef MODM_STM32_NUCLEO_G070RB_HPP -#define MODM_STM32_NUCLEO_G070RB_HPP - -#include -#include -#include -/// @ingroup modm_board_nucleo_g070rb -#define MODM_BOARD_HAS_LOGGER - -using namespace modm::platform; - -namespace Board -{ -/// @ingroup modm_board_nucleo_g070rb -/// @{ -using namespace modm::literals; - -/// STM32G070RB running at 64MHz generated from the internal 16MHz oscillator -struct SystemClock -{ - static constexpr uint32_t Frequency = 64_MHz; - static constexpr uint32_t Ahb = Frequency; - static constexpr uint32_t Apb = Frequency; - - static constexpr uint32_t Rng = Ahb; - static constexpr uint32_t Crc = Ahb; - static constexpr uint32_t Flash = Ahb; - static constexpr uint32_t Exti = Ahb; - static constexpr uint32_t Rcc = Ahb; - static constexpr uint32_t Dmamux = Ahb; - static constexpr uint32_t Dma = Ahb; - - static constexpr uint32_t Dbg = Apb; - static constexpr uint32_t Timer17 = Apb; - static constexpr uint32_t Timer16 = Apb; - static constexpr uint32_t Timer15 = Apb; - static constexpr uint32_t Usart1 = Apb; - static constexpr uint32_t Spi1 = Apb; - static constexpr uint32_t I2s1 = Apb; - static constexpr uint32_t Timer1 = Apb; - static constexpr uint32_t Adc1 = Apb; - static constexpr uint32_t ItLine = Apb; - static constexpr uint32_t SysCfg = Apb; - static constexpr uint32_t Tamp = Apb; - static constexpr uint32_t Bkp = Apb; - static constexpr uint32_t Ucpd2 = Apb; - static constexpr uint32_t Ucpd1 = Apb; - static constexpr uint32_t Dac = Apb; - static constexpr uint32_t Pwr = Apb; - static constexpr uint32_t I2c2 = Apb; - static constexpr uint32_t I2c1 = Apb; - static constexpr uint32_t Usart4 = Apb; - static constexpr uint32_t Usart3 = Apb; - static constexpr uint32_t Usart2 = Apb; - static constexpr uint32_t Spi2 = Apb; - static constexpr uint32_t Iwdg = Apb; - static constexpr uint32_t Wwdg = Apb; - static constexpr uint32_t Rtc = Apb; - static constexpr uint32_t Timer14 = Apb; - static constexpr uint32_t Timer7 = Apb; - static constexpr uint32_t Timer6 = Apb; - static constexpr uint32_t Timer3 = Apb; - - static bool inline - enable() - { - Rcc::enableInternalClock(); // 16MHz - // (internal clock / 1_M) * 8_N / 2_R = 128MHz / 2 = 64MHz - const Rcc::PllFactors pllFactors{ - .pllM = 1, - .pllN = 8, - .pllR = 2, - }; - Rcc::enablePll(Rcc::PllSource::InternalClock, pllFactors); - Rcc::setFlashLatency(); - // switch system clock to PLL output - Rcc::enableSystemClock(Rcc::SystemClockSource::Pll); - Rcc::setAhbPrescaler(Rcc::AhbPrescaler::Div1); - Rcc::setApbPrescaler(Rcc::ApbPrescaler::Div1); - // update frequencies for busy-wait delay functions - Rcc::updateCoreFrequency(); - - return true; - } -}; - -// Arduino Footprint -using A0 = GpioA0; -using A1 = GpioA1; -using A2 = GpioA4; -using A3 = GpioB1; -using A4 = GpioB11; -using A5 = GpioB12; - -using D0 = GpioC5; -using D1 = GpioC4; -using D2 = GpioA10; -using D3 = GpioB3; -using D4 = GpioB5; -using D5 = GpioB4; -using D6 = GpioB14; -using D7 = GpioA8; -using D8 = GpioA9; -using D9 = GpioC7; -using D10 = GpioB0; -using D11 = GpioA7; -using D12 = GpioA6; -using D13 = GpioA5; -using D14 = GpioB9; -using D15 = GpioB8; - -using Button = GpioInverted; -using LedD13 = D13; - -using Leds = SoftwareGpioPort< LedD13 >; -/// @} - -namespace stlink -{ -/// @ingroup modm_board_nucleo_g070rb -/// @{ -using Rx = GpioInputA3; -using Tx = GpioOutputA2; -using Uart = Usart2; -/// @} -} - -/// @ingroup modm_board_nucleo_g070rb -/// @{ -using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >; - -inline void -initialize() -{ - SystemClock::enable(); - SysTickTimer::initialize(); - - stlink::Uart::connect(); - stlink::Uart::initialize(); - - Button::setInput(); -} -/// @} - -} - -#endif // MODM_STM32_NUCLEO_G070RB_HPP diff --git a/src/modm/board/nucleo_g070rb/module.lb b/src/modm/board/nucleo_g070rb/module.lb index 148f459ada..147168f08b 100644 --- a/src/modm/board/nucleo_g070rb/module.lb +++ b/src/modm/board/nucleo_g070rb/module.lb @@ -34,7 +34,7 @@ def build(env): "with_assert": env.has_module(":architecture:assert") } env.template("../board.cpp.in", "board.cpp") - env.copy('.') + env.copy("../nucleo_g071rb/board.hpp", "board.hpp") env.outbasepath = "modm/openocd/modm/board/" env.copy(repopath("tools/openocd/modm/st_nucleo_g0.cfg"), "st_nucleo_g0.cfg") diff --git a/src/modm/board/nucleo_g071rb/board.hpp b/src/modm/board/nucleo_g071rb/board.hpp index c803d7227c..59c91861ca 100644 --- a/src/modm/board/nucleo_g071rb/board.hpp +++ b/src/modm/board/nucleo_g071rb/board.hpp @@ -14,14 +14,14 @@ #include #include #include -/// @ingroup modm_board_nucleo_g071rb +/// @ingroup modm_board_nucleo_g071rb modm_board_nucleo_g070rb #define MODM_BOARD_HAS_LOGGER using namespace modm::platform; namespace Board { -/// @ingroup modm_board_nucleo_g071rb +/// @ingroup modm_board_nucleo_g071rb modm_board_nucleo_g070rb /// @{ using namespace modm::literals; @@ -70,7 +70,7 @@ struct SystemClock static constexpr uint32_t Usart3 = Apb; static constexpr uint32_t Usart2 = Apb; static constexpr uint32_t Spi2 = Apb; - static constexpr uint32_t Iwdg = Apb; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static constexpr uint32_t Wwdg = Apb; static constexpr uint32_t Rtc = Apb; static constexpr uint32_t Timer14 = Apb; @@ -135,7 +135,7 @@ using Leds = SoftwareGpioPort< LedD13 >; namespace stlink { -/// @ingroup modm_board_nucleo_g071rb +/// @ingroup modm_board_nucleo_g071rb modm_board_nucleo_g070rb /// @{ using Rx = GpioInputA3; using Tx = GpioOutputA2; @@ -143,7 +143,7 @@ using Uart = Usart2; /// @} } -/// @ingroup modm_board_nucleo_g071rb +/// @ingroup modm_board_nucleo_g071rb modm_board_nucleo_g070rb /// @{ using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >; diff --git a/src/modm/board/nucleo_g431kb/board.hpp b/src/modm/board/nucleo_g431kb/board.hpp index b04e75bcf1..0b6b999c4d 100644 --- a/src/modm/board/nucleo_g431kb/board.hpp +++ b/src/modm/board/nucleo_g431kb/board.hpp @@ -84,6 +84,7 @@ struct SystemClock static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; static constexpr uint32_t Timer20 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_g431rb/board.hpp b/src/modm/board/nucleo_g431rb/board.hpp index fafd17fee7..de04fe9c12 100644 --- a/src/modm/board/nucleo_g431rb/board.hpp +++ b/src/modm/board/nucleo_g431rb/board.hpp @@ -79,6 +79,7 @@ struct SystemClock static constexpr uint32_t Timer15 = Apb2Timer; static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_g474re/board.hpp b/src/modm/board/nucleo_g474re/board.hpp index 870a8c178e..29d9ec86a5 100644 --- a/src/modm/board/nucleo_g474re/board.hpp +++ b/src/modm/board/nucleo_g474re/board.hpp @@ -92,6 +92,7 @@ struct SystemClock static constexpr uint32_t Timer16 = Apb2Timer; static constexpr uint32_t Timer17 = Apb2Timer; static constexpr uint32_t Timer20 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_h723zg/board.hpp b/src/modm/board/nucleo_h723zg/board.hpp index 2b28ff010a..eb974e48cd 100644 --- a/src/modm/board/nucleo_h723zg/board.hpp +++ b/src/modm/board/nucleo_h723zg/board.hpp @@ -103,6 +103,7 @@ struct SystemClock static constexpr uint32_t Timer24 = Apb1Timer; static constexpr uint32_t Usb = 48_MHz; // From PLL3Q + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_h743zi/board.hpp b/src/modm/board/nucleo_h743zi/board.hpp index 9127839453..7847157a3c 100644 --- a/src/modm/board/nucleo_h743zi/board.hpp +++ b/src/modm/board/nucleo_h743zi/board.hpp @@ -96,6 +96,7 @@ struct SystemClock static constexpr uint32_t Timer17 = Apb2Timer; static constexpr uint32_t Usb = 48_MHz; // From PLL3Q + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l031k6/board.hpp b/src/modm/board/nucleo_l031k6/board.hpp index 0de709fb16..ce88228d8c 100644 --- a/src/modm/board/nucleo_l031k6/board.hpp +++ b/src/modm/board/nucleo_l031k6/board.hpp @@ -53,6 +53,7 @@ struct SystemClock static constexpr uint32_t Timer22 = Apb2Timer; static constexpr uint32_t Usart2 = Apb1; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l053r8/board.hpp b/src/modm/board/nucleo_l053r8/board.hpp index 27860ada47..ba8ca0d7c3 100644 --- a/src/modm/board/nucleo_l053r8/board.hpp +++ b/src/modm/board/nucleo_l053r8/board.hpp @@ -59,6 +59,7 @@ struct SystemClock static constexpr uint32_t Timer6 = Apb1Timer; static constexpr uint32_t Timer21 = Apb2Timer; static constexpr uint32_t Timer22 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l152re/board.hpp b/src/modm/board/nucleo_l152re/board.hpp index 8b89f6ee11..a33e6079e6 100644 --- a/src/modm/board/nucleo_l152re/board.hpp +++ b/src/modm/board/nucleo_l152re/board.hpp @@ -60,6 +60,7 @@ struct SystemClock static constexpr uint32_t Timer9 = Apb2Timer; static constexpr uint32_t Timer10 = Apb2Timer; static constexpr uint32_t Timer11 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l432kc/board.hpp b/src/modm/board/nucleo_l432kc/board.hpp index 87b3d860bb..3627d45d9b 100644 --- a/src/modm/board/nucleo_l432kc/board.hpp +++ b/src/modm/board/nucleo_l432kc/board.hpp @@ -43,6 +43,7 @@ struct SystemClock static constexpr uint32_t Spi1 = Apb2; static constexpr uint32_t Spi2 = Apb2; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l452re/board.hpp b/src/modm/board/nucleo_l452re/board.hpp index 27426c24e1..5b8d38e020 100644 --- a/src/modm/board/nucleo_l452re/board.hpp +++ b/src/modm/board/nucleo_l452re/board.hpp @@ -73,6 +73,7 @@ struct SystemClock static constexpr uint32_t Usart3 = Apb1; static constexpr uint32_t Usb = Apb1; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l476rg/board.hpp b/src/modm/board/nucleo_l476rg/board.hpp index a43fb0bcbc..2d887a5753 100644 --- a/src/modm/board/nucleo_l476rg/board.hpp +++ b/src/modm/board/nucleo_l476rg/board.hpp @@ -53,6 +53,7 @@ struct SystemClock static constexpr uint32_t Usart3 = Apb1; static constexpr uint32_t Usart4 = Apb1; static constexpr uint32_t Usart5 = Apb1; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l496zg-p/board.hpp b/src/modm/board/nucleo_l496zg-p/board.hpp index 0554d9c332..c0974a885a 100644 --- a/src/modm/board/nucleo_l496zg-p/board.hpp +++ b/src/modm/board/nucleo_l496zg-p/board.hpp @@ -81,6 +81,7 @@ struct SystemClock static constexpr uint32_t Usb = 48_MHz; static constexpr uint32_t Rng = 48_MHz; static constexpr uint32_t Sdmmc = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_l552ze-q/board.hpp b/src/modm/board/nucleo_l552ze-q/board.hpp index 6232761fd8..4b391492fa 100644 --- a/src/modm/board/nucleo_l552ze-q/board.hpp +++ b/src/modm/board/nucleo_l552ze-q/board.hpp @@ -82,6 +82,7 @@ struct SystemClock static constexpr uint32_t Usb = 48_MHz; static constexpr uint32_t Rng = 48_MHz; static constexpr uint32_t Sdmmc = 48_MHz; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/nucleo_u575zi-q/board.hpp b/src/modm/board/nucleo_u575zi-q/board.hpp index fbfd54c93a..2b4efeb31d 100644 --- a/src/modm/board/nucleo_u575zi-q/board.hpp +++ b/src/modm/board/nucleo_u575zi-q/board.hpp @@ -84,6 +84,7 @@ struct SystemClock static constexpr uint32_t Usb = Hsi48; static constexpr uint32_t Rng = Hsi48; static constexpr uint32_t Sdmmc = Pll1P; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/olimexino_stm32/board.hpp b/src/modm/board/olimexino_stm32/board.hpp index 4ce0cf8ed4..94a3d1a47f 100644 --- a/src/modm/board/olimexino_stm32/board.hpp +++ b/src/modm/board/olimexino_stm32/board.hpp @@ -62,6 +62,7 @@ struct SystemClock static constexpr uint32_t Timer6 = Apb1Timer; static constexpr uint32_t Timer7 = Apb1Timer; static constexpr uint32_t Timer8 = Apb2Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/stm32_f4ve/board.hpp b/src/modm/board/stm32_f4ve/board.hpp index 076b7e053d..12d99a479e 100644 --- a/src/modm/board/stm32_f4ve/board.hpp +++ b/src/modm/board/stm32_f4ve/board.hpp @@ -79,6 +79,7 @@ struct SystemClock static constexpr uint32_t Timer12 = Apb1Timer; static constexpr uint32_t Timer13 = Apb1Timer; static constexpr uint32_t Timer14 = Apb1Timer; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/board/stm32f030f4p6_demo/board.hpp b/src/modm/board/stm32f030f4p6_demo/board.hpp index 21c37300fa..e4c129201c 100644 --- a/src/modm/board/stm32f030f4p6_demo/board.hpp +++ b/src/modm/board/stm32f030f4p6_demo/board.hpp @@ -47,6 +47,7 @@ struct SystemClock static constexpr uint32_t Timer14 = Apb; static constexpr uint32_t Timer16 = Apb; static constexpr uint32_t Timer17 = Apb; + static constexpr uint32_t Iwdg = Rcc::LsiFrequency; static bool inline enable() diff --git a/src/modm/math/algorithm/enumerate.hpp b/src/modm/math/algorithm/enumerate.hpp index 883ef1884d..39c27c5d8b 100644 --- a/src/modm/math/algorithm/enumerate.hpp +++ b/src/modm/math/algorithm/enumerate.hpp @@ -12,8 +12,10 @@ #pragma once -#include +#include +#include #include +#include namespace modm { @@ -31,7 +33,10 @@ constexpr auto enumerate(T && iterable) TIter iter; constexpr bool operator != (const iterator & other) const { return iter != other.iter; } constexpr void operator ++ () { ++i; ++iter; } - constexpr auto operator * () const { return std::tie(i, *iter); } + constexpr auto operator * () const + { + return std::tuple>{i, *iter}; + } }; struct iterable_wrapper { diff --git a/src/modm/math/algorithm/module.lb b/src/modm/math/algorithm/module.lb index 5e4b1b51d2..401d562a15 100644 --- a/src/modm/math/algorithm/module.lb +++ b/src/modm/math/algorithm/module.lb @@ -13,7 +13,7 @@ def init(module): module.name = ":math:algorithm" - module.description = "Math Algorithms" + module.description = FileReader("module.md") def prepare(module, options): module.depends(":math:units") diff --git a/src/modm/math/algorithm/module.md b/src/modm/math/algorithm/module.md new file mode 100644 index 0000000000..98809a438d --- /dev/null +++ b/src/modm/math/algorithm/module.md @@ -0,0 +1,196 @@ +# Algorithms + +A collection of useful and lightweight algorithms. + + +## Convenience Iterators + +Inspired by Python's built-in `range` and `enumerate` functions, you can use +`modm::range` and `modm::enumerate` in for loops: + +```cpp +// Iterates over 0 .. 9 +for (auto i : modm::range(10)) { + MODM_LOG_INFO << i << modm::endl; +} +// Iterates over 10 .. 19 +for (auto i : modm::range(10, 20)) { + MODM_LOG_INFO << i << modm::endl; +} +// Iterates over 20, 22, 24, 26, 28 +for (auto i : modm::range(20, 30, 2)) { + MODM_LOG_INFO << i << modm::endl; +} + +// Iterates over 0 .. N-1, where N = size of iterable +for (auto [i, item] : modm::enumerate(iterable)) { + MODM_LOG_INFO << i << item << modm::endl; +} +``` + + +## Prescaler Calculators + +Peripheral output frequencies are usually generated by dividing an input clock +with a prescaler in hardware. Finding the closest prescaler value for a desired +output frequency can be unintuitive, therefore, these classes provide a simple +interface for a constexpr calculator. + +All calculators return a `Result` struct containing desired, input, and output +frequencies, the relative error of the output vs desired frequency, and the +prescaler and its index. The prescaler index is typically the value to write +to the register directly: + +```cpp +// 16-bit linear prescaler [1, 2^16] mapped as [0, 0xffff]. +constexpr auto result = Prescaler::from_linear(10_MHz, 1_kHz, 1, 1ul << 16); +static_assert(result.input_frequency == 10_MHz); +static_assert(result.desired_frequency == 1_kHz); +// Calculator finds an exact match without error +static_assert(result.frequency == 1_kHz); +static_assert(result.error == 0); +// with prescaler 1e4 = 1e7 / 1e3. +static_assert(result.prescaler == 10'000); +static_assert(result.index == 9'999); +PERIPHERAL->PRESCALER = result.index; +``` + +The index is particularly useful for non-contiguous prescalers, the most common +being power-of-two values: + +```cpp +// Power-of-two prescaler with 8 values between [16, 4096]. +constexpr auto result = Prescaler::from_power(32_kHz, 100_Hz, 1ul << 4, 1ul << 12); +// Calculator cannot find an exact match! Closest has -25% error! +static_assert(result.frequency == 125_Hz); +static_assert(result.error == -0.25); +// Ideal Prescaler is 320, clostest is 256 +static_assert(result.prescaler == 256); +// Index is 256 = 1ul << (4 + 4) +static_assert(result.index == 4); +``` + +Non-contiguous prescalers can also be created with a modifier function: + +```cpp +// Only even prescalers from [2, 1024] +constexpr auto result = Prescaler::from_function( + 110_MHz, 3.5_MHz, 1, 512, [](uint32_t i){ return i*2; }); +// Ideal prescaler is 31.4, closest is 32 with ~2% error. +static_assert(result.frequency == 3.4375_MHz); +static_assert(result.error == 0.02); +static_assert(result.prescaler == 32); +static_assert(result.index == 15); // 32/2 - 1 +``` + +For all other cases, prescalers can be passed as an initializer list or as any +forward range. Note that the prescaler values *must* be sorted, otherwise +the calculator will compute the wrong prescaler values! + +```cpp +constexpr auto result = Prescaler::from_list(1_MHz, 1_kHz, {2,4,16,256,1024}); +constexpr auto result = Prescaler::from_range(2_kHz, 1_kHz, std::array{1,2,3}); +``` + +A special case is made of two chained prescalers that are both linear +powers-of-two. These are often called "fractional prescalers" and act as a +single binary-scaled linear prescaler and can thus be modeled as such: + +```cpp +// A fractional 12.4-bit prescaler can be modeled as a single 16-bit prescaler. +constexpr auto result = Prescaler::from_linear(SystemClock::Usart1, 115200, 16, 1ul << 16); +// The resulting prescaler can be written directly to the register. +USART1->BRR = result.prescaler; +``` + + +### Prescalers with Counters + +However, often chained prescalers cannot be converted to a linear prescaler, for +example, a timer with a set of power-of-two prescalers and a 16 or 32-bit +counter. These must be computed with a different class: + +```cpp +// A prescaler with power-of-two values [4, 256] going into a 12-bit down counter. +constexpr auto result = PrescalerCounter::from_power(32_kHz, 1_Hz, 1ul << 12, 4, 256); +// Calculator finds an exact match without error +static_assert(result.frequency == 1_Hz); +static_assert(result.error == 0); +// with prescaler 8 and counter 4'000. +static_assert(result.prescaler == 8); +static_assert(result.counter == 4'000); +static_assert(result.index == 1); +``` + +The calculator only picks the first prescaler with the lowest error, however, +in this example, there can be multiple exact solutions: + + 32000 = 8 × 4000 = 16 × 2000 = ... = 128 × 250 = 256 × 125 + +If the prescaler and counter is used to generate a waveform like PWM, then it is +beneficial to pick the combination with the largest counter value. However, if +the use case is to preserve power, then a slow running counter requires the +highest prescaler. Therefore the order of prescalers can be reversed: + +```cpp +constexpr auto result = PrescalerCounter::from_power(32_kHz, 1_Hz, 1ul << 12, 256, 4); +static_assert(result.prescaler == 256); +static_assert(result.counter == 125); +// Index is not the same! +static_assert(result.index == 0); +``` + +The same applies to the `PrescalerCounter::from_linear()` and +`PrescalerCounter::from_function()` calculators, while the order for lists and +forward ranges can be entirely arbitrary: + +```cpp +constexpr auto result = PrescalerCounter::from_list(32_kHz, 1_Hz, 1ul << 12, {128,16,256,4}); +static_assert(result.prescaler == 128); +static_assert(result.counter == 250); +// Index is relative to the list order now! +static_assert(result.index == 0); +``` + +!!! tip "Time Durations" + While the calculator is designed for frequencies, time durations can also be + computed by transforming the input as `frequency = 1.0 / duration` and then + transforming the output back as `duration = 1.0 / frequency`. + +!!! success "Floating-Point Frequencies" + You can define the type used for frequency representation by using the + `GenericPrescaler` and `GenericPrescalerCounter` classes. + + +### Tolerance of Prescaler Error + +Each `Result` has a signed(!), relative error attached, which can be used to +assert on the quality of the calculation. Note that using `static_assert` on the +error directly will only print the error values: + +```cpp +static_assert(std::abs(result.error) < 5_pct); +``` +``` +error: static assertion failed + | static_assert(std::abs(result.error) < tolerance); + | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~ +note: the comparison reduces to '(0.10 < 0.05)' +``` + +However, by using a helper method, the requested and closest available +frequencies can be displayed to the developer: + +```cpp +// Accidentally used kBaud instead of Baud, which cannot be generated +constexpr auto result = Prescaler::from_linear(SystemClock::Usart2, 115200_kBd, 16, 1ul << 16); +modm::assertBaudrateInTolerance(); +``` +``` +In instantiation of 'static void modm::PeripheralDriver::assertBaudrateInTolerance() +[with long long unsigned int available = 3000000; long long unsigned int requested = 115200000; float tolerance = 0.01f]': +error: static assertion failed: The closest available baudrate exceeds the tolerance of the requested baudrate! + | static_assert(modm::isValueInTolerance(requested, available, tolerance), + | ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +note: 'modm::isValueInTolerance(115200000, 3000000, 0.01f)' evaluates to false +``` diff --git a/src/modm/math/algorithm/prescaler.hpp b/src/modm/math/algorithm/prescaler.hpp index 502d2d7f25..4d8ca958e7 100644 --- a/src/modm/math/algorithm/prescaler.hpp +++ b/src/modm/math/algorithm/prescaler.hpp @@ -15,10 +15,8 @@ #include #include -#include -#include #include -#include +#include namespace modm { @@ -29,50 +27,49 @@ namespace modm * @note For ranges the end is *inclusive*: [begin, end]! * @ingroup modm_math_algorithm */ -template +template class GenericPrescaler { public: struct Result { - constexpr Result(T input_frequency, - T desired_frequency, - uint32_t index, uint32_t prescaler) : + constexpr Result(T input_frequency, T desired_frequency, + uint32_t index, uint32_t prescaler) : index{index}, prescaler{prescaler}, frequency{input_frequency / prescaler}, input_frequency{input_frequency}, desired_frequency{desired_frequency}, - error{1.f - float(input_frequency / prescaler) / desired_frequency} + error{1.f - float(input_frequency) / float(prescaler * desired_frequency)} {} /// Zero-indexed prescaler result - const uint32_t index; + uint32_t index; /// Prescaler value - const uint32_t prescaler; + uint32_t prescaler; /// Generated frequency - const T frequency; + T frequency; /// Input frequency - const T input_frequency; + T input_frequency; /// Desired Frequency - const T desired_frequency; + T desired_frequency; /// Relative Frequency Error - const float error; + float error; }; public: - /// From any iterable container. - /// @note container must have `begin()`, `end()` and `size()` function! - template + /// From any forward range. + /// @pre The container must be sorted from low to high numbers! static constexpr Result - from_iterator(T input_frequency, - T desired_frequency, - Iterator prescalers) + from_range(T input_frequency, T desired_frequency, + std::ranges::forward_range auto&& prescalers) { const double desired = double(input_frequency) / desired_frequency; - uint32_t prescaler_floor{*prescalers.begin()}; - uint32_t prescaler_ceiling{*prescalers.begin()}; + const size_t prescaler_size = std::ranges::distance( + std::ranges::begin(prescalers), std::ranges::end(prescalers)); + uint32_t prescaler_floor{*std::ranges::begin(prescalers)}; + uint32_t prescaler_ceiling{*std::ranges::begin(prescalers)}; uint32_t ii_floor{0}, ii_ceiling{0}; - if (desired <= prescaler_floor or prescalers.size() == 1) + if (desired <= prescaler_floor or prescaler_size == 1) return {input_frequency, desired_frequency, 0, prescaler_floor}; for (uint32_t prescaler : prescalers) { @@ -91,54 +88,62 @@ GenericPrescaler } /// From a initializer list. + /// @pre The list must be sorted from low to high numbers! static constexpr Result - from_list(T input_frequency, - T desired_frequency, + from_list(T input_frequency, T desired_frequency, std::initializer_list prescalers) { - return from_iterator(input_frequency, desired_frequency, prescalers); + return from_range(input_frequency, desired_frequency, prescalers); } /// From any linear range via modifier function. /// @note the range end is *inclusive*: [begin, end]. + /// @pre begin must be smaller or equal than end! template< typename Function > static constexpr Result - from_function(T input_frequency, - T desired_frequency, - uint32_t begin, uint32_t end, - Function prescaler_modifier) + from_function(T input_frequency, T desired_frequency, + uint32_t begin, uint32_t end, Function prescaler_modifier) { struct linear_range_iterator { + using iterator_category [[maybe_unused]] = std::forward_iterator_tag; + using value_type [[maybe_unused]] = uint32_t; + using difference_type [[maybe_unused]] = int32_t; + using pointer [[maybe_unused]] = value_type*; + using reference [[maybe_unused]] = value_type&; + uint32_t state; - const Function modifier; - constexpr uint32_t operator*() const { return modifier(state); } + Function *modifier; + + constexpr value_type operator*() const { return (*modifier)(state); } constexpr linear_range_iterator& operator++() { state++; return *this; } - constexpr bool operator!=(const linear_range_iterator &o) const { return state != o.state; } + constexpr linear_range_iterator operator++(int) { auto old(*this); ++*this; return old; } + constexpr bool operator==(const linear_range_iterator &o) const { return state == o.state; } + constexpr difference_type operator-(const linear_range_iterator &o) const { return state - o.state; } }; struct linear_range { - const uint32_t m_begin; - const uint32_t m_end; - const Function modifier; - constexpr linear_range_iterator begin() const { return linear_range_iterator{m_begin, modifier}; } - constexpr linear_range_iterator end() const { return linear_range_iterator{m_end, modifier}; } + uint32_t m_begin; + uint32_t m_end; + Function *modifier; + + constexpr linear_range_iterator begin() const { return {m_begin, modifier}; } + constexpr linear_range_iterator end() const { return {m_end, modifier}; } constexpr size_t size() const { return m_end - m_begin; } }; - linear_range range{begin, end+1, prescaler_modifier}; - return from_iterator(input_frequency, desired_frequency, range); + linear_range range{begin, end+1, &prescaler_modifier}; + return from_range(input_frequency, desired_frequency, range); } /// From any linear range. /// @note the range end is *inclusive*: [begin, end]. + /// @pre begin must be smaller or equal than end! static constexpr Result - from_range(T input_frequency, - T desired_frequency, - uint32_t begin, uint32_t end) + from_linear(T input_frequency, T desired_frequency, uint32_t begin, uint32_t end) { const double desired = double(input_frequency) / desired_frequency; - const uint32_t prescaler_floor = std::max(uint32_t(std::floor(desired)), begin); - const uint32_t prescaler_ceiling = std::min(uint32_t(std::ceil(desired)), end); + const uint32_t prescaler_floor = std::max(uint32_t(desired), begin); + const uint32_t prescaler_ceiling = std::min(uint32_t(desired) + 1, end); const T baud_lower = input_frequency / prescaler_ceiling; const T baud_upper = input_frequency / prescaler_floor; const double baud_middle = (baud_upper + baud_lower) / 2.0; @@ -149,12 +154,10 @@ GenericPrescaler /// From any 2-logarithmic range. /// @note the range end is *inclusive*: [begin, end]. - /// @param begin must be a power-of-two! - /// @param end must be a power-of-two! + /// @pre `begin` and `end` must be powers of two! + /// @pre `begin` must be smaller or equal than `end`! static constexpr Result - from_power(T input_frequency, - T desired_frequency, - uint32_t begin, uint32_t end) + from_power(T input_frequency, T desired_frequency, uint32_t begin, uint32_t end) { const double desired = double(input_frequency) / desired_frequency; uint32_t ii{0}; uint32_t power{begin}; diff --git a/src/modm/math/algorithm/prescaler_counter.hpp b/src/modm/math/algorithm/prescaler_counter.hpp new file mode 100644 index 0000000000..aa11407f56 --- /dev/null +++ b/src/modm/math/algorithm/prescaler_counter.hpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2024, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#include +#include +#include +#include +#include "enumerate.hpp" + +namespace modm +{ + +/** + * Computes the best fitting prescaler and counter value from a list. + * + * @note For ranges the end is *inclusive*: [begin, end]! + * @ingroup modm_math_algorithm + */ +template +class +GenericPrescalerCounter +{ +public: + struct Result + { + constexpr Result(T input_frequency, T desired_frequency, + uint32_t index, uint32_t prescaler, uint32_t counter) : + index{index}, prescaler{prescaler}, counter{counter}, + frequency{input_frequency / (prescaler * counter)}, + input_frequency{input_frequency}, + desired_frequency{desired_frequency}, + error{1.f - float(input_frequency) / float(prescaler * counter * desired_frequency)} + {} + /// Zero-indexed prescaler result + uint32_t index; + /// Prescaler value + uint32_t prescaler; + /// Counter value + uint32_t counter; + /// Generated frequency + T frequency; + /// Input frequency + T input_frequency; + /// Desired Frequency + T desired_frequency; + /// Relative Frequency Error + float error; + }; + +public: + /// From any forward range. + static constexpr Result + from_range(T input_frequency, T desired_frequency, uint32_t max_counter, + std::ranges::forward_range auto&& prescalers) + { + const double desired = double(input_frequency) / desired_frequency; + const auto [min, max] = std::ranges::minmax_element(prescalers); + // clamp to lowest frequency + if (desired < (*min * 1)) { + return {input_frequency, desired_frequency, + uint32_t(std::distance(std::ranges::begin(prescalers), min)), + *min, 1}; + } + // clamp to highest frequency + if (desired > (*max * max_counter)) { + return {input_frequency, desired_frequency, + uint32_t(std::distance(std::ranges::begin(prescalers), max)), + *max, max_counter}; + } + + uint32_t out_prescaler{0}, out_index{0}, out_counter{0}; + double out_error{std::numeric_limits::infinity()}; + auto fn_compare = [&](uint32_t idx, uint32_t pre, uint32_t cnt) + { + const double err = std::abs(desired - pre * cnt); + if (err < out_error) { + out_error = err; + out_prescaler = pre; + out_counter = cnt; + out_index = idx; + } + }; + for (const auto&& [idx, prescaler] : enumerate(prescalers)) + { + if (max_counter * prescaler < desired) continue; + const auto cnt = std::max(1, desired / prescaler); + fn_compare(idx, prescaler, cnt); + if (cnt > max_counter - 1) continue; + fn_compare(idx, prescaler, cnt + 1); + } + return {input_frequency, desired_frequency, out_index, out_prescaler, out_counter}; + } + + /// From a initializer list. + static constexpr Result + from_list(T input_frequency, T desired_frequency, uint32_t max_counter, + std::initializer_list prescalers) + { + return from_range(input_frequency, desired_frequency, max_counter, prescalers); + } + + /// From any linear range via modifier function. + /// @note the range end is *inclusive*: [begin, end]. + template< typename Function > + static constexpr Result + from_function(T input_frequency, T desired_frequency, uint32_t max_counter, + uint32_t begin, uint32_t end, Function prescaler_modifier) + { + struct linear_range_iterator + { + using iterator_category [[maybe_unused]] = std::forward_iterator_tag; + using value_type [[maybe_unused]] = uint32_t; + using difference_type [[maybe_unused]] = int32_t; + using pointer [[maybe_unused]] = value_type*; + using reference [[maybe_unused]] = value_type&; + + value_type state; + value_type value; + Function *modifier; + bool reversed; + + constexpr value_type operator*() const { return (*modifier)(value); } + constexpr linear_range_iterator& operator++() { state++; reversed ? value-- : value++; return *this; } + constexpr linear_range_iterator operator++(int) { auto old(*this); ++*this; return old; } + constexpr bool operator==(const linear_range_iterator &o) const { return state == o.state; } + constexpr difference_type operator-(const linear_range_iterator &o) const { return state - o.state; } + }; + struct linear_range + { + uint32_t m_begin; + uint32_t m_end; + Function *modifier; + bool reversed; + + constexpr linear_range_iterator begin() const + { return {m_begin, reversed ? m_end-1 : m_begin, modifier, reversed}; } + constexpr linear_range_iterator end() const + { return {m_end, reversed ? m_begin : m_end-1, modifier, reversed}; } + constexpr size_t size() const { return m_end - m_begin; } + }; + const bool reversed = begin > end; + if (reversed) std::swap(begin, end); + linear_range range{begin, end+1, &prescaler_modifier, reversed}; + return from_range(input_frequency, desired_frequency, max_counter, range); + } + + /// From any linear range. + /// @note the range end is *inclusive*: [begin, end]. + static constexpr Result + from_linear(T input_frequency, T desired_frequency, uint32_t max_counter, + uint32_t begin, uint32_t end) + { + return from_function(input_frequency, desired_frequency, max_counter, + begin, end, [](uint32_t ii) { return ii; }); + } + + /// From any 2-logarithmic range. + /// @note the range end is *inclusive*: [begin, end]. + /// @param begin must be a power-of-two! + /// @param end must be a power-of-two! + static constexpr Result + from_power(T input_frequency, T desired_frequency, uint32_t max_counter, + uint32_t begin, uint32_t end) + { + return from_function(input_frequency, desired_frequency, max_counter, + std::bit_width(begin - 1), std::bit_width(end - 1), + [](uint32_t ii) { return 1ul << ii; }); + } +}; + +using PrescalerCounter = GenericPrescalerCounter; + +} // namespace modm diff --git a/src/modm/math/tolerance.hpp b/src/modm/math/tolerance.hpp index f9a05fa5a0..d8f9d76b7a 100644 --- a/src/modm/math/tolerance.hpp +++ b/src/modm/math/tolerance.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2015, 2018, Niklas Hauser + * Copyright (c) 2013-2015, 2018, 2024, Niklas Hauser * * This file is part of the modm project. * @@ -9,60 +9,20 @@ */ // ---------------------------------------------------------------------------- -#ifndef MODM_MATH_TOLERANCE_HPP -#define MODM_MATH_TOLERANCE_HPP +#pragma once -#include #include +#include namespace modm { -/** - * This class checks if values are within a certain tolerance. - * - * This can be used to guarantee the quality of certain parameters, - * mostly baudrate or datarate. - * - * @ingroup modm_math - */ -class -Tolerance +/// @ingroup modm_math +template< typename T > +constexpr bool +isValueInTolerance(T reference, T actual, percent_t tolerance) { -public: - static constexpr int64_t - absoluteError(uint32_t reference, uint32_t actual) - { - return (int64_t(reference) - actual); - } - - static constexpr float - relativeError(uint32_t reference, uint32_t actual) - { - return (1.f - float(actual) / reference); - } - - static constexpr bool - isErrorInTolerance(float error, percent_t tolerance) - { - return (error == 0) or (((error > 0) ? error : -error) <= pct2f(tolerance)); - } - - static constexpr bool - isValueInTolerance(uint32_t reference, uint32_t actual, percent_t tolerance) - { - return isErrorInTolerance(relativeError(reference, actual), tolerance); - } - - template< uint32_t reference, uint32_t actual, percent_t tolerance > - static void - assertValueInTolerance() - { - static_assert(isValueInTolerance(reference, actual, tolerance), - "The actual value exceeds the tolerance of reference!"); - } -}; + return std::abs(1.0 - double(actual) / double(reference)) <= std::abs(double(tolerance)); +} } // namespace modm - -#endif // MODM_MATH_TOLERANCE_HPP diff --git a/src/modm/math/units.hpp b/src/modm/math/units.hpp index 564e4878a6..fc68df8c03 100644 --- a/src/modm/math/units.hpp +++ b/src/modm/math/units.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Niklas Hauser + * Copyright (c) 2019, 2024, Niklas Hauser * * This file is part of the modm project. * @@ -14,6 +14,7 @@ #include #include +#include #ifdef __DOXYGEN__ @@ -36,8 +37,12 @@ namespace modm template constexpr bitrate_t kbps(T value); template constexpr bitrate_t Mbps(T value); - using percent_t = uint16_t; + using percent_t = float; template constexpr percent_t pct(T value); + + using seconds_t = std::chrono::seconds; + using milliseconds_t = std::chrono::milliseconds; + using microseconds_t = std::chrono::microseconds; /// @} namespace literals @@ -63,8 +68,7 @@ namespace modm #else -#define MODM_LITERAL_DEFINITION(type, name, symbol) \ -namespace modm { \ +#define MODM_UNITS_LITERAL_DEFINITION(type, name, symbol) \ using MODM_CONCAT(name, _t) = type; \ template constexpr MODM_CONCAT(name, _t) symbol(T value) { return value; } \ template constexpr MODM_CONCAT(name, _t) MODM_CONCAT(k, symbol)(T value) { return value * 1'000ul; } \ @@ -75,21 +79,38 @@ namespace literals { \ constexpr MODM_CONCAT(name, _t) MODM_CONCAT(operator""_k, symbol)(long double value) { return MODM_CONCAT(k, symbol)(value); } \ constexpr MODM_CONCAT(name, _t) MODM_CONCAT(operator""_M, symbol)(unsigned long long int value) { return MODM_CONCAT(M, symbol)(value); } \ constexpr MODM_CONCAT(name, _t) MODM_CONCAT(operator""_M, symbol)(long double value) { return MODM_CONCAT(M, symbol)(value); } \ -}} +} + +#define MODM_UNITS_TIME_DEFINITION(type) \ +struct MODM_CONCAT(type, _t) { \ + template< class Rep, class Period > \ + constexpr MODM_CONCAT(type, _t)(std::chrono::duration duration) \ + : count_{std::chrono::duration_cast(duration).count()} {} \ + std::chrono::type::rep count_; \ + constexpr std::chrono::type::rep count() const { return count_; } \ +}; + +namespace modm +{ -MODM_LITERAL_DEFINITION(uint32_t, frequency, Hz) -MODM_LITERAL_DEFINITION(uint32_t, baudrate, Bd) -MODM_LITERAL_DEFINITION(uint32_t, bitrate, bps) +MODM_UNITS_LITERAL_DEFINITION(uint32_t, frequency, Hz) +MODM_UNITS_LITERAL_DEFINITION(uint32_t, baudrate, Bd) +MODM_UNITS_LITERAL_DEFINITION(uint32_t, bitrate, bps) -namespace modm { -enum class percent_t : uint16_t {}; -template constexpr percent_t pct(T value) { return percent_t(uint16_t(value * 600ul)); } -constexpr float pct2f(percent_t value) { return uint16_t(value) / 60'000.f; } +using percent_t = float; +template constexpr percent_t pct(T value) { return value / 100.f; } +// DEPRECATED: 2025q1 +modm_deprecated("Access the value directly.") constexpr float pct2f(percent_t value) { return value; } namespace literals { constexpr percent_t operator""_pct(long double value) { return pct(value); } constexpr percent_t operator""_pct(unsigned long long int value) { return pct(value); } } + +MODM_UNITS_TIME_DEFINITION(seconds) +MODM_UNITS_TIME_DEFINITION(milliseconds) +MODM_UNITS_TIME_DEFINITION(microseconds) + using namespace ::modm::literals; } diff --git a/src/modm/math/units.lb b/src/modm/math/units.lb index 12250bb851..35bae20e26 100644 --- a/src/modm/math/units.lb +++ b/src/modm/math/units.lb @@ -45,26 +45,39 @@ bitrate_t bitrate = modm::kbps(125); frequency = 4295_MHz; // OVERFLOW at 2^32 units! ``` -## Integral Percentages -Since `float` cannot be used as a non-type template argument, an integer type -for providing tolerances in `percent_t` is available. -Note that `percent_t` is implemented as an enum class, which prevents implicit -conversions, since the base for this is not 1. -You must therefore use the `modm::pct(T value)` or `_pct` constructors. +## Percentages + +Percentages are stored as normalized floating point numbers and can be converted +using these convenience constructors: ```cpp using namespace modm::literals; percent_t tolerance = modm::pct(10); tolerance = 10_pct; - -// convert back to float. *internal use only* -float percent = modm::pct2f(tolerance); + tolerance = 0.1f; ``` -!!! warning "This type is not guaranteed to hold more than 100 percent!" +## Time + +Simplified types allow passing `std::chrono::duration` values as template +parameters: + +```cpp +seconds_t duration = 10s; +milliseconds_t duration = 10ms; +microseconds_t duration = 10us; + +auto count = duration.count(); + +template< milliseconds_t period > +void setPeriod() +{ + auto seconds = 1000.0 / period.count(); +} +``` """ def prepare(module, options): diff --git a/src/modm/platform/can/common/can_bit_timings.hpp b/src/modm/platform/can/common/can_bit_timings.hpp index 57cfcc8dd7..247f6c9557 100644 --- a/src/modm/platform/can/common/can_bit_timings.hpp +++ b/src/modm/platform/can/common/can_bit_timings.hpp @@ -115,7 +115,7 @@ class CanBitTiming template static constexpr void assertBitrateInTolerance() { - static_assert(pct2f(tolerance) >= BestConfig.error, + static_assert(tolerance >= BestConfig.error, "The closest available bitrate exceeds the specified maximum tolerance!"); } diff --git a/src/modm/platform/clock/stm32/module.lb b/src/modm/platform/clock/stm32/module.lb index 65d5cd9024..ceda4c17db 100644 --- a/src/modm/platform/clock/stm32/module.lb +++ b/src/modm/platform/clock/stm32/module.lb @@ -36,26 +36,26 @@ def build(env): properties["core"] = core = device.get_driver("core")["type"] if target["family"] in ["f1", "f3"]: - properties["hsi_frequency"] = 8 - properties["lsi_frequency"] = 40 + properties["hsi_frequency"] = 8_000_000 + properties["lsi_frequency"] = 40_000 properties["boot_frequency"] = properties["hsi_frequency"] elif target["family"] in ["h7"]: - properties["hsi_frequency"] = 64 - properties["lsi_frequency"] = 32 + properties["hsi_frequency"] = 64_000_000 + properties["lsi_frequency"] = 32_000 properties["boot_frequency"] = properties["hsi_frequency"] elif target["family"] in ["l0", "l1"]: - properties["hsi_frequency"] = 16 - properties["lsi_frequency"] = 37 - properties["msi_frequency"] = 2.097 + properties["hsi_frequency"] = 16_000_000 + properties["lsi_frequency"] = 37_000 + properties["msi_frequency"] = 2_097_000 properties["boot_frequency"] = properties["msi_frequency"] elif target["family"] in ["l5"]: - properties["hsi_frequency"] = 16 - properties["lsi_frequency"] = 32 - properties["msi_frequency"] = 4 + properties["hsi_frequency"] = 16_000_000 + properties["lsi_frequency"] = 32_000 + properties["msi_frequency"] = 4_000_000 properties["boot_frequency"] = properties["msi_frequency"] else: - properties["hsi_frequency"] = 16 - properties["lsi_frequency"] = 32 + properties["hsi_frequency"] = 16_000_000 + properties["lsi_frequency"] = 32_000 properties["boot_frequency"] = properties["hsi_frequency"] # TODO: Move this data into the device files diff --git a/src/modm/platform/clock/stm32/rcc.hpp.in b/src/modm/platform/clock/stm32/rcc.hpp.in index a958d38f41..72a379e84a 100644 --- a/src/modm/platform/clock/stm32/rcc.hpp.in +++ b/src/modm/platform/clock/stm32/rcc.hpp.in @@ -39,7 +39,9 @@ namespace modm::platform class Rcc { public: - static constexpr uint32_t BootFrequency = {{ "{0:,}".format((1000000 * boot_frequency)|int).replace(',', "'") }}; + static constexpr uint32_t LsiFrequency = {{ lsi_frequency | modm.digsep }}; + static constexpr uint32_t HsiFrequency = {{ hsi_frequency | modm.digsep }}; + static constexpr uint32_t BootFrequency = {{ boot_frequency | modm.digsep }}; enum class PllSource : uint32_t diff --git a/src/modm/platform/clock/systick/systick_timer.hpp.in b/src/modm/platform/clock/systick/systick_timer.hpp.in index be3882cc40..c4fd39d7d3 100644 --- a/src/modm/platform/clock/systick/systick_timer.hpp.in +++ b/src/modm/platform/clock/systick/systick_timer.hpp.in @@ -43,7 +43,7 @@ public: if constexpr (SystemClock::Frequency < {{ref_clk}}'000'000) %% endif { - constexpr auto result = Prescaler::from_range( + constexpr auto result = Prescaler::from_linear( SystemClock::Frequency, {{ systick_frequency }}, 1, (1ul << 24)-1); PeripheralDriver::assertBaudrateInTolerance< result.frequency, {{ systick_frequency }}, tolerance >(); @@ -56,7 +56,7 @@ public: %% if ref_clk > 1 else { - constexpr auto result = Prescaler::from_range( + constexpr auto result = Prescaler::from_linear( SystemClock::Frequency/{{ref_clk}}, {{ systick_frequency }}, 1, (1ul << 24)-1); PeripheralDriver::assertBaudrateInTolerance< result.frequency, {{ systick_frequency }}, tolerance >(); diff --git a/src/modm/platform/i2c/sam_x7x/i2c_master.hpp.in b/src/modm/platform/i2c/sam_x7x/i2c_master.hpp.in index f62d0b34b0..1b881334de 100644 --- a/src/modm/platform/i2c/sam_x7x/i2c_master.hpp.in +++ b/src/modm/platform/i2c/sam_x7x/i2c_master.hpp.in @@ -61,7 +61,7 @@ private: const float freq = 1.f / (tHigh + tLow); const float error = std::fabs(1.f - freq / baudrate); - return error < pct2f(tolerance); + return error < tolerance; } template diff --git a/src/modm/platform/i2c/stm32-extended/i2c_timing_calculator.hpp b/src/modm/platform/i2c/stm32-extended/i2c_timing_calculator.hpp index c80cfd69a1..be9bac7870 100644 --- a/src/modm/platform/i2c/stm32-extended/i2c_timing_calculator.hpp +++ b/src/modm/platform/i2c/stm32-extended/i2c_timing_calculator.hpp @@ -97,7 +97,7 @@ class I2cTimingCalculator float speed = calculateSpeed(prescaler, sclLow, sclHigh); auto error = std::fabs((speed / params.targetSpeed) - 1.0f); // modm::Tolerance value is in unit [1/1000] - if ((error < pct2f(params.tolerance)) && (error <= lastError) && (prescaler <= bestPrescaler)) { + if ((error < params.tolerance) && (error <= lastError) && (prescaler <= bestPrescaler)) { lastError = error; bestPrescaler = prescaler; bestSclLow = sclLow; @@ -290,7 +290,7 @@ class I2cTimingCalculator auto clockPeriod = float(prescaler + 1) / params.peripheralClock; auto targetSclTime = 1.f / params.targetSpeed; - auto sclTimeMax = targetSclTime * (1.f + pct2f(params.tolerance)); + auto sclTimeMax = targetSclTime * (1.f + params.tolerance); auto maxSclSum = ((sclTimeMax - params.riseTime - params.fallTime - 2*SyncTime) / clockPeriod) - 2; diff --git a/src/modm/platform/i2c/stm32/i2c_master.hpp.in b/src/modm/platform/i2c/stm32/i2c_master.hpp.in index 7364509da5..06459aa04e 100644 --- a/src/modm/platform/i2c/stm32/i2c_master.hpp.in +++ b/src/modm/platform/i2c/stm32/i2c_master.hpp.in @@ -76,7 +76,7 @@ public: constexpr uint8_t scalar = (baudrate <= 100'000) ? 2 : ((baudrate <= 300'000) ? 3 : 25); constexpr uint16_t range_begin = (scalar == 2) ? 4 : 1; - constexpr auto result = Prescaler::from_range( + constexpr auto result = Prescaler::from_linear( SystemClock::I2c{{ id }} / scalar, baudrate, range_begin, 4095); assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); diff --git a/src/modm/platform/iwdg/stm32/iwdg.cpp b/src/modm/platform/iwdg/stm32/iwdg.cpp deleted file mode 100644 index 1147e7eec1..0000000000 --- a/src/modm/platform/iwdg/stm32/iwdg.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023, Zühlke Engineering (Austria) GmbH - * - * This file is part of the modm project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ -// ---------------------------------------------------------------------------- - -#include "iwdg.hpp" - -void -Iwdg::initialize(Iwdg::Prescaler prescaler, uint32_t reload) -{ - writeKey(writeCommand); - IWDG->PR = (IWDG->PR & ~static_cast(Iwdg::Prescaler::All)) | - static_cast(prescaler); - IWDG->RLR = (IWDG->RLR & ~IWDG_RLR_RL) | (reload << IWDG_RLR_RL_Pos); - writeKey(0); // disable access to PR and RLR registers -} - -void -Iwdg::enable() -{ - writeKey(enableCommand); -} - -void -Iwdg::trigger() -{ - writeKey(reloadCommand); -} - -void -Iwdg::writeKey(uint32_t key) -{ - IWDG->KR = (IWDG->KR & ~IWDG_KR_KEY_Msk) | ((key & IWDG_KR_KEY_Msk) << IWDG_KR_KEY_Pos); -} - -Iwdg::Status -Iwdg::getStatus() -{ - const auto status = IWDG->SR & (IWDG_SR_PVU | IWDG_SR_RVU); - return static_cast(status); -}; \ No newline at end of file diff --git a/src/modm/platform/iwdg/stm32/iwdg.hpp b/src/modm/platform/iwdg/stm32/iwdg.hpp index d81b2a1e48..26321b6c5a 100644 --- a/src/modm/platform/iwdg/stm32/iwdg.hpp +++ b/src/modm/platform/iwdg/stm32/iwdg.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Zühlke Engineering (Austria) GmbH + * Copyright (c) 2024, Niklas Hauser * * This file is part of the modm project. * @@ -10,13 +11,20 @@ // ---------------------------------------------------------------------------- #pragma once +#include +#include #include "../device.hpp" -class Iwdg + +namespace modm::platform +{ + +/// @ingroup modm_platform_iwdg +class Iwdg : public ::modm::PeripheralDriver { public: enum class - Prescaler : uint32_t + Prescaler : uint8_t { Div4 = 0, Div8 = IWDG_PR_PR_0, @@ -29,7 +37,7 @@ class Iwdg }; enum class - Status : uint32_t + Status : uint8_t { None = 0, Prescaler = IWDG_SR_PVU, @@ -37,20 +45,57 @@ class Iwdg All = IWDG_SR_PVU | IWDG_SR_RVU, }; +public: + template< class SystemClock, milliseconds_t timeout, percent_t tolerance=pct(1) > static void - initialize(Prescaler prescaler, uint32_t reload); - static void - enable(); - static void - trigger(); - static Status - getStatus(); + initialize() + { + constexpr double frequency = 1000.0 / timeout.count(); + constexpr auto result = modm::GenericPrescalerCounter::from_power( + SystemClock::Iwdg, frequency, 1ul << 12, 256, 4); + assertDurationInTolerance< 1.0 / result.frequency, 1.0 / frequency, tolerance >(); + + configure(Prescaler(result.index), result.counter - 1); + } + + + static inline void + enable() + { + writeKey(enableCommand); + } + + static inline void + trigger() + { + writeKey(reloadCommand); + } + + static inline Status + getStatus() + { + return Status(IWDG->SR); + } private: - static constexpr uint32_t reloadCommand = 0xAAAA; - static constexpr uint32_t writeCommand = 0x5555; - static constexpr uint32_t enableCommand = 0xCCCC; + static inline void + configure(Prescaler prescaler, uint16_t reload) + { + writeKey(writeCommand); + IWDG->PR = uint32_t(prescaler); + IWDG->RLR = reload; + writeKey(0); // disable access to PR and RLR registers + } - static void - writeKey(uint32_t key); -}; \ No newline at end of file + static inline void + writeKey(uint16_t key) + { + IWDG->KR = key; + } + + static constexpr uint16_t reloadCommand = 0xAAAA; + static constexpr uint16_t writeCommand = 0x5555; + static constexpr uint16_t enableCommand = 0xCCCC; +}; + +} diff --git a/src/modm/platform/iwdg/stm32/module.lb b/src/modm/platform/iwdg/stm32/module.lb index f1cc92ad69..98536a5b64 100644 --- a/src/modm/platform/iwdg/stm32/module.lb +++ b/src/modm/platform/iwdg/stm32/module.lb @@ -14,15 +14,17 @@ def init(module): module.name = ":platform:iwdg" module.description = "Independent watchdog" + def prepare(module, options): device = options[":target"] - target = device.identifier - if target["family"] in ["h7"]: - # STM32H7 is not yet supported with any IWDG implementation im modm + # STM32H7 is not yet supported with any IWDG implementation + if device.identifier.family in ["h7"]: return False + + module.depends(":cmsis:device", ":math:algorithm") return device.has_driver("iwdg:stm32") + def build(env): env.outbasepath = "modm/src/modm/platform/iwdg" env.copy("iwdg.hpp") - env.copy("iwdg.cpp") diff --git a/src/modm/platform/spi/rp/spi_master.hpp.in b/src/modm/platform/spi/rp/spi_master.hpp.in index e8676bc22b..054c843a5b 100644 --- a/src/modm/platform/spi/rp/spi_master.hpp.in +++ b/src/modm/platform/spi/rp/spi_master.hpp.in @@ -121,7 +121,7 @@ public: // Find largest post-divide which makes output closest to baudrate. Post-divide is // an integer in the range 1 to 256 inclusive. - constexpr uint32_t postdiv = Prescaler::from_range(freq_in / prescale, baudrate, 1, 256).prescaler; + constexpr uint32_t postdiv = Prescaler::from_linear(freq_in / prescale, baudrate, 1, 256).prescaler; constexpr uint32_t result_baudrate = freq_in / (prescale * postdiv); diff --git a/src/modm/platform/spi/sam/spi_master.hpp.in b/src/modm/platform/spi/sam/spi_master.hpp.in index ed5726dd46..a6f9ef804d 100644 --- a/src/modm/platform/spi/sam/spi_master.hpp.in +++ b/src/modm/platform/spi/sam/spi_master.hpp.in @@ -93,7 +93,7 @@ public: FLEXCOM{{ id }}->FLEXCOM_MR = FLEXCOM_MR_OPMODE_SPI; // Note: SPI peripheral supports operating from a programmable clock // output, but here we only use the main peripheral clock - constexpr auto result = modm::Prescaler::from_range(SystemClock::Frequency, baudrate, 2, 256); + constexpr auto result = modm::Prescaler::from_linear(SystemClock::Frequency, baudrate, 2, 256); assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); Regs()->SPI_CSR[0] = SPI_CSR_SCBR(result.prescaler); diff --git a/src/modm/platform/spi/sam_x7x/spi_master.hpp.in b/src/modm/platform/spi/sam_x7x/spi_master.hpp.in index 9f40cc092f..3cd2f1326a 100644 --- a/src/modm/platform/spi/sam_x7x/spi_master.hpp.in +++ b/src/modm/platform/spi/sam_x7x/spi_master.hpp.in @@ -74,7 +74,7 @@ public: static void initialize() { - constexpr auto result = modm::Prescaler::from_range(SystemClock::Spi{{ id }}, baudrate, 1, 255); + constexpr auto result = modm::Prescaler::from_linear(SystemClock::Spi{{ id }}, baudrate, 1, 255); assertBaudrateInTolerance(); SpiHal{{ id }}::initialize(result.prescaler); diff --git a/src/modm/platform/uart/at90_tiny_mega/uart.hpp.in b/src/modm/platform/uart/at90_tiny_mega/uart.hpp.in index fba51e803a..512e1d8697 100644 --- a/src/modm/platform/uart/at90_tiny_mega/uart.hpp.in +++ b/src/modm/platform/uart/at90_tiny_mega/uart.hpp.in @@ -67,7 +67,7 @@ public: { // use double speed when necessary constexpr uint32_t scalar = (baudrate * 16l > SystemClock::Uart) ? 8 : 16; - constexpr auto result = Prescaler::from_range( + constexpr auto result = Prescaler::from_linear( SystemClock::Uart / scalar, baudrate, 1, 4095); assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); constexpr uint16_t ubrr = result.index | ((scalar == 8) ? 0x8000 : 0); diff --git a/src/modm/platform/uart/rp/uart.hpp.in b/src/modm/platform/uart/rp/uart.hpp.in index f45085b7ef..ae22c1aa5f 100644 --- a/src/modm/platform/uart/rp/uart.hpp.in +++ b/src/modm/platform/uart/rp/uart.hpp.in @@ -112,7 +112,7 @@ public: // 16.6 fractional baudrate generator with 16x oversampling constexpr uint32_t min = (1ul << 7); constexpr uint32_t max = (1ul << 22) - 1ul; - constexpr auto result = Prescaler::from_range(SystemClock::PeriFrequency*4, baudrate, min, max); + constexpr auto result = Prescaler::from_linear(SystemClock::PeriFrequency*4, baudrate, min, max); modm::PeripheralDriver::assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); // Load PL011's baud divisor registers uart{{ id }}_hw->ibrd = result.prescaler >> 6; diff --git a/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in index 8947a40bee..629f5aee38 100644 --- a/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in +++ b/src/modm/platform/uart/sam-sercom/uart_hal_impl.hpp.in @@ -75,7 +75,7 @@ void constexpr uint32_t scalar = (baudrate * 16l > SystemClock::{{ sercom | capitalize }}) ? 8 : 16; {{ peripheral }}->USART.CTRLA.bit.SAMPR = (scalar == 16) ? 0x1 : 0x3; // Prescaler 13 bit integer, 3 bit fractional - constexpr auto result = Prescaler::from_range( + constexpr auto result = Prescaler::from_linear( SystemClock::{{ sercom | capitalize }}/(scalar/8), baudrate, 1, (1ul << 16) - 1ul); assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); {{ peripheral }}->USART.BAUD.FRAC.BAUD = result.prescaler >> 3; diff --git a/src/modm/platform/uart/stm32/uart_hal_impl.hpp.in b/src/modm/platform/uart/stm32/uart_hal_impl.hpp.in index f24d5e9a88..821b307356 100644 --- a/src/modm/platform/uart/stm32/uart_hal_impl.hpp.in +++ b/src/modm/platform/uart/stm32/uart_hal_impl.hpp.in @@ -70,20 +70,20 @@ void %% if over8 constexpr uint32_t scalar = (baudrate * 16 > SystemClock::{{ name }}) ? 8 : 16; constexpr uint32_t max = ((scalar == 16) ? (1ul << 16) : (1ul << 15)) - 1ul; - constexpr auto result = Prescaler::from_range(SystemClock::{{ name }}, baudrate, 1, max); + constexpr auto result = Prescaler::from_linear(SystemClock::{{ name }}, baudrate, scalar, max); %% elif uart_type == "Lpuart" static_assert(SystemClock::{{ name }} >= baudrate * 3, "fck must be in the range [3 x baud rate, 4096 x baud rate]."); static_assert(SystemClock::{{ name }} <= uint64_t(baudrate) * 4096, "fck must be in the range [3 x baud rate, 4096 x baud rate]."); constexpr uint32_t max = (1ul << 20) - 1ul; - constexpr auto result = GenericPrescaler::from_range( + constexpr auto result = GenericPrescaler::from_linear( uint64_t(SystemClock::{{ name }}) * 256, baudrate, 0x300, max); %% else constexpr uint32_t max = (1ul << 16) - 1ul; - constexpr auto result = Prescaler::from_range(SystemClock::{{ name }}, baudrate, 1, max); + constexpr auto result = Prescaler::from_linear(SystemClock::{{ name }}, baudrate, 16, max); %% endif modm::PeripheralDriver::assertBaudrateInTolerance< result.frequency, baudrate, tolerance >(); diff --git a/src/modm/platform/usb/sam/usb.hpp.in b/src/modm/platform/usb/sam/usb.hpp.in index 5db79081a8..dd37c4e266 100644 --- a/src/modm/platform/usb/sam/usb.hpp.in +++ b/src/modm/platform/usb/sam/usb.hpp.in @@ -30,7 +30,7 @@ public: { %% if target["family"] == "g5x" // only the USB device mode is supported for now - static_assert(modm::Tolerance::isValueInTolerance(48_MHz, SystemClock::Usb, 0.25_pct), + static_assert(modm::isValueInTolerance(48_MHz, SystemClock::Usb, 0.25_pct), "The USB clock frequency must be within 0.25\% of 48MHz!"); // Select DM/DP function for PA21/22 MATRIX->CCFG_SYSIO &= ~(CCFG_SYSIO_SYSIO11 | CCFG_SYSIO_SYSIO10); diff --git a/test/modm/math/algorithm/prescaler_counter_test.cpp b/test/modm/math/algorithm/prescaler_counter_test.cpp new file mode 100644 index 0000000000..8410c08faa --- /dev/null +++ b/test/modm/math/algorithm/prescaler_counter_test.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2024, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include +#include + +#include "prescaler_counter_test.hpp" +using namespace modm::literals; + +using Prescaler = modm::GenericPrescalerCounter; + +void +PrescalerCounterTest::testList() +{ + // one prescaler + { + const auto result = Prescaler::from_list( + 32_kHz, 1_Hz, 1ul << 12, {8}); + TEST_ASSERT_EQUALS(result.index, 0ul); + TEST_ASSERT_EQUALS(result.prescaler, 8ul); + TEST_ASSERT_EQUALS(result.counter, 4000ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1.0); + TEST_ASSERT_EQUALS_FLOAT(result.error, 0.0); + } + // two prescaler 1 + { + const auto result = Prescaler::from_list( + 32_kHz, 1_Hz, 1ul << 12, {4, 8}); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 8ul); + TEST_ASSERT_EQUALS(result.counter, 4000ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1.0); + TEST_ASSERT_EQUALS_FLOAT(result.error, 0.0); + } + // two prescaler 2 + { + const auto result = Prescaler::from_list( + 32_kHz, 2_Hz, 1ul << 12, {9, 11}); + TEST_ASSERT_EQUALS(result.index, 0ul); + TEST_ASSERT_EQUALS(result.prescaler, 9ul); + TEST_ASSERT_EQUALS(result.counter, 1778ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1.99975f); + TEST_ASSERT_EQUALS_FLOAT(result.error, 0.000125); + } + // exact matches + { + const auto result = Prescaler::from_list( + 40_kHz, 4_Hz, 1ul << 16, {7,8,9,10,11,12}); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 8ul); + TEST_ASSERT_EQUALS(result.counter, 1250ul); + TEST_ASSERT_EQUALS(result.frequency, 4); + TEST_ASSERT_EQUALS(result.error, 0); + } + { + const auto result = Prescaler::from_list( + 32_kHz, 0.25, 1ul << 10, {128,64,32}); + TEST_ASSERT_EQUALS(result.index, 0ul); + TEST_ASSERT_EQUALS(result.prescaler, 128ul); + TEST_ASSERT_EQUALS(result.counter, 1000ul); + TEST_ASSERT_EQUALS(result.frequency, 0.25); + TEST_ASSERT_EQUALS(result.error, 0); + } + // inexact matches within prescaler range + { + const auto result = Prescaler::from_list( + 32_kHz, 1.902515, 1ul << 12, {3,5,7,11}); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 5ul); + TEST_ASSERT_EQUALS(result.counter, 3364ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1.9025f); + TEST_ASSERT_EQUALS_FLOAT(result.error, 0.00001); + } + { + const auto result = Prescaler::from_list( + 2_kHz, 1.093948, 1ul << 8, {11,13,17}); + TEST_ASSERT_EQUALS(result.index, 0ul); + TEST_ASSERT_EQUALS(result.prescaler, 11ul); + TEST_ASSERT_EQUALS(result.counter, 166ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1.095290f); + TEST_ASSERT_EQUALS_FLOAT(result.error, -0.00123); + } + { + const auto result = Prescaler::from_list( + 2_kHz, 1.25, 1ul << 6, {23,29,31}); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 29ul); + TEST_ASSERT_EQUALS(result.counter, 55ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1.253918); + TEST_ASSERT_EQUALS_FLOAT(result.error, -0.003135); + } + // inexact matches on error border within prescaler range + { + const auto result = Prescaler::from_list( + 1_kHz, 0.8138020833, 1ul << 6, {1024}); // ±20% + TEST_ASSERT_EQUALS(result.index, 0ul); + TEST_ASSERT_EQUALS(result.prescaler, 1024ul); + TEST_ASSERT_EQUALS(result.counter, 1ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 0.9765625); + TEST_ASSERT_EQUALS_FLOAT(result.error, -0.2); + } + // clamping below prescaler range + { + const auto result = Prescaler::from_list( + 1_kHz, 10_kHz, 1ul << 10, {9,1,10,2}); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 1ul); + TEST_ASSERT_EQUALS(result.counter, 1ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 1000); + TEST_ASSERT_EQUALS_FLOAT(result.error, 0.9); + } + // clamping above prescaler range + { + const auto result = Prescaler::from_list( + 10_kHz, 1_Hz, 1ul << 10, {1,4,3,2}); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 4ul); + TEST_ASSERT_EQUALS(result.counter, 1024ul); + TEST_ASSERT_EQUALS_FLOAT(result.frequency, 2.44140625); + TEST_ASSERT_EQUALS_FLOAT(result.error, -1.44141); + } + // const with static_assert + { + constexpr auto result = Prescaler::from_list( + 10_kHz, 1_Hz, 1ul << 10, {51,7,11}); + static_assert(result.index == 2ul); + static_assert(result.prescaler == 11ul); + static_assert(result.counter == 909); + static_assert(result.frequency - 1.0001 < 0.01); + static_assert(result.error - -0.00001 < 0.01); + } +} + +void +PrescalerCounterTest::testFunction() +{ + // implemented via iterator + { + const auto result = Prescaler::from_function( + 32_kHz, 2_Hz, 1ul << 12, 9, 11, [](uint32_t ii) { return 2*ii; }); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 20ul); + TEST_ASSERT_EQUALS(result.counter, 800ul); + TEST_ASSERT_EQUALS(result.frequency, 2); + TEST_ASSERT_EQUALS(result.error, 0); + } + { + const auto result = Prescaler::from_function( + 32_kHz, 2_Hz, 1ul << 12, 11, 9, [](uint32_t ii) { return 2*ii; }); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 20ul); + TEST_ASSERT_EQUALS(result.counter, 800ul); + TEST_ASSERT_EQUALS(result.frequency, 2); + TEST_ASSERT_EQUALS(result.error, 0); + } +} + +void +PrescalerCounterTest::testLinear() +{ + // implemented via iterator + { + const auto result = Prescaler::from_linear( + 40_kHz, 4_Hz, 1ul << 10, 8, 12); + TEST_ASSERT_EQUALS(result.index, 2ul); + TEST_ASSERT_EQUALS(result.prescaler, 10ul); + TEST_ASSERT_EQUALS(result.counter, 1000ul); + TEST_ASSERT_EQUALS(result.frequency, 4); + TEST_ASSERT_EQUALS(result.error, 0); + } + { + const auto result = Prescaler::from_linear( + 40_kHz, 4_Hz, 1ul << 10, 12, 8); + TEST_ASSERT_EQUALS(result.index, 2ul); + TEST_ASSERT_EQUALS(result.prescaler, 10ul); + TEST_ASSERT_EQUALS(result.counter, 1000ul); + TEST_ASSERT_EQUALS(result.frequency, 4); + TEST_ASSERT_EQUALS(result.error, 0); + } +} + +void +PrescalerCounterTest::testPower() +{ + // implemented via iterator + { + const auto result = Prescaler::from_power( + 40_kHz, 4_Hz, 1ul << 10, 8, 32); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 16ul); + TEST_ASSERT_EQUALS(result.counter, 625ul); + TEST_ASSERT_EQUALS(result.frequency, 4); + TEST_ASSERT_EQUALS(result.error, 0); + } + { + const auto result = Prescaler::from_power( + 40_kHz, 4_Hz, 1ul << 10, 32, 8); + TEST_ASSERT_EQUALS(result.index, 1ul); + TEST_ASSERT_EQUALS(result.prescaler, 16ul); + TEST_ASSERT_EQUALS(result.counter, 625ul); + TEST_ASSERT_EQUALS(result.frequency, 4); + TEST_ASSERT_EQUALS(result.error, 0); + } +} diff --git a/test/modm/math/algorithm/prescaler_counter_test.hpp b/test/modm/math/algorithm/prescaler_counter_test.hpp new file mode 100644 index 0000000000..65669a9c4a --- /dev/null +++ b/test/modm/math/algorithm/prescaler_counter_test.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2024, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#include + +/// @ingroup modm_test_test_math +class PrescalerCounterTest : public unittest::TestSuite +{ +public: + void + testList(); + + void + testFunction(); + + void + testLinear(); + + void + testPower(); +}; diff --git a/test/modm/math/algorithm/prescaler_test.cpp b/test/modm/math/algorithm/prescaler_test.cpp index 134cba118c..90b0ae2aff 100644 --- a/test/modm/math/algorithm/prescaler_test.cpp +++ b/test/modm/math/algorithm/prescaler_test.cpp @@ -169,11 +169,11 @@ PrescalerTest::testFunction() } void -PrescalerTest::testRange() +PrescalerTest::testLinear() { // one prescaler { - const auto result = modm::Prescaler::from_range( + const auto result = modm::Prescaler::from_linear( 1_MHz, 0.25_MHz, 1, 1); TEST_ASSERT_EQUALS(result.index, 0ul); TEST_ASSERT_EQUALS(result.prescaler, 1ul); @@ -181,7 +181,7 @@ PrescalerTest::testRange() } // two prescalers { - const auto result = modm::Prescaler::from_range( + const auto result = modm::Prescaler::from_linear( 1_MHz, 0.25_MHz, 1, 2); TEST_ASSERT_EQUALS(result.index, 1ul); TEST_ASSERT_EQUALS(result.prescaler, 2ul); @@ -189,7 +189,7 @@ PrescalerTest::testRange() } // clamp lower range { - const auto result = modm::Prescaler::from_range( + const auto result = modm::Prescaler::from_linear( 1_MHz, 2_MHz, 1, 10); TEST_ASSERT_EQUALS(result.index, 0ul); TEST_ASSERT_EQUALS(result.prescaler, 1ul); @@ -197,7 +197,7 @@ PrescalerTest::testRange() } // clamp upper range { - const auto result = modm::Prescaler::from_range( + const auto result = modm::Prescaler::from_linear( 1_MHz, 0.05_MHz, 1, 10); TEST_ASSERT_EQUALS(result.index, 9ul); TEST_ASSERT_EQUALS(result.prescaler, 10ul); @@ -205,7 +205,7 @@ PrescalerTest::testRange() } // decide on error border { - const auto result = modm::Prescaler::from_range( + const auto result = modm::Prescaler::from_linear( 1_MHz, 0.75_MHz, 1, 10); TEST_ASSERT_EQUALS(result.index, 1ul); TEST_ASSERT_EQUALS(result.prescaler, 2ul); diff --git a/test/modm/math/algorithm/prescaler_test.hpp b/test/modm/math/algorithm/prescaler_test.hpp index bed1eafc45..dca1d50692 100644 --- a/test/modm/math/algorithm/prescaler_test.hpp +++ b/test/modm/math/algorithm/prescaler_test.hpp @@ -22,7 +22,7 @@ class PrescalerTest : public unittest::TestSuite testFunction(); void - testRange(); + testLinear(); void testPower(); diff --git a/test/modm/ui/color/color_test.cpp b/test/modm/ui/color/color_test.cpp index ce4aca9a24..0864e30282 100644 --- a/test/modm/ui/color/color_test.cpp +++ b/test/modm/ui/color/color_test.cpp @@ -93,9 +93,9 @@ void ColorTest::testRgbHsvPingPongConvertion_8bit() // Convertion can distort - allow some tolerance. using namespace modm; - TEST_ASSERT_TRUE(modm::Tolerance::isValueInTolerance(rgb8.red, rgb8_b.red, 1_pct)); - TEST_ASSERT_TRUE(modm::Tolerance::isValueInTolerance(rgb8.green, rgb8_b.green, 1_pct)); - TEST_ASSERT_TRUE(modm::Tolerance::isValueInTolerance(rgb8.blue, rgb8_b.blue, 1_pct)); + TEST_ASSERT_TRUE(modm::isValueInTolerance(rgb8.red, rgb8_b.red, 1_pct)); + TEST_ASSERT_TRUE(modm::isValueInTolerance(rgb8.green, rgb8_b.green, 1_pct)); + TEST_ASSERT_TRUE(modm::isValueInTolerance(rgb8.blue, rgb8_b.blue, 1_pct)); } // TODO 16bit convertion not yet working @@ -109,7 +109,7 @@ void ColorTest::testRgbHsvPingPongConvertion_8bit() // // Convertion can distort - allow some tolerance. // using namespace modm; -// TEST_ASSERT_TRUE(modm::Tolerance::isValueInTolerance(rgb.red, rgb16_b.red, 1_pct)); -// TEST_ASSERT_TRUE(modm::Tolerance::isValueInTolerance(rgb.green, rgb16_b.green, 1_pct)); -// TEST_ASSERT_TRUE(modm::Tolerance::isValueInTolerance(rgb.blue, rgb16_b.blue, 1_pct)); -// } \ No newline at end of file +// TEST_ASSERT_TRUE(modm::isValueInTolerance(rgb.red, rgb16_b.red, 1_pct)); +// TEST_ASSERT_TRUE(modm::isValueInTolerance(rgb.green, rgb16_b.green, 1_pct)); +// TEST_ASSERT_TRUE(modm::isValueInTolerance(rgb.blue, rgb16_b.blue, 1_pct)); +// }