Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Fix delay_ns cycle calculation #642

Merged
merged 7 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ jobs:
(cd test && make compile-nucleo-l432)
(cd test && make compile-nucleo-f103_A)
(cd test && make compile-nucleo-f103_B)
(cd test && make compile-nucleo-f091)
- name: Linux Examples
if: always()
run: |
Expand Down Expand Up @@ -90,7 +91,7 @@ jobs:
- name: Examples STM32F0 Series
if: always()
run: |
(cd examples && ../tools/scripts/examples_compile.py stm32f0_discovery stm32f072_discovery nucleo_f031k6 nucleo_f072rb nucleo_f042k6 stm32f030f4p6_demo_board)
(cd examples && ../tools/scripts/examples_compile.py stm32f0_discovery stm32f072_discovery nucleo_f031k6 nucleo_f072rb nucleo_f091rc nucleo_f042k6 stm32f030f4p6_demo_board)
- name: Examples STM32F1 Series
if: always()
run: |
Expand Down
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -469,39 +469,41 @@ We have out-of-box support for many development boards including documentation.
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f042k6">NUCLEO-F042K6</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f072rb">NUCLEO-F072RB</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f091rc">NUCLEO-F091RC</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f103rb">NUCLEO-F103RB</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f303k8">NUCLEO-F303K8</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f303re">NUCLEO-F303RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f334r8">NUCLEO-F334R8</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f334r8">NUCLEO-F334R8</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f401re">NUCLEO-F401RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f411re">NUCLEO-F411RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f429zi">NUCLEO-F429ZI</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f439zi">NUCLEO-F439ZI</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f439zi">NUCLEO-F439ZI</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f446re">NUCLEO-F446RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f446ze">NUCLEO-F446ZE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f746zg">NUCLEO-F746ZG</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f767zi">NUCLEO-F767ZI</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-f767zi">NUCLEO-F767ZI</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-g071rb">NUCLEO-G071RB</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-g431kb">NUCLEO-G431KB</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-g431rb">NUCLEO-G431RB</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-g474re">NUCLEO-G474RE</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-g474re">NUCLEO-G474RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l031k6">NUCLEO-L031K6</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l152re">NUCLEO-L152RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l432kc">NUCLEO-L432KC</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l452re">NUCLEO-L452RE</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l452re">NUCLEO-L452RE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l476rg">NUCLEO-L476RG</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-nucleo-l496zg-p">NUCLEO-L496ZG-P</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-olimexino-stm32">OLIMEXINO-STM32</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-raspberrypi">Raspberry Pi</a></td>
</tr><tr>
<td align="center"><a href="https://modm.io/reference/module/modm-board-raspberrypi">Raspberry Pi</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-samd21-mini">SAMD21-MINI</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-stm32_f4ve">STM32-F4VE</a></td>
<td align="center"><a href="https://modm.io/reference/module/modm-board-stm32f030_demo">STM32F030-DEMO</a></td>
</tr><tr>
</tr>
</table>
<!--/bsptable-->
Expand Down
207 changes: 207 additions & 0 deletions examples/generic/delay/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
/*
* Copyright (c) 2021, 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 <modm/board.hpp>

using namespace Board;

#ifdef CFG_TUSB_MCU
#include <modm/debug.hpp>
modm::IODeviceWrapper<UsbUart0, modm::IOBuffer::DiscardIfFull> usb_io_device;
modm::log::Logger modm::log::info(usb_io_device);
#endif

static void
run_delay_ns(uint32_t ns)
{
#ifdef CFG_TUSB_MCU
tud_task();
#endif
uint32_t start, stop;
{
modm::atomic::Lock _;
#ifdef DWT
start = DWT->CYCCNT;
#else
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
SysTick->LOAD = (1ul << 23);
SysTick->VAL = 0;
stop = SysTick->VAL;
#endif
modm::delay_ns(ns);
#ifdef DWT
stop = DWT->CYCCNT;
#else
start = SysTick->VAL;
#endif
}
#ifdef CFG_TUSB_MCU
tud_task();
#endif
const uint32_t cycles = (stop - start) - 4;
const uint32_t expected = uint64_t(SystemCoreClock) * ns / 1'000'000'000ull;
const uint32_t real = cycles * 1'000'000'000ull / SystemCoreClock;
MODM_LOG_INFO.printf("%8lu | %7lu | %7lu | %8lu %c\n", ns, expected, cycles, real,
(cycles < expected*1.2f ? (cycles > expected*0.8f ? ' ' : '<') : '>')) << modm::flush;
#ifdef CFG_TUSB_MCU
tud_task();
#endif
}

static void
run_delay_us(uint32_t us)
{
#ifdef CFG_TUSB_MCU
tud_task();
#endif
uint32_t start, stop;
{
modm::atomic::Lock _;
#ifdef DWT
start = DWT->CYCCNT;
#else
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
SysTick->LOAD = (1ul << 23);
SysTick->VAL = 0;
stop = SysTick->VAL;
#endif
modm::delay_us(us);
#ifdef DWT
stop = DWT->CYCCNT;
#else
start = SysTick->VAL;
#endif
}
#ifdef CFG_TUSB_MCU
tud_task();
#endif
const uint32_t cycles = (stop - start) - 4;
const uint32_t expected = uint64_t(SystemCoreClock) * us / 1'000'000ull;
const uint32_t real = cycles * 1'000'000ull / SystemCoreClock;
MODM_LOG_INFO.printf("%8lu | %8lu | %8lu | %8lu %c\n", us, expected, cycles, real,
(cycles < expected*1.2f ? (cycles > expected*0.8f ? ' ' : '<') : '>')) << modm::flush;
#ifdef CFG_TUSB_MCU
tud_task();
#endif
}

static void
run_test_ns(bool short_test=false)
{
MODM_LOG_INFO << "\nmodm::delay_ns for system clock = " << SystemCoreClock << modm::endl;
MODM_LOG_INFO << " expected | measured\n";
MODM_LOG_INFO << " ns | cycles | cycles | ns\n";

if (short_test)
{
run_delay_ns( 100);
run_delay_ns( 1'000);
run_delay_ns( 10'000);
run_delay_ns( 100'000);
run_delay_ns( 1'000'000);
run_delay_ns(10'000'000);
}
else
{
run_delay_ns(1);
run_delay_ns(5);
run_delay_ns(10);
for (uint32_t ii= 50; ii < 1000; ii += 50) run_delay_ns(ii);
for (uint32_t ii=1000; ii < 2000; ii += 100) run_delay_ns(ii);
for (uint32_t ii=2000; ii <= 10000; ii += 1000) run_delay_ns(ii);
run_delay_ns(100'000);
run_delay_ns(1'000'000);
run_delay_ns(10'000'000);
}
}

static void
run_test_us(bool short_test=false)
{
MODM_LOG_INFO << "\nmodm::delay_us for boot clock = " << SystemCoreClock << modm::endl;
MODM_LOG_INFO << " expected | measured\n";
MODM_LOG_INFO << " us | cycles | cycles | us\n";

if (short_test)
{
run_delay_us(1);
run_delay_us(5);
for (uint32_t ii=10; ii < 100; ii += 10) run_delay_us(ii);
run_delay_us(1'000);
}
else
{
run_delay_us( 1);
run_delay_us( 5);
run_delay_us( 10);
run_delay_us( 100);
run_delay_us( 1'000);
run_delay_us( 10'000);
run_delay_us(100'000);
}
}

#ifndef CFG_TUSB_MCU
// STM32 device
struct BootClock
{
// It may be necessary to scale these, due to clock prescalers != 1
static constexpr uint32_t Usart1 = Rcc::BootFrequency;
static constexpr uint32_t Usart2 = Rcc::BootFrequency;
static constexpr uint32_t Usart3 = Rcc::BootFrequency;
static constexpr uint32_t Usart4 = Rcc::BootFrequency;
static constexpr uint32_t Usart5 = Rcc::BootFrequency;
};
int main()
{
Board::stlink::Uart::connect<Board::stlink::Tx::Tx>();
Board::stlink::Uart::initialize<BootClock, 115200_Bd, 5_pct>();

run_test_ns(true);
run_test_us(true);

Board::initialize();

run_test_ns();
run_test_us();

while(true) {}
return 0;
}

#else
// SAMD21
int main()
{
Board::initialize();
Board::initializeUsbFs();
tusb_init();

MODM_LOG_INFO << "Hello World\n";

static int32_t counter{0};
while (true)
{
tud_task();

if (counter-- < 0)
{
Leds::toggle();
counter = 1'000'000;
MODM_LOG_INFO << modm::platform::delay_ns_per_loop << modm::endl;
run_test_ns();
run_test_us(true);
}
}
return 0;
}

#endif
24 changes: 24 additions & 0 deletions examples/generic/delay/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<library>
<!-- <extends>modm:nucleo-l152re</extends> -->
<!-- <extends>modm:nucleo-f103rb</extends> -->
<!-- <extends>modm:nucleo-f401re</extends> -->
<!-- <extends>modm:nucleo-f411re</extends> -->
<!-- <extends>modm:nucleo-f446re</extends> -->
<extends>modm:nucleo-f334r8</extends>
<!-- <extends>modm:nucleo-f303k8</extends> -->
<!-- <extends>modm:nucleo-l476rg</extends> -->
<!-- <extends>modm:disco-f746ng</extends> -->
<!-- <extends>modm:nucleo-g071rb</extends> -->
<!-- <extends>modm:nucleo-f072rb</extends> -->
<!-- <extends>modm:nucleo-f091rc</extends> -->
<!-- <extends>modm:samd21-mini</extends> -->
<options>
<option name="modm:build:build.path">../../../build/generic/delay</option>
<!-- <option name="modm:tinyusb:config">device.cdc</option> -->
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:debug</module>
<!-- <module>modm:tinyusb</module> -->
</modules>
</library>
44 changes: 44 additions & 0 deletions examples/nucleo_f091rc/blink/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2021, 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 <modm/board.hpp>
#include <modm/processing.hpp>

using namespace Board;

int
main()
{
Board::initialize();
LedD13::setOutput();

// Use the logging streams to print some messages.
// Change MODM_LOG_LEVEL above to enable or disable these messages
MODM_LOG_DEBUG << "debug" << modm::endl;
MODM_LOG_INFO << "info" << modm::endl;
MODM_LOG_WARNING << "warning" << modm::endl;
MODM_LOG_ERROR << "error" << modm::endl;

uint32_t counter(0);
modm::ShortPeriodicTimer timer(1s);

while (true)
{
if (timer.execute())
{
LedD13::toggle();

MODM_LOG_INFO << "loop: " << counter++ << modm::endl;
}
}

return 0;
}
10 changes: 10 additions & 0 deletions examples/nucleo_f091rc/blink/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<library>
<extends>modm:nucleo-f091rc</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_f091rc/blink</option>
</options>
<modules>
<module>modm:build:scons</module>
<module>modm:processing:timer</module>
</modules>
</library>
15 changes: 13 additions & 2 deletions src/modm/architecture/interface/delay.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,20 @@ to you is to delay for _at least_ the specified time. Note that invocation of
interrupts during spinning may add delay too. For additional limitations also
check the description of the `modm:platform:core` modules.

Please note that the delay these functions provide is defined as the time from
invocation to the time of execution return. Obviously no delay beyond that is
considered, which may require you to use shorter delays to compensate for the
overhead of your code:

```cpp
do // GpioA4 toggling takes longer than 500ns because:
{
modm::delay_ns(500); // takes ~500ns
GpioA4::toggle(); // takes a few cycles
} while(1); // jump back to loop also takes a few cycles
```

You should always prefer Software Timers (see `modm:processing:timer`) over
these *blocking* delay functions. However, when `modm::Clock` is not set up yet,
or when you need very small delays (for example to bit-bang a protocol), you
need to use these delay functions.


Loading