mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-29 15:04:32 +01:00
Merge remote-tracking branch 'origin/master' into feature/esp32c6
This commit is contained in:
commit
7e03812494
57 changed files with 2788 additions and 1679 deletions
88
.github/workflows/build.yml
vendored
88
.github/workflows/build.yml
vendored
|
@ -15,6 +15,8 @@ env:
|
|||
OLDOLDOLDSTABLE_VERSION: 0.4
|
||||
QEMU_VERSION: 8.2.0
|
||||
QEMU_URL: https://download.qemu.org/qemu-8.2.0.tar.xz
|
||||
QEMU_ESP: qemu_esp
|
||||
QEMU_ESP_URL: https://github.com/espressif/qemu/releases/download/esp-develop-8.2.0-20240122/qemu-riscv32-softmmu-esp_develop_8.2.0_20240122-x86_64-linux-gnu.tar.xz
|
||||
|
||||
jobs:
|
||||
# Run cargo xtask format-check
|
||||
|
@ -257,7 +259,7 @@ jobs:
|
|||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y qemu-system-arm qemu-system-riscv32
|
||||
sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build
|
||||
sudo apt install -y git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build
|
||||
|
||||
- if: ${{ steps.cache-qemu.outputs.cache-hit != 'true' }}
|
||||
name: Download QEMU
|
||||
|
@ -277,7 +279,15 @@ jobs:
|
|||
name: Build QEMU
|
||||
run: |
|
||||
cd qemu-${{ env.QEMU_VERSION }}
|
||||
make -j$(nproc)
|
||||
ninja -C build
|
||||
|
||||
- name: Download ESP32 QEMU
|
||||
run: wget "${{ env.QEMU_ESP_URL }}" --output-document=${{ env.QEMU_ESP}}.tar.xz
|
||||
|
||||
- name: Extract ESP32 QEMU
|
||||
run: |
|
||||
mkdir -p qemu-${{ env.QEMU_VERSION }}/build/esp32
|
||||
tar --strip-components=1 -xvJf ${{ env.QEMU_ESP }}.tar.xz -C qemu-${{ env.QEMU_VERSION }}/build/esp32 qemu
|
||||
|
||||
- name: Archive QEMU build
|
||||
run: |
|
||||
|
@ -413,6 +423,75 @@ jobs:
|
|||
if: ${{ matrix.backend != 'riscv32-imc-clint' }}
|
||||
run: cargo xtask --deny-warnings --platform hifive1 --backend ${{ matrix.backend }} qemu
|
||||
|
||||
# Platform esp32c3: verify the example output with run-pass tests
|
||||
testexamplesesp32c3:
|
||||
name: QEMU run (esp32c3)
|
||||
needs: buildqemu
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
toolchain:
|
||||
- stable
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust ${{ matrix.toolchain }}
|
||||
run: |
|
||||
rustup set profile minimal
|
||||
rustup override set ${{ matrix.toolchain }}
|
||||
|
||||
- name: Configure Rust target
|
||||
run: |
|
||||
rustup target add riscv32imac-unknown-none-elf
|
||||
rustup target add riscv32imc-unknown-none-elf
|
||||
|
||||
- name: Add Rust component llvm-tools-preview
|
||||
run: rustup component add llvm-tools-preview
|
||||
|
||||
- name: Install libudev espflash dependency
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libudev-dev
|
||||
|
||||
# Use precompiled binutils
|
||||
- name: Install cargo-binutils
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-binutils
|
||||
|
||||
# Use precompiled if possible
|
||||
- name: Install cargo-binutils
|
||||
uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: espflash
|
||||
|
||||
- name: Install esptool.py
|
||||
run: pip install esptool
|
||||
|
||||
- name: Cache Dependencies
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install QEMU to get dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y qemu-system-riscv32
|
||||
|
||||
- name: Download built QEMU
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: qemu
|
||||
|
||||
- name: Extract ESP32 QEMU into local path
|
||||
run: sudo tar --strip-components=1 -xf qemu.tar -C /usr/local/ esp32/
|
||||
|
||||
- name: Check which QEMU is used
|
||||
run: |
|
||||
which qemu-system-riscv32
|
||||
|
||||
- name: Run-pass tests
|
||||
run: cargo xtask -v --platform esp32-c3 qemu
|
||||
|
||||
# Run test suite
|
||||
tests:
|
||||
name: tests
|
||||
|
@ -720,7 +799,7 @@ jobs:
|
|||
tool: mdbook-mermaid
|
||||
|
||||
- name: mdBook Action
|
||||
uses: peaceiris/actions-mdbook@v1
|
||||
uses: peaceiris/actions-mdbook@v2
|
||||
with:
|
||||
mdbook-version: 'latest'
|
||||
|
||||
|
@ -831,7 +910,7 @@ jobs:
|
|||
tar -xf bookstodeploy.tar
|
||||
|
||||
- name: Deploy to GH-pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./bookstodeploy
|
||||
|
@ -853,6 +932,7 @@ jobs:
|
|||
- checkexamplesesp32c6
|
||||
- testexampleslm3s6965
|
||||
- testexampleshifive1
|
||||
- testexamplesesp32c3
|
||||
- tests
|
||||
- docs
|
||||
- mdbook
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -9,3 +9,4 @@ book-target/
|
|||
|
||||
.DS_Store
|
||||
.vscode/
|
||||
qemu.log
|
||||
|
|
36
ci/expected/esp32c3/sw_and_hw.run
Normal file
36
ci/expected/esp32c3/sw_and_hw.run
Normal file
|
@ -0,0 +1,36 @@
|
|||
QEMU 8.2.0 monitor - type 'help' for more information
|
||||
(qemu) q[K
|
||||
ESP-ROM:esp32c3-api1-20210207
|
||||
Build:Feb 7 2021
|
||||
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
|
||||
SPIWP:0xee
|
||||
mode:DIO, clock div:2
|
||||
load:0x3fcd5820,len:0x1714
|
||||
load:0x403cc710,len:0x968
|
||||
load:0x403ce710,len:0x2f9c
|
||||
entry 0x403cc710
|
||||
[0;32mI (0) boot: ESP-IDF v5.1.2-342-gbcf1645e44 2nd stage bootloader[0m
|
||||
[0;32mI (0) boot: compile time Dec 12 2023 10:50:58[0m
|
||||
[0;32mI (0) boot: chip revision: v0.3[0m
|
||||
[0;32mI (0) boot.esp32c3: SPI Speed : 40MHz[0m
|
||||
[0;32mI (0) boot.esp32c3: SPI Mode : SLOW READ[0m
|
||||
[0;32mI (0) boot.esp32c3: SPI Flash Size : 4MB[0m
|
||||
[0;32mI (0) boot: Enabling RNG early entropy source...[0m
|
||||
[0;32mI (1) boot: Partition Table:[0m
|
||||
[0;32mI (1) boot: ## Label Usage Type ST Offset Length[0m
|
||||
[0;32mI (1) boot: 0 nvs WiFi data 01 02 00009000 00006000[0m
|
||||
[0;32mI (1) boot: 1 phy_init RF data 01 01 0000f000 00001000[0m
|
||||
[0;32mI (1) boot: 2 factory factory app 00 00 00010000 003f0000[0m
|
||||
[0;32mI (1) boot: End of partition table[0m
|
||||
[0;32mI (1) esp_image: REDACTED
|
||||
[0;32mI (3) esp_image: REDACTED
|
||||
[0;32mI (3) esp_image: REDACTED
|
||||
[0;32mI (8) esp_image: REDACTED
|
||||
[0;32mI (11) boot: Loaded app from partition at offset 0x10000[0m
|
||||
[0;32mI (11) boot: Disabling RNG early entropy source...[0m
|
||||
init
|
||||
Inside high prio task, press button now!
|
||||
Leaving high prio task.
|
||||
idle
|
||||
Inside low prio task, press button now!
|
||||
Leaving low prio task.
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||
use rtic::app;
|
||||
use rtic_monotonics::systick::*;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
systick_monotonic!(Mono, 1_000);
|
||||
|
||||
pub mod pac {
|
||||
pub use embassy_stm32::pac::Interrupt as interrupt;
|
||||
pub use embassy_stm32::pac::*;
|
||||
|
@ -26,8 +28,7 @@ mod app {
|
|||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
// Initialize the systick interrupt & obtain the token to prove that we did
|
||||
let systick_mono_token = rtic_monotonics::create_systick_token!();
|
||||
Systick::start(cx.core.SYST, 25_000_000, systick_mono_token);
|
||||
Mono::start(cx.core.SYST, 25_000_000);
|
||||
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
defmt::info!("Hello World!");
|
||||
|
@ -53,7 +54,7 @@ mod app {
|
|||
led.set_low();
|
||||
}
|
||||
state = !state;
|
||||
Systick::delay(1000.millis()).await;
|
||||
Mono::delay(1000.millis()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
[target.riscv32imc-unknown-none-elf]
|
||||
runner = "espflash flash --monitor"
|
||||
# Real hardware
|
||||
#runner = "espflash flash --monitor"
|
||||
|
||||
# QEMU emulator
|
||||
runner = "./runner.sh"
|
||||
|
||||
[build]
|
||||
rustflags = [
|
||||
|
|
31
examples/esp32c3/runner.sh
Executable file
31
examples/esp32c3/runner.sh
Executable file
|
@ -0,0 +1,31 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [ $# -eq 0 ]
|
||||
then
|
||||
echo "No arguments supplied! Provide path to ELF as argument"
|
||||
fi
|
||||
|
||||
outputfilenamecargo=$1
|
||||
outputfilename="$outputfilenamecargo".bin
|
||||
|
||||
logfile=qemu.log
|
||||
|
||||
qemuexec=qemu-system-riscv32
|
||||
|
||||
# Building ESP32-C3 image
|
||||
espflash save-image --chip esp32c3 --merge "$outputfilenamecargo" "$outputfilename" 1>&2
|
||||
|
||||
# Get stats
|
||||
esptool.py image_info --version 2 "$outputfilename" 1>&2
|
||||
|
||||
# Run in QEMU
|
||||
$qemuexec -nographic -monitor tcp:127.0.0.1:55555,server,nowait -icount 3 -machine esp32c3 -drive file="$outputfilename",if=mtd,format=raw -serial file:"$logfile" &
|
||||
|
||||
# Let it run
|
||||
sleep 3s
|
||||
|
||||
# Kill QEMU nicely by sending 'q' (quit) over tcp
|
||||
echo q | nc -N 127.0.0.1 55555
|
||||
# Output that will be compared, remove the esp_image segments as they change
|
||||
# between runs
|
||||
cat "$logfile" | sed 's/esp_image: .*$/esp_image: REDACTED/'
|
9
examples/lm3s6965/Cargo.lock
generated
9
examples/lm3s6965/Cargo.lock
generated
|
@ -362,7 +362,6 @@ dependencies = [
|
|||
"critical-section",
|
||||
"rtic-core",
|
||||
"rtic-macros",
|
||||
"rtic-monotonics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -392,12 +391,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-hal 1.0.0",
|
||||
"fugit",
|
||||
"rtic-time",
|
||||
]
|
||||
|
@ -417,9 +415,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "1.3.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"fugit",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
|
|
@ -11,7 +11,9 @@ use panic_semihosting as _;
|
|||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
|
||||
mod app {
|
||||
use cortex_m_semihosting::{debug, hprintln};
|
||||
use rtic_monotonics::systick::*;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
|
||||
systick_monotonic!(Mono, 100);
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
@ -23,8 +25,7 @@ mod app {
|
|||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
hprintln!("init");
|
||||
|
||||
let systick_token = rtic_monotonics::create_systick_token!();
|
||||
Systick::start(cx.core.SYST, 12_000_000, systick_token);
|
||||
Mono::start(cx.core.SYST, 12_000_000);
|
||||
|
||||
foo::spawn().ok();
|
||||
bar::spawn().ok();
|
||||
|
@ -36,21 +37,21 @@ mod app {
|
|||
#[task]
|
||||
async fn foo(_cx: foo::Context) {
|
||||
hprintln!("hello from foo");
|
||||
Systick::delay(100.millis()).await;
|
||||
Mono::delay(100.millis()).await;
|
||||
hprintln!("bye from foo");
|
||||
}
|
||||
|
||||
#[task]
|
||||
async fn bar(_cx: bar::Context) {
|
||||
hprintln!("hello from bar");
|
||||
Systick::delay(200.millis()).await;
|
||||
Mono::delay(200.millis()).await;
|
||||
hprintln!("bye from bar");
|
||||
}
|
||||
|
||||
#[task]
|
||||
async fn baz(_cx: baz::Context) {
|
||||
hprintln!("hello from baz");
|
||||
Systick::delay(300.millis()).await;
|
||||
Mono::delay(300.millis()).await;
|
||||
hprintln!("bye from baz");
|
||||
|
||||
debug::exit(debug::EXIT_SUCCESS);
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
use cortex_m_semihosting::{debug, hprintln};
|
||||
use panic_semihosting as _;
|
||||
use rtic_monotonics::systick::*;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
systick_monotonic!(Mono, 100);
|
||||
|
||||
#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)]
|
||||
mod app {
|
||||
use super::*;
|
||||
use futures::{future::FutureExt, select_biased};
|
||||
use rtic_monotonics::Monotonic;
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
@ -27,8 +27,7 @@ mod app {
|
|||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
hprintln!("init");
|
||||
|
||||
let systick_token = rtic_monotonics::create_systick_token!();
|
||||
Systick::start(cx.core.SYST, 12_000_000, systick_token);
|
||||
Mono::start(cx.core.SYST, 12_000_000);
|
||||
// ANCHOR_END: init
|
||||
|
||||
foo::spawn().ok();
|
||||
|
@ -42,19 +41,19 @@ mod app {
|
|||
// Call hal with short relative timeout using `select_biased`
|
||||
select_biased! {
|
||||
v = hal_get(1).fuse() => hprintln!("hal returned {}", v),
|
||||
_ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first
|
||||
_ = Mono::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first
|
||||
}
|
||||
|
||||
// Call hal with long relative timeout using `select_biased`
|
||||
select_biased! {
|
||||
v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first
|
||||
_ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ),
|
||||
_ = Mono::delay(1000.millis()).fuse() => hprintln!("timeout", ),
|
||||
}
|
||||
// ANCHOR_END: select_biased
|
||||
|
||||
// ANCHOR: timeout_after_basic
|
||||
// Call hal with long relative timeout using monotonic `timeout_after`
|
||||
match Systick::timeout_after(1000.millis(), hal_get(1)).await {
|
||||
match Mono::timeout_after(1000.millis(), hal_get(1)).await {
|
||||
Ok(v) => hprintln!("hal returned {}", v),
|
||||
_ => hprintln!("timeout"),
|
||||
}
|
||||
|
@ -62,20 +61,20 @@ mod app {
|
|||
|
||||
// ANCHOR: timeout_at_basic
|
||||
// get the current time instance
|
||||
let mut instant = Systick::now();
|
||||
let mut instant = Mono::now();
|
||||
|
||||
// do this 3 times
|
||||
for n in 0..3 {
|
||||
// absolute point in time without drift
|
||||
instant += 1000.millis();
|
||||
Systick::delay_until(instant).await;
|
||||
Mono::delay_until(instant).await;
|
||||
|
||||
// absolute point in time for timeout
|
||||
let timeout = instant + 500.millis();
|
||||
hprintln!("now is {:?}, timeout at {:?}", Systick::now(), timeout);
|
||||
hprintln!("now is {:?}, timeout at {:?}", Mono::now(), timeout);
|
||||
|
||||
match Systick::timeout_at(timeout, hal_get(n)).await {
|
||||
Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()),
|
||||
match Mono::timeout_at(timeout, hal_get(n)).await {
|
||||
Ok(v) => hprintln!("hal returned {} at time {:?}", v, Mono::now()),
|
||||
_ => hprintln!("timeout"),
|
||||
}
|
||||
}
|
||||
|
@ -90,7 +89,7 @@ async fn hal_get(n: u32) -> u32 {
|
|||
// emulate some delay time dependent on n
|
||||
let d = 350.millis() + n * 100.millis();
|
||||
hprintln!("the hal takes a duration of {:?}", d);
|
||||
Systick::delay(d).await;
|
||||
Mono::delay(d).await;
|
||||
// emulate some return value
|
||||
5
|
||||
}
|
||||
|
|
40
examples/nrf52840_blinky/Cargo.lock
generated
40
examples/nrf52840_blinky/Cargo.lock
generated
|
@ -136,7 +136,7 @@ dependencies = [
|
|||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -179,9 +179,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0-rc.2"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e57ec6ad0bc8eb967cf9c9f144177f5e8f2f6f02dad0b8b683f9f05f6b22def"
|
||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-async"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-storage"
|
||||
|
@ -412,18 +421,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -468,18 +477,18 @@ dependencies = [
|
|||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.4.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0-rc.2",
|
||||
"embedded-hal 1.0.0",
|
||||
"fugit",
|
||||
"nrf52840-pac",
|
||||
"rtic-time",
|
||||
|
@ -487,9 +496,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "1.1.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"fugit",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
@ -537,9 +549,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.39"
|
||||
version = "2.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
||||
checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -563,7 +575,7 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.39",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -26,7 +26,7 @@ features = ["thumbv7-backend"]
|
|||
|
||||
[dependencies.rtic-monotonics]
|
||||
path = "../../rtic-monotonics"
|
||||
version = "1.4.0"
|
||||
version = "2.0.0"
|
||||
features = ["nrf52840"]
|
||||
|
||||
# cargo build/run
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
use nrf52840_blinky::hal;
|
||||
|
||||
use rtic_monotonics::nrf::rtc::prelude::*;
|
||||
nrf_rtc0_monotonic!(Mono);
|
||||
|
||||
#[rtic::app(device = hal::pac, dispatchers = [SWI0_EGU0])]
|
||||
mod app {
|
||||
use super::*;
|
||||
|
@ -12,10 +15,6 @@ mod app {
|
|||
use hal::gpio::{Level, Output, Pin, PushPull};
|
||||
use hal::prelude::*;
|
||||
|
||||
use rtic_monotonics::nrf::rtc::Rtc0 as Mono;
|
||||
use rtic_monotonics::nrf::rtc::*;
|
||||
use rtic_monotonics::Monotonic;
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
|
@ -30,8 +29,7 @@ mod app {
|
|||
hal::clocks::Clocks::new(cx.device.CLOCK).start_lfclk();
|
||||
|
||||
// Initialize Monotonic
|
||||
let token = rtic_monotonics::create_nrf_rtc0_monotonic_token!();
|
||||
Mono::start(cx.device.RTC0, token);
|
||||
Mono::start(cx.device.RTC0);
|
||||
|
||||
// Setup LED
|
||||
let port0 = hal::gpio::p0::Parts::new(cx.device.P0);
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
use nrf52840_blinky::hal;
|
||||
|
||||
use rtic_monotonics::nrf::timer::prelude::*;
|
||||
nrf_timer0_monotonic!(Mono, 8_000_000);
|
||||
|
||||
#[rtic::app(device = hal::pac, dispatchers = [SWI0_EGU0])]
|
||||
mod app {
|
||||
use super::*;
|
||||
|
@ -12,10 +15,6 @@ mod app {
|
|||
use hal::gpio::{Level, Output, Pin, PushPull};
|
||||
use hal::prelude::*;
|
||||
|
||||
use rtic_monotonics::nrf::timer::Timer0 as Mono;
|
||||
use rtic_monotonics::nrf::timer::*;
|
||||
use rtic_monotonics::Monotonic;
|
||||
|
||||
#[shared]
|
||||
struct Shared {}
|
||||
|
||||
|
@ -27,8 +26,7 @@ mod app {
|
|||
#[init]
|
||||
fn init(cx: init::Context) -> (Shared, Local) {
|
||||
// Initialize Monotonic
|
||||
let token = rtic_monotonics::create_nrf_timer0_monotonic_token!();
|
||||
Mono::start(cx.device.TIMER0, token);
|
||||
Mono::start(cx.device.TIMER0);
|
||||
|
||||
// Setup LED
|
||||
let port0 = hal::gpio::p0::Parts::new(cx.device.P0);
|
||||
|
|
187
examples/rp2040_local_i2c_init/Cargo.lock
generated
187
examples/rp2040_local_i2c_init/Cargo.lock
generated
|
@ -10,9 +10,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
|||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c314e70d181aa6053b26e3f7fbf86d1dfff84f816a6175b967666b3506ef7289"
|
||||
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
@ -52,7 +52,7 @@ checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
|||
dependencies = [
|
||||
"bare-metal 0.2.5",
|
||||
"bitfield",
|
||||
"embedded-hal",
|
||||
"embedded-hal 0.2.7",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
|
@ -73,23 +73,23 @@ checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-any"
|
||||
version = "2.4.3"
|
||||
version = "2.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df"
|
||||
checksum = "c01a5e1f881f6fb6099a7bdf949e946719fd4f1fefa56264890574febf0eb6d0"
|
||||
dependencies = [
|
||||
"debug-helper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||
|
||||
[[package]]
|
||||
name = "debug-helper"
|
||||
|
@ -99,9 +99,9 @@ checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
|
|||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-dma"
|
||||
|
@ -123,10 +123,64 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
|
||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-async"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "frunk"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11a351b59e12f97b4176ee78497dff72e4276fb1ceb13e19056aca7fa0206287"
|
||||
dependencies = [
|
||||
"frunk_core",
|
||||
"frunk_derives",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frunk_core"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af2469fab0bd07e64ccf0ad57a1438f63160c69b2e57f04a439653d68eb558d6"
|
||||
|
||||
[[package]]
|
||||
name = "frunk_derives"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e"
|
||||
dependencies = [
|
||||
"frunk_proc_macro_helpers",
|
||||
"quote",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "frunk_proc_macro_helpers"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35b54add839292b743aeda6ebedbd8b11e93404f902c56223e51b9ec18a13d2c"
|
||||
dependencies = [
|
||||
"frunk_core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fugit"
|
||||
|
@ -139,21 +193,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.28"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.28"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.28"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
|
@ -169,15 +223,15 @@ checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
|
@ -224,7 +278,7 @@ checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -238,15 +292,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.12"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.9"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -265,6 +319,12 @@ dependencies = [
|
|||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -274,7 +334,7 @@ dependencies = [
|
|||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -291,18 +351,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.29"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -315,11 +375,10 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|||
|
||||
[[package]]
|
||||
name = "rp-pico"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aab28f6f4e19cec2d61b64cdd685e69794b81c579fd3b765579c46018fe616d0"
|
||||
checksum = "6341771e6f8e5d130b2b3cbc23435b7847761adf198af09f4b2a60407d43bd56"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"fugit",
|
||||
"rp2040-boot2",
|
||||
|
@ -329,23 +388,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rp2040-boot2"
|
||||
version = "0.2.1"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c773ec49b836077aa144b58dc7654a243e1eecdb6cf0d25361ae7c7600fabd8"
|
||||
checksum = "7c92f344f63f950ee36cf4080050e4dce850839b9175da38f9d2ffb69b4dbb21"
|
||||
dependencies = [
|
||||
"crc-any",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-hal"
|
||||
version = "0.8.2"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1369bb84862d7f69391a96606b2f29a00bfce7f29a749e23d5f01fc3f607ada0"
|
||||
checksum = "1ff2b9ae7e6dd6720fd9f64250c9087260e50fe98b6b032ccca65be3581167ca"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"embedded-dma",
|
||||
"embedded-hal",
|
||||
"embedded-hal 0.2.7",
|
||||
"frunk",
|
||||
"fugit",
|
||||
"itertools",
|
||||
"nb 1.1.0",
|
||||
|
@ -368,17 +428,18 @@ dependencies = [
|
|||
"cortex-m-rt",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-pac"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9192cafbb40d717c9e0ddf767aaf9c69fee1b4e48d22ed853b57b11f6d9f3d7e"
|
||||
checksum = "12d9d8375815f543f54835d01160d4e47f9e2cae75f17ff8f1ec19ce1da96e4c"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
|
@ -387,7 +448,7 @@ name = "rp2040_local_i2c_init"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"embedded-hal",
|
||||
"embedded-hal 0.2.7",
|
||||
"fugit",
|
||||
"panic-probe",
|
||||
"rp-pico",
|
||||
|
@ -397,7 +458,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"bare-metal 1.0.0",
|
||||
|
@ -409,9 +470,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-common"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -422,22 +484,23 @@ checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
|||
|
||||
[[package]]
|
||||
name = "rtic-macros"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-hal 1.0.0",
|
||||
"fugit",
|
||||
"rp2040-pac",
|
||||
"rtic-time",
|
||||
|
@ -445,9 +508,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"fugit",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
@ -494,10 +560,21 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
name = "syn"
|
||||
version = "2.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
|
@ -525,9 +602,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
|||
|
||||
[[package]]
|
||||
name = "volatile-register"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
|
||||
checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
|
||||
dependencies = [
|
||||
"vcell",
|
||||
]
|
||||
|
|
|
@ -15,14 +15,14 @@ features = ["thumbv6-backend"]
|
|||
|
||||
[dependencies.rtic-monotonics]
|
||||
path = "../../rtic-monotonics"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
features = ["rp2040"]
|
||||
|
||||
[dependencies]
|
||||
cortex-m = "0.7"
|
||||
embedded-hal = { version = "0.2.7", features = ["unproven"] }
|
||||
fugit = "0.3"
|
||||
rp-pico = "0.7.0"
|
||||
rp-pico = "0.8.0"
|
||||
panic-probe = "0.3"
|
||||
|
||||
[profile.dev]
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[rtic::app(
|
||||
device = rp_pico::hal::pac,
|
||||
dispatchers = [TIMER_IRQ_1]
|
||||
)]
|
||||
use rtic_monotonics::rp2040::prelude::*;
|
||||
|
||||
rp2040_timer_monotonic!(Mono);
|
||||
|
||||
#[rtic::app(device = rp_pico::hal::pac)]
|
||||
mod app {
|
||||
use super::*;
|
||||
|
||||
use rp_pico::hal::{
|
||||
clocks, gpio,
|
||||
gpio::pin::bank0::{Gpio2, Gpio25, Gpio3},
|
||||
gpio::pin::PushPullOutput,
|
||||
clocks,
|
||||
gpio::{
|
||||
self,
|
||||
bank0::{Gpio2, Gpio25, Gpio3},
|
||||
FunctionSioOutput, PullNone, PullUp,
|
||||
},
|
||||
pac,
|
||||
sio::Sio,
|
||||
watchdog::Watchdog,
|
||||
|
@ -20,15 +26,13 @@ mod app {
|
|||
use core::mem::MaybeUninit;
|
||||
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
|
||||
use fugit::RateExtU32;
|
||||
use rtic_monotonics::rp2040::*;
|
||||
|
||||
use panic_probe as _;
|
||||
|
||||
type I2CBus = I2C<
|
||||
pac::I2C1,
|
||||
(
|
||||
gpio::Pin<Gpio2, gpio::FunctionI2C>,
|
||||
gpio::Pin<Gpio3, gpio::FunctionI2C>,
|
||||
gpio::Pin<Gpio2, gpio::FunctionI2C, PullUp>,
|
||||
gpio::Pin<Gpio3, gpio::FunctionI2C, PullUp>,
|
||||
),
|
||||
>;
|
||||
|
||||
|
@ -37,7 +41,7 @@ mod app {
|
|||
|
||||
#[local]
|
||||
struct Local {
|
||||
led: gpio::Pin<Gpio25, PushPullOutput>,
|
||||
led: gpio::Pin<Gpio25, FunctionSioOutput, PullNone>,
|
||||
i2c: &'static mut I2CBus,
|
||||
}
|
||||
|
||||
|
@ -48,11 +52,8 @@ mod app {
|
|||
i2c_ctx: MaybeUninit<I2CBus> = MaybeUninit::uninit()
|
||||
])]
|
||||
fn init(mut ctx: init::Context) -> (Shared, Local) {
|
||||
// Initialize the interrupt for the RP2040 timer and obtain the token
|
||||
// proving that we have.
|
||||
let rp2040_timer_token = rtic_monotonics::create_rp2040_monotonic_token!();
|
||||
// Configure the clocks, watchdog - The default is to generate a 125 MHz system clock
|
||||
Timer::start(ctx.device.TIMER, &mut ctx.device.RESETS, rp2040_timer_token); // default rp2040 clock-rate is 125MHz
|
||||
Mono::start(ctx.device.TIMER, &mut ctx.device.RESETS); // default rp2040 clock-rate is 125MHz
|
||||
let mut watchdog = Watchdog::new(ctx.device.WATCHDOG);
|
||||
let clocks = clocks::init_clocks_and_plls(
|
||||
XOSC_CRYSTAL_FREQ,
|
||||
|
@ -74,12 +75,21 @@ mod app {
|
|||
sio.gpio_bank0,
|
||||
&mut ctx.device.RESETS,
|
||||
);
|
||||
let mut led = gpioa.led.into_push_pull_output();
|
||||
let mut led = gpioa
|
||||
.led
|
||||
.into_pull_type::<PullNone>()
|
||||
.into_push_pull_output();
|
||||
led.set_low().unwrap();
|
||||
|
||||
// Init I2C pins
|
||||
let sda_pin = gpioa.gpio2.into_mode::<gpio::FunctionI2C>();
|
||||
let scl_pin = gpioa.gpio3.into_mode::<gpio::FunctionI2C>();
|
||||
let sda_pin = gpioa
|
||||
.gpio2
|
||||
.into_pull_up_disabled()
|
||||
.into_function::<gpio::FunctionI2C>();
|
||||
let scl_pin = gpioa
|
||||
.gpio3
|
||||
.into_pull_up_disabled()
|
||||
.into_function::<gpio::FunctionI2C>();
|
||||
|
||||
// Init I2C itself, using MaybeUninit to overwrite the previously
|
||||
// uninitialized i2c_ctx variable without dropping its value
|
||||
|
@ -118,7 +128,7 @@ mod app {
|
|||
// now to do something with it!
|
||||
|
||||
// Delay for 1 second
|
||||
Timer::delay(1000.millis()).await;
|
||||
Mono::delay(1000.millis()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
118
examples/stm32f3_blinky/Cargo.lock
generated
118
examples/stm32f3_blinky/Cargo.lock
generated
|
@ -52,11 +52,12 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
|||
|
||||
[[package]]
|
||||
name = "bxcan"
|
||||
version = "0.6.2"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b13b4b2ea9ab2ba924063ebb86ad895cb79f4a79bf90f27949eb20c335b30f9"
|
||||
checksum = "40ac3d0c0a542d0ab5521211f873f62706a7136df415676f676d347e5a41dd80"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"embedded-hal 0.2.7",
|
||||
"nb 1.1.0",
|
||||
"vcell",
|
||||
]
|
||||
|
@ -86,7 +87,7 @@ dependencies = [
|
|||
"bare-metal 0.2.5",
|
||||
"bitfield",
|
||||
"critical-section",
|
||||
"embedded-hal",
|
||||
"embedded-hal 0.2.7",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
|
@ -112,9 +113,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
|
@ -136,7 +137,7 @@ dependencies = [
|
|||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -147,7 +148,7 @@ checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
|||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -169,6 +170,21 @@ dependencies = [
|
|||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-async"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-time"
|
||||
version = "0.12.1"
|
||||
|
@ -180,9 +196,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "enumset"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e875f1719c16de097dee81ed675e2d9bb63096823ed3f0ca827b7dea3028bbbb"
|
||||
checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d"
|
||||
dependencies = [
|
||||
"enumset_derive",
|
||||
]
|
||||
|
@ -196,7 +212,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.22",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -343,28 +359,28 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "panic-rtt-target"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6ab67bc881453e4c90f958c657c1303670ea87bc1a16e87fd71a40f656dce9"
|
||||
checksum = "608d1d809dd8960d5e8364981279c7ab280a13d98b99eae049885a7ab2b1cbfe"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"rtt-target 0.3.1",
|
||||
"critical-section",
|
||||
"rtt-target",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.12"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
|
||||
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
|
@ -378,6 +394,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -404,18 +426,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.63"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.29"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -431,7 +453,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"bare-metal 1.0.0",
|
||||
|
@ -443,9 +465,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-common"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -456,49 +479,44 @@ checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
|||
|
||||
[[package]]
|
||||
name = "rtic-macros"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.50",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-hal 1.0.0",
|
||||
"fugit",
|
||||
"rtic-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"fugit",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtt-target"
|
||||
version = "0.3.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b"
|
||||
dependencies = [
|
||||
"ufmt-write",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtt-target"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3afa12c77ba1b9bf560e4039a9b9a08bb9cde0e9e6923955eeb917dd8d5cf303"
|
||||
checksum = "10b34c9e6832388e45f3c01f1bb60a016384a0a4ad80cdd7d34913bed25037f0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"ufmt-write",
|
||||
|
@ -553,9 +571,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stm32f3"
|
||||
version = "0.14.0"
|
||||
version = "0.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "265cda62ac13307414de4aca58dbbbd8038ddba85cffbb335823aa216f2e3200"
|
||||
checksum = "b28b37228ef3fa47956af38c6abd756e912f244c1657f14e66d42fc8d74ea96f"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
|
@ -567,30 +585,32 @@ dependencies = [
|
|||
name = "stm32f3-blinky"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"cortex-m",
|
||||
"embedded-hal 0.2.7",
|
||||
"panic-rtt-target",
|
||||
"rtic",
|
||||
"rtic-monotonics",
|
||||
"rtt-target 0.4.0",
|
||||
"rtt-target",
|
||||
"stm32f3xx-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32f3xx-hal"
|
||||
version = "0.9.2"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c9d827f02df3826371c897404dfbea8a1abd544eed9d6cdc3e5f6e9f04b9e06"
|
||||
checksum = "4c73e8b6e63435b75198d2fe2b27cd7f5c8e0b07bd5da9f82cffddf23210f77f"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"bxcan",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"critical-section",
|
||||
"embedded-dma",
|
||||
"embedded-hal",
|
||||
"embedded-hal 0.2.7",
|
||||
"embedded-time",
|
||||
"enumset",
|
||||
"nb 1.1.0",
|
||||
"num-traits",
|
||||
"paste",
|
||||
"rtcc",
|
||||
"slice-group-by",
|
||||
|
@ -612,9 +632,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.22"
|
||||
version = "2.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616"
|
||||
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
@ -14,17 +14,21 @@ features = ["thumbv7-backend"]
|
|||
|
||||
[dependencies.rtic-monotonics]
|
||||
path = "../../rtic-monotonics"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
features = ["cortex-m-systick"]
|
||||
|
||||
[dependencies.cortex-m]
|
||||
version = "0.7.7"
|
||||
features = ["critical-section-single-core"]
|
||||
|
||||
[dependencies]
|
||||
embedded-hal = "0.2.7"
|
||||
panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
|
||||
rtt-target = { version = "0.4.0" }
|
||||
panic-rtt-target = { version = "0.1.3" }
|
||||
rtt-target = { version = "0.5.0" }
|
||||
|
||||
[dependencies.stm32f3xx-hal]
|
||||
features = ["stm32f303xc", "rt"]
|
||||
version = "0.9.2"
|
||||
version = "0.10.0"
|
||||
|
||||
# this lets you use `cargo fix`!
|
||||
[[bin]]
|
||||
|
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
use panic_rtt_target as _;
|
||||
use rtic::app;
|
||||
use rtic_monotonics::systick::*;
|
||||
use rtic_monotonics::systick::prelude::*;
|
||||
use rtt_target::{rprintln, rtt_init_print};
|
||||
use stm32f3xx_hal::gpio::{Output, PushPull, PA5};
|
||||
use stm32f3xx_hal::prelude::*;
|
||||
|
||||
systick_monotonic!(Mono, 1000);
|
||||
|
||||
#[app(device = stm32f3xx_hal::pac, peripherals = true, dispatchers = [SPI1])]
|
||||
mod app {
|
||||
use super::*;
|
||||
|
@ -30,8 +32,7 @@ mod app {
|
|||
let mut rcc = cx.device.RCC.constrain();
|
||||
|
||||
// Initialize the systick interrupt & obtain the token to prove that we did
|
||||
let systick_mono_token = rtic_monotonics::create_systick_token!();
|
||||
Systick::start(cx.core.SYST, 36_000_000, systick_mono_token); // default STM32F303 clock-rate is 36MHz
|
||||
Mono::start(cx.core.SYST, 36_000_000); // default STM32F303 clock-rate is 36MHz
|
||||
|
||||
rtt_init_print!();
|
||||
rprintln!("init");
|
||||
|
@ -67,7 +68,7 @@ mod app {
|
|||
cx.local.led.set_low().unwrap();
|
||||
*cx.local.state = true;
|
||||
}
|
||||
Systick::delay(1000.millis()).await;
|
||||
Mono::delay(1000.millis()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
examples/stm32g030f6_periodic_prints/.cargo/config.toml
Normal file
24
examples/stm32g030f6_periodic_prints/.cargo/config.toml
Normal file
|
@ -0,0 +1,24 @@
|
|||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# TODO(2) replace `$CHIP` with your chip's name (see `probe-run --list-chips` output)
|
||||
runner = "probe-run --chip STM32G030F6Px"
|
||||
rustflags = [
|
||||
"-C", "linker=flip-link",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||
"-C", "link-arg=--nmagic",
|
||||
]
|
||||
|
||||
[build]
|
||||
# TODO(3) Adjust the compilation target.
|
||||
# (`thumbv6m-*` is compatible with all ARM Cortex-M chips but using the right
|
||||
# target improves performance)
|
||||
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||
|
||||
[alias]
|
||||
rb = "run --bin"
|
||||
rrb = "run --release --bin"
|
9
examples/stm32g030f6_periodic_prints/.vscode/settings.json
vendored
Normal file
9
examples/stm32g030f6_periodic_prints/.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
// override the default setting (`cargo check --all-targets`) which produces the following error
|
||||
// "can't find crate for `test`" when the default compilation target is a no_std target
|
||||
// with these changes RA will call `cargo check --bins` on save
|
||||
"rust-analyzer.checkOnSave.allTargets": false,
|
||||
"rust-analyzer.checkOnSave.extraArgs": [
|
||||
"--bins"
|
||||
]
|
||||
}
|
511
examples/stm32g030f6_periodic_prints/Cargo.lock
generated
Normal file
511
examples/stm32g030f6_periodic_prints/Cargo.lock
generated
Normal file
|
@ -0,0 +1,511 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "atomic-polyfill"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||
dependencies = [
|
||||
"bare-metal 0.2.5",
|
||||
"bitfield",
|
||||
"critical-section",
|
||||
"embedded-hal 0.2.7",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
|
||||
dependencies = [
|
||||
"cortex-m-rt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt-macros"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
|
||||
|
||||
[[package]]
|
||||
name = "defmt"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3939552907426de152b3c2c6f51ed53f98f448babd26f28694c95f5906194595"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"defmt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-macros"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18bdc7a7b92ac413e19e95240e75d3a73a8d8e78aa24a594c22cbb4d44b4bbda"
|
||||
dependencies = [
|
||||
"defmt-parser",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-parser"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f"
|
||||
dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "defmt-rtt"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "609923761264dd99ed9c7d209718cda4631c5fe84668e0f0960124cbb844c49f"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||
dependencies = [
|
||||
"nb 0.1.3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-async"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fugit"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7"
|
||||
dependencies = [
|
||||
"gcd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcd"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||
|
||||
[[package]]
|
||||
name = "panic-probe"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"defmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"rtic-core",
|
||||
"rtic-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-common"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-core"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
|
||||
|
||||
[[package]]
|
||||
name = "rtic-macros"
|
||||
version = "2.0.1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-hal 1.0.0",
|
||||
"fugit",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rtic-time",
|
||||
"stm32-metapac",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0",
|
||||
"embedded-hal-async",
|
||||
"fugit",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "stm32-metapac"
|
||||
version = "15.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deabea56a8821dcea05d0109f3ab3135f31eb572444e5da203d06149c594c8c6"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32g0"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfc2ac544cea741c92a501bfd027d197354cd22ee92b439aea26d2ee0b55bcd7"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32g030f6_periodic_prints"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"defmt",
|
||||
"defmt-rtt",
|
||||
"fugit",
|
||||
"panic-probe",
|
||||
"rtic",
|
||||
"rtic-monotonics",
|
||||
"stm32g0xx-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stm32g0xx-hal"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fae457e81f9601121c5b92dca20e3612c80ea957898f8e0e68efcaab6b242067"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cortex-m",
|
||||
"embedded-hal 0.2.7",
|
||||
"fugit",
|
||||
"nb 1.1.0",
|
||||
"stm32g0",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.51",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "volatile-register"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
|
||||
dependencies = [
|
||||
"vcell",
|
||||
]
|
48
examples/stm32g030f6_periodic_prints/Cargo.toml
Normal file
48
examples/stm32g030f6_periodic_prints/Cargo.toml
Normal file
|
@ -0,0 +1,48 @@
|
|||
[package]
|
||||
authors = ["Finomnis <finomnis@gmail.com>"]
|
||||
name = "stm32g030f6_periodic_prints"
|
||||
edition = "2021"
|
||||
version = "0.1.0"
|
||||
|
||||
[workspace]
|
||||
|
||||
|
||||
[dependencies.rtic]
|
||||
path = "../../rtic"
|
||||
version = "2.0.1"
|
||||
features = ["thumbv6-backend"]
|
||||
|
||||
[dependencies.rtic-monotonics]
|
||||
path = "../../rtic-monotonics"
|
||||
version = "2.0.0"
|
||||
features = ["stm32g030f6", "stm32_tim3"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7.3"
|
||||
defmt = "0.3.4"
|
||||
defmt-rtt = "0.4.0"
|
||||
fugit = "0.3.7"
|
||||
panic-probe = { version = "0.3.1", features = ["print-defmt"] }
|
||||
|
||||
stm32g0xx-hal = { version = "0.2.0", features = ["rt", "stm32g030"] }
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
31
examples/stm32g030f6_periodic_prints/README.md
Normal file
31
examples/stm32g030f6_periodic_prints/README.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# `stm32g030f6_periodic_prints`
|
||||
|
||||
An RTIC periodic print example intended for the stm32g030f6 chip.
|
||||
|
||||
## Dependencies
|
||||
|
||||
#### 1. `flip-link`:
|
||||
|
||||
```console
|
||||
$ cargo install flip-link
|
||||
```
|
||||
|
||||
#### 2. `probe-rs`:
|
||||
|
||||
``` console
|
||||
$ # make sure to install v0.2.0 or later
|
||||
$ cargo install probe-rs --features cli
|
||||
```
|
||||
|
||||
|
||||
## Run
|
||||
|
||||
The stm32g030f6 chip needs to be connected to the computer via an SWD probe, like a [J-Link EDU Mini].
|
||||
|
||||
Then, run:
|
||||
|
||||
```
|
||||
cargo run --release
|
||||
```
|
||||
|
||||
[J-Link EDU Mini]: https://www.segger.com/products/debug-probes/j-link/models/j-link-edu-mini/
|
6
examples/stm32g030f6_periodic_prints/memory.x
Normal file
6
examples/stm32g030f6_periodic_prints/memory.x
Normal file
|
@ -0,0 +1,6 @@
|
|||
/* Linker script for the STM32G030F6 */
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x08000000, LENGTH = 32K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 8K
|
||||
}
|
57
examples/stm32g030f6_periodic_prints/src/main.rs
Normal file
57
examples/stm32g030f6_periodic_prints/src/main.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
#![deny(unsafe_code)]
|
||||
#![deny(warnings)]
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use defmt_rtt as _; // global logger
|
||||
|
||||
pub use stm32g0xx_hal as hal; // memory layout
|
||||
|
||||
use panic_probe as _;
|
||||
|
||||
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
|
||||
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
|
||||
#[defmt::panic_handler]
|
||||
fn panic() -> ! {
|
||||
cortex_m::asm::udf()
|
||||
}
|
||||
|
||||
use rtic_monotonics::stm32::prelude::*;
|
||||
stm32_tim3_monotonic!(Mono, 1_000_000);
|
||||
|
||||
#[rtic::app(device = hal::stm32, peripherals = true, dispatchers = [USART1, USART2])]
|
||||
mod app {
|
||||
use super::*;
|
||||
|
||||
#[local]
|
||||
struct LocalResources {}
|
||||
|
||||
#[shared]
|
||||
struct SharedResources {}
|
||||
|
||||
#[init]
|
||||
fn init(ctx: init::Context) -> (SharedResources, LocalResources) {
|
||||
// enable dma clock during sleep, otherwise defmt doesn't work
|
||||
ctx.device.RCC.ahbenr.modify(|_, w| w.dmaen().set_bit());
|
||||
|
||||
defmt::println!("TIM Monotonic blinker example!");
|
||||
|
||||
// Start the monotonic
|
||||
Mono::start(16_000_000);
|
||||
|
||||
print_messages::spawn().unwrap();
|
||||
|
||||
(SharedResources {}, LocalResources {})
|
||||
}
|
||||
|
||||
#[task(priority = 2)]
|
||||
async fn print_messages(_cx: print_messages::Context) {
|
||||
let mut next_update = <Mono as Monotonic>::Instant::from_ticks(0u64);
|
||||
|
||||
loop {
|
||||
defmt::println!("Time: {} ticks", Mono::now().ticks());
|
||||
next_update += 1000u64.millis();
|
||||
Mono::delay_until(next_update).await;
|
||||
}
|
||||
}
|
||||
}
|
22
examples/teensy4_blinky/Cargo.lock
generated
22
examples/teensy4_blinky/Cargo.lock
generated
|
@ -133,9 +133,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "1.0.0-rc.2"
|
||||
version = "1.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e57ec6ad0bc8eb967cf9c9f144177f5e8f2f6f02dad0b8b683f9f05f6b22def"
|
||||
checksum = "bc402f79e1fd22731ca945b4f97b5ff37e7b3f379312595c42bb2e8811c29920"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal-async"
|
||||
version = "1.0.0-rc.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa1fba2ef2ffb35d614acc6fb323ddf7facc45c069f24544d49ea54e5043626d"
|
||||
dependencies = [
|
||||
"embedded-hal 1.0.0-rc.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
|
@ -440,12 +449,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.4.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"atomic-polyfill",
|
||||
"cfg-if",
|
||||
"cortex-m",
|
||||
"embedded-hal 1.0.0-rc.2",
|
||||
"embedded-hal 1.0.0-rc.3",
|
||||
"fugit",
|
||||
"imxrt-ral",
|
||||
"rtic-time",
|
||||
|
@ -453,9 +462,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rtic-time"
|
||||
version = "1.1.0"
|
||||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"embedded-hal 1.0.0-rc.3",
|
||||
"embedded-hal-async",
|
||||
"fugit",
|
||||
"futures-util",
|
||||
"rtic-common",
|
||||
]
|
||||
|
|
|
@ -14,7 +14,7 @@ features = ["thumbv7-backend"]
|
|||
|
||||
[dependencies.rtic-monotonics]
|
||||
path = "../../rtic-monotonics"
|
||||
version = "1.2.1"
|
||||
version = "2.0.0"
|
||||
features = ["imxrt_gpt1"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -13,9 +13,8 @@ use bsp::logging;
|
|||
|
||||
use embedded_hal::serial::Write;
|
||||
|
||||
use rtic_monotonics::imxrt::Gpt1 as Mono;
|
||||
use rtic_monotonics::imxrt::*;
|
||||
use rtic_monotonics::Monotonic;
|
||||
use rtic_monotonics::imxrt::prelude::*;
|
||||
imxrt_gpt1_monotonic!(Mono, board::PERCLK_FREQUENCY);
|
||||
|
||||
#[rtic::app(device = teensy4_bsp, dispatchers = [LPSPI1])]
|
||||
mod app {
|
||||
|
@ -61,8 +60,7 @@ mod app {
|
|||
|
||||
// Initialize Monotonic
|
||||
gpt1.set_clock_source(hal::gpt::ClockSource::PeripheralClock);
|
||||
let gpt1_mono_token = rtic_monotonics::create_imxrt_gpt1_token!();
|
||||
Mono::start(board::PERCLK_FREQUENCY, gpt1.release(), gpt1_mono_token);
|
||||
Mono::start(gpt1.release());
|
||||
|
||||
// Setup LED
|
||||
let led = board::led(&mut gpio2, pins.p13);
|
||||
|
|
|
@ -10,8 +10,8 @@ fn panic(_: &::core::panic::PanicInfo) -> ! {
|
|||
|
||||
use teensy4_bsp::{board, hal};
|
||||
|
||||
use rtic_monotonics::imxrt::Gpt1 as Mono;
|
||||
use rtic_monotonics::imxrt::*;
|
||||
use rtic_monotonics::imxrt::prelude::*;
|
||||
imxrt_gpt1_monotonic!(Mono, board::PERCLK_FREQUENCY);
|
||||
|
||||
#[rtic::app(device = teensy4_bsp, dispatchers = [LPSPI1])]
|
||||
mod app {
|
||||
|
@ -36,8 +36,7 @@ mod app {
|
|||
|
||||
// Initialize Monotonic
|
||||
gpt1.set_clock_source(hal::gpt::ClockSource::PeripheralClock);
|
||||
let gpt1_mono_token = rtic_monotonics::create_imxrt_gpt1_token!();
|
||||
Mono::start(board::PERCLK_FREQUENCY, gpt1.release(), gpt1_mono_token);
|
||||
Mono::start(gpt1.release());
|
||||
|
||||
// Setup LED
|
||||
let led = board::led(&mut gpio2, pins.p13);
|
||||
|
|
|
@ -246,4 +246,3 @@ pub fn extra_modules(_app: &App, _analysis: &SyntaxAnalysis) -> Vec<TokenStream2
|
|||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||
|
||||
## Unreleased
|
||||
## Unreleased - v2.0.0
|
||||
|
||||
### Changed
|
||||
|
||||
- Rework all timers based on `rtic-time 2.0.0`
|
||||
- Most timer tick rates are now configurable
|
||||
- Tweak `build.rs` to avoid warnings in Nightly 1.78+
|
||||
- Removed unused `rust-toolchain.toml`
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rtic-monotonics"
|
||||
version = "1.5.0"
|
||||
version = "2.0.0"
|
||||
|
||||
edition = "2021"
|
||||
authors = [
|
||||
|
@ -24,13 +24,17 @@ features = [
|
|||
"imxrt_gpt1",
|
||||
"imxrt_gpt2",
|
||||
"imxrt-ral/imxrt1011",
|
||||
"stm32h725ag",
|
||||
"stm32_tim2",
|
||||
"stm32_tim3",
|
||||
"stm32_tim4",
|
||||
"stm32_tim5",
|
||||
"stm32_tim15",
|
||||
]
|
||||
rustdoc-flags = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
rtic-time = { version = "1.1.0", path = "../rtic-time" }
|
||||
embedded-hal = { version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0", optional = true }
|
||||
rtic-time = { version = "2.0.0", path = "../rtic-time" }
|
||||
fugit = { version = "0.3.6" }
|
||||
atomic-polyfill = "1"
|
||||
cfg-if = "1.0.0"
|
||||
|
@ -69,8 +73,6 @@ defmt = ["fugit/defmt"]
|
|||
|
||||
# Systick on Cortex-M, default 1 kHz
|
||||
cortex-m-systick = ["dep:cortex-m"]
|
||||
systick-100hz = []
|
||||
systick-10khz = []
|
||||
# Use 64-bit wide backing storage for the Instant
|
||||
systick-64bit = []
|
||||
|
||||
|
@ -99,7 +101,6 @@ stm32_tim2 = []
|
|||
stm32_tim3 = []
|
||||
stm32_tim4 = []
|
||||
stm32_tim5 = []
|
||||
stm32_tim12 = []
|
||||
stm32_tim15 = []
|
||||
|
||||
stm32-metapac = ["dep:stm32-metapac", "dep:quote", "dep:proc-macro2"]
|
||||
|
|
|
@ -1,112 +1,158 @@
|
|||
//! [`Monotonic`] implementations for i.MX RT's GPT peripherals.
|
||||
//! [`Monotonic`](rtic_time::Monotonic) implementations for i.MX RT's GPT peripherals.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use rtic_monotonics::imxrt::*;
|
||||
//! use rtic_monotonics::imxrt::Gpt1 as Mono;
|
||||
//! use rtic_monotonics::imxrt::prelude::*;
|
||||
//! imxrt_gpt1_monotonic!(Mono, 1_000_000);
|
||||
//!
|
||||
//! fn init() {
|
||||
//! // Obtain ownership of the timer register block
|
||||
//! // Obtain ownership of the timer register block.
|
||||
//! let gpt1 = unsafe { imxrt_ral::gpt::GPT1::instance() };
|
||||
//!
|
||||
//! // Configure the timer clock source and determine its tick rate
|
||||
//! let timer_tickrate_hz = 1_000_000;
|
||||
//!
|
||||
//! // Generate timer token to ensure correct timer interrupt handler is used
|
||||
//! let token = rtic_monotonics::create_imxrt_gpt1_token!();
|
||||
//! // Configure the timer tick rate as specified earlier
|
||||
//! todo!("Configure the gpt1 peripheral to a tick rate of 1_000_000");
|
||||
//!
|
||||
//! // Start the monotonic
|
||||
//! Mono::start(timer_tickrate_hz, gpt1, token);
|
||||
//! Mono::start(gpt1);
|
||||
//! }
|
||||
//!
|
||||
//! async fn usage() {
|
||||
//! loop {
|
||||
//! // Use the monotonic
|
||||
//! let timestamp = Mono::now().ticks();
|
||||
//! let timestamp = Mono::now();
|
||||
//! Mono::delay(100.millis()).await;
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::{Monotonic, TimeoutError, TimerQueue};
|
||||
use atomic_polyfill::{AtomicU32, Ordering};
|
||||
use rtic_time::{
|
||||
half_period_counter::calculate_now,
|
||||
timer_queue::{TimerQueue, TimerQueueBackend},
|
||||
};
|
||||
|
||||
pub use imxrt_ral as ral;
|
||||
|
||||
/// Common definitions and traits for using the i.MX RT monotonics
|
||||
pub mod prelude {
|
||||
#[cfg(feature = "imxrt_gpt1")]
|
||||
pub use crate::imxrt_gpt1_monotonic;
|
||||
#[cfg(feature = "imxrt_gpt2")]
|
||||
pub use crate::imxrt_gpt2_monotonic;
|
||||
|
||||
pub use crate::Monotonic;
|
||||
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||
use rtic_time::half_period_counter::calculate_now;
|
||||
|
||||
use imxrt_ral as ral;
|
||||
|
||||
const TIMER_HZ: u32 = 1_000_000;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_create_imxrt_timer_interrupt {
|
||||
($mono_timer:ident, $timer:ident, $timer_token:ident) => {{
|
||||
($mono_backend:ident, $timer:ident) => {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn $timer() {
|
||||
$crate::imxrt::$mono_timer::__tq().on_monotonic_interrupt();
|
||||
use $crate::TimerQueueBackend;
|
||||
$crate::imxrt::$mono_backend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct $timer_token;
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_create_imxrt_timer_struct {
|
||||
($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
|
||||
/// A `Monotonic` based on the GPT peripheral.
|
||||
struct $name;
|
||||
|
||||
unsafe impl $crate::InterruptToken<$crate::imxrt::$mono_timer> for $timer_token {}
|
||||
impl $name {
|
||||
/// Starts the `Monotonic`.
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(gpt: $crate::imxrt::ral::gpt::$timer) {
|
||||
$crate::__internal_create_imxrt_timer_interrupt!($mono_backend, $timer);
|
||||
|
||||
$timer_token
|
||||
}};
|
||||
$crate::imxrt::$mono_backend::_start(gpt);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register the GPT1 interrupt for the monotonic.
|
||||
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||
type Backend = $crate::imxrt::$mono_backend;
|
||||
type Instant = $crate::fugit::Instant<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
type Duration = $crate::fugit::Duration<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
}
|
||||
|
||||
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a GPT1 based monotonic and register the GPT1 interrupt for it.
|
||||
///
|
||||
/// See [`crate::imxrt`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral. It's the user's responsibility
|
||||
/// to configure the peripheral to the given frequency before starting the
|
||||
/// monotonic.
|
||||
#[cfg(feature = "imxrt_gpt1")]
|
||||
#[macro_export]
|
||||
macro_rules! create_imxrt_gpt1_token {
|
||||
() => {{
|
||||
$crate::__internal_create_imxrt_timer_interrupt!(Gpt1, GPT1, Gpt1Token)
|
||||
}};
|
||||
macro_rules! imxrt_gpt1_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_imxrt_timer_struct!($name, Gpt1Backend, GPT1, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register the GPT2 interrupt for the monotonic.
|
||||
/// Create a GPT2 based monotonic and register the GPT2 interrupt for it.
|
||||
///
|
||||
/// See [`crate::imxrt`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral. It's the user's responsibility
|
||||
/// to configure the peripheral to the given frequency before starting the
|
||||
/// monotonic.
|
||||
#[cfg(feature = "imxrt_gpt2")]
|
||||
#[macro_export]
|
||||
macro_rules! create_imxrt_gpt2_token {
|
||||
() => {{
|
||||
$crate::__internal_create_imxrt_timer_interrupt!(Gpt2, GPT2, Gpt2Token)
|
||||
}};
|
||||
macro_rules! imxrt_gpt2_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_imxrt_timer_struct!($name, Gpt2Backend, GPT2, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! make_timer {
|
||||
($mono_name:ident, $timer:ident, $period:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// Timer implementing [`Monotonic`] which runs at 1 MHz.
|
||||
($mono_name:ident, $backend_name:ident, $timer:ident, $period:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// GPT based [`TimerQueueBackend`].
|
||||
$(
|
||||
#[cfg_attr(docsrs, doc(cfg($($doc)*)))]
|
||||
)?
|
||||
|
||||
pub struct $mono_name;
|
||||
pub struct $backend_name;
|
||||
|
||||
use ral::gpt::$timer;
|
||||
|
||||
/// Number of 2^31 periods elapsed since boot.
|
||||
static $period: AtomicU32 = AtomicU32::new(0);
|
||||
static $tq: TimerQueue<$mono_name> = TimerQueue::new();
|
||||
static $tq: TimerQueue<$backend_name> = TimerQueue::new();
|
||||
|
||||
impl $mono_name {
|
||||
/// Starts the monotonic timer.
|
||||
impl $backend_name {
|
||||
/// Starts the timer.
|
||||
///
|
||||
/// - `tick_freq_hz`: The tick frequency of the given timer.
|
||||
/// - `gpt`: The GPT timer register block instance.
|
||||
/// - `_interrupt_token`: Required for correct timer interrupt handling.
|
||||
/// **Do not use this function directly.**
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(tick_freq_hz: u32, gpt: $timer, _interrupt_token: impl crate::InterruptToken<Self>) {
|
||||
// Find a prescaler that creates our desired tick frequency
|
||||
let previous_prescaler = ral::read_reg!(ral::gpt, gpt, PR, PRESCALER) + 1;
|
||||
let previous_clock_freq = tick_freq_hz * previous_prescaler;
|
||||
assert!((previous_clock_freq % TIMER_HZ) == 0,
|
||||
"Unable to find a fitting prescaler value!\n Input: {}/{}\n Desired: {}",
|
||||
previous_clock_freq, previous_prescaler, TIMER_HZ);
|
||||
let prescaler = previous_clock_freq / TIMER_HZ;
|
||||
assert!(prescaler > 0);
|
||||
assert!(prescaler <= 4096);
|
||||
/// Use the prelude macros instead.
|
||||
pub fn _start(gpt: $timer) {
|
||||
|
||||
// Disable the timer.
|
||||
ral::modify_reg!(ral::gpt, gpt, CR, EN: 0);
|
||||
|
@ -122,11 +168,6 @@ macro_rules! make_timer {
|
|||
// Reset period
|
||||
$period.store(0, Ordering::SeqCst);
|
||||
|
||||
// Prescaler
|
||||
ral::modify_reg!(ral::gpt, gpt, PR,
|
||||
PRESCALER: (prescaler - 1), // Scale to our desired clock rate
|
||||
);
|
||||
|
||||
// Enable interrupts
|
||||
ral::write_reg!(ral::gpt, gpt, IR,
|
||||
ROVIE: 1, // Rollover interrupt
|
||||
|
@ -150,7 +191,6 @@ macro_rules! make_timer {
|
|||
ENMOD: 0, // Keep state when disabled
|
||||
);
|
||||
|
||||
|
||||
// SAFETY: We take full ownership of the peripheral and interrupt vector,
|
||||
// plus we are not using any external shared resources so we won't impact
|
||||
// basepri/source masking based critical sections.
|
||||
|
@ -159,65 +199,21 @@ macro_rules! make_timer {
|
|||
cortex_m::peripheral::NVIC::unmask(ral::Interrupt::$timer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to access the underlying timer queue
|
||||
#[doc(hidden)]
|
||||
pub fn __tq() -> &'static TimerQueue<$mono_name> {
|
||||
&$tq
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
$tq.delay(duration).await;
|
||||
}
|
||||
impl TimerQueueBackend for $backend_name {
|
||||
type Ticks = u64;
|
||||
|
||||
/// Timeout at a specific time.
|
||||
pub async fn timeout_at<F: core::future::Future>(
|
||||
instant: <Self as rtic_time::Monotonic>::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_at(instant, future).await
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: core::future::Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_after(duration, future).await
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
#[inline]
|
||||
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||
$tq.delay_until(instant).await;
|
||||
}
|
||||
}
|
||||
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!($mono_name);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!($mono_name);
|
||||
|
||||
impl Monotonic for $mono_name {
|
||||
type Instant = fugit::TimerInstantU64<TIMER_HZ>;
|
||||
type Duration = fugit::TimerDurationU64<TIMER_HZ>;
|
||||
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
fn now() -> Self::Ticks {
|
||||
let gpt = unsafe{ $timer::instance() };
|
||||
|
||||
Self::Instant::from_ticks(calculate_now(
|
||||
calculate_now(
|
||||
|| $period.load(Ordering::Relaxed),
|
||||
|| ral::read_reg!(ral::gpt, gpt, CNT)
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Instant) {
|
||||
fn set_compare(instant: Self::Ticks) {
|
||||
let gpt = unsafe{ $timer::instance() };
|
||||
|
||||
// Set the timer regardless of whether it is multiple periods in the future,
|
||||
|
@ -225,8 +221,7 @@ macro_rules! make_timer {
|
|||
// The worst thing that can happen is a spurious wakeup, and with a timer
|
||||
// period of half an hour, this is hardly a problem.
|
||||
|
||||
let ticks = instant.duration_since_epoch().ticks();
|
||||
let ticks_wrapped = ticks as u32;
|
||||
let ticks_wrapped = instant as u32;
|
||||
|
||||
ral::write_reg!(ral::gpt, gpt, OCR[1], ticks_wrapped);
|
||||
}
|
||||
|
@ -257,12 +252,16 @@ macro_rules! make_timer {
|
|||
assert!(prev % 2 == 0, "Monotonic must have skipped an interrupt!");
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||
&$tq
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "imxrt_gpt1")]
|
||||
make_timer!(Gpt1, GPT1, GPT1_HALFPERIODS, GPT1_TQ);
|
||||
make_timer!(Gpt1, Gpt1Backend, GPT1, GPT1_HALFPERIODS, GPT1_TQ);
|
||||
|
||||
#[cfg(feature = "imxrt_gpt2")]
|
||||
make_timer!(Gpt2, GPT2, GPT2_HALFPERIODS, GPT2_TQ);
|
||||
make_timer!(Gpt2, Gpt2Backend, GPT2, GPT2_HALFPERIODS, GPT2_TQ);
|
||||
|
|
|
@ -21,14 +21,18 @@
|
|||
//! `Available on crate features X only` tag are available on any `nrf52*` feature.
|
||||
//!
|
||||
// To build these docs correctly:
|
||||
// RUSTFLAGS="--cfg docsrs" cargo doc --featuers cortex-m-systick,rp2040,nrf52840
|
||||
// RUSTFLAGS="--cfg docsrs" cargo +nightly doc --features thumbv7-backend,cortex-m-systick,rp2040,nrf52840,imxrt_gpt1,imxrt_gpt2,imxrt-ral/imxrt1011,stm32h725ag,stm32_tim2,stm32_tim3,stm32_tim4,stm32_tim5,stm32_tim15
|
||||
|
||||
#![no_std]
|
||||
#![deny(missing_docs)]
|
||||
#![allow(incomplete_features)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||
|
||||
pub use rtic_time::{Monotonic, TimeoutError, TimerQueue};
|
||||
pub use fugit;
|
||||
pub use rtic_time::{
|
||||
self, monotonic::TimerQueueBasedMonotonic, timer_queue::TimerQueueBackend, Monotonic,
|
||||
TimeoutError,
|
||||
};
|
||||
|
||||
#[cfg(feature = "cortex-m-systick")]
|
||||
pub mod systick;
|
||||
|
@ -92,13 +96,3 @@ pub(crate) unsafe fn set_monotonic_prio(
|
|||
|
||||
nvic.set_priority(interrupt, hw_prio);
|
||||
}
|
||||
|
||||
/// This marker is implemented on an interrupt token to enforce that the right tokens
|
||||
/// are given to the correct monotonic implementation.
|
||||
///
|
||||
/// This trait is implemented by this crate and not intended for user implementation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is only safely implemented by this crate.
|
||||
pub unsafe trait InterruptToken<Periperhal> {}
|
||||
|
|
|
@ -1,96 +1,152 @@
|
|||
//! [`Monotonic`] implementation for the nRF Real Time Clocks (RTC).
|
||||
//! [`Monotonic`](rtic_time::Monotonic) implementation for the nRF Real Time Clocks (RTC).
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use rtic_monotonics::nrf::rtc::*;
|
||||
//! use rtic_monotonics::nrf::rtc::prelude::*;
|
||||
//! nrf_rtc0_monotonic!(Mono);
|
||||
//!
|
||||
//! fn init() {
|
||||
//! # // This is normally provided by the selected PAC
|
||||
//! # let rtc = unsafe { core::mem::transmute(()) };
|
||||
//! // Generate the required token
|
||||
//! let token = rtic_monotonics::create_nrf_rtc0_monotonic_token!();
|
||||
//!
|
||||
//! // Start the monotonic
|
||||
//! Rtc0::start(rtc, token);
|
||||
//! Mono::start(rtc);
|
||||
//! }
|
||||
//!
|
||||
//! async fn usage() {
|
||||
//! loop {
|
||||
//! // Use the monotonic
|
||||
//! Rtc0::delay(100.millis()).await;
|
||||
//! let timestamp = Mono::now();
|
||||
//! Mono::delay(100.millis()).await;
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
#[cfg(feature = "nrf52810")]
|
||||
use nrf52810_pac::{self as pac, Interrupt, RTC0, RTC1};
|
||||
#[cfg(feature = "nrf52811")]
|
||||
use nrf52811_pac::{self as pac, Interrupt, RTC0, RTC1};
|
||||
#[cfg(feature = "nrf52832")]
|
||||
use nrf52832_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2};
|
||||
#[cfg(feature = "nrf52833")]
|
||||
use nrf52833_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2};
|
||||
#[cfg(feature = "nrf52840")]
|
||||
use nrf52840_pac::{self as pac, Interrupt, RTC0, RTC1, RTC2};
|
||||
#[cfg(feature = "nrf5340-app")]
|
||||
use nrf5340_app_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1};
|
||||
#[cfg(feature = "nrf5340-net")]
|
||||
use nrf5340_net_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1};
|
||||
#[cfg(feature = "nrf9160")]
|
||||
use nrf9160_pac::{self as pac, Interrupt, RTC0_NS as RTC0, RTC1_NS as RTC1};
|
||||
/// Common definitions and traits for using the nRF RTC monotonics
|
||||
pub mod prelude {
|
||||
pub use crate::nrf_rtc0_monotonic;
|
||||
pub use crate::nrf_rtc1_monotonic;
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
pub use crate::nrf_rtc2_monotonic;
|
||||
|
||||
use crate::{Monotonic, TimeoutError, TimerQueue};
|
||||
use atomic_polyfill::{AtomicU32, Ordering};
|
||||
use core::future::Future;
|
||||
pub use crate::Monotonic;
|
||||
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||
use rtic_time::half_period_counter::calculate_now;
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf52810")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf52810_pac::{self as pac, RTC0, RTC1};
|
||||
#[cfg(feature = "nrf52811")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf52811_pac::{self as pac, RTC0, RTC1};
|
||||
#[cfg(feature = "nrf52832")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf52832_pac::{self as pac, RTC0, RTC1, RTC2};
|
||||
#[cfg(feature = "nrf52833")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf52833_pac::{self as pac, RTC0, RTC1, RTC2};
|
||||
#[cfg(feature = "nrf52840")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf52840_pac::{self as pac, RTC0, RTC1, RTC2};
|
||||
#[cfg(feature = "nrf5340-app")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf5340_app_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1};
|
||||
#[cfg(feature = "nrf5340-net")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf5340_net_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1};
|
||||
#[cfg(feature = "nrf9160")]
|
||||
#[doc(hidden)]
|
||||
pub use nrf9160_pac::{self as pac, RTC0_NS as RTC0, RTC1_NS as RTC1};
|
||||
|
||||
use atomic_polyfill::{AtomicU32, Ordering};
|
||||
use rtic_time::{
|
||||
half_period_counter::calculate_now,
|
||||
timer_queue::{TimerQueue, TimerQueueBackend},
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_create_nrf_rtc_interrupt {
|
||||
($mono_timer:ident, $rtc:ident, $rtc_token:ident) => {{
|
||||
($mono_backend:ident, $rtc:ident) => {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn $rtc() {
|
||||
$crate::nrf::rtc::$mono_timer::__tq().on_monotonic_interrupt();
|
||||
use $crate::TimerQueueBackend;
|
||||
$crate::nrf::rtc::$mono_backend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct $rtc_token;
|
||||
|
||||
unsafe impl $crate::InterruptToken<$crate::nrf::rtc::$mono_timer> for $rtc_token {}
|
||||
|
||||
$rtc_token
|
||||
}};
|
||||
}
|
||||
|
||||
/// Register the Rtc0 interrupt for the monotonic.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_rtc0_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_rtc_interrupt!(Rtc0, RTC0, Rtc0Token)
|
||||
}};
|
||||
macro_rules! __internal_create_nrf_rtc_struct {
|
||||
($name:ident, $mono_backend:ident, $timer:ident) => {
|
||||
/// A `Monotonic` based on the nRF RTC peripheral.
|
||||
struct $name;
|
||||
|
||||
impl $name {
|
||||
/// Starts the `Monotonic`.
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(rtc: $crate::nrf::rtc::$timer) {
|
||||
$crate::__internal_create_nrf_rtc_interrupt!($mono_backend, $timer);
|
||||
|
||||
$crate::nrf::rtc::$mono_backend::_start(rtc);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register the Rtc1 interrupt for the monotonic.
|
||||
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||
type Backend = $crate::nrf::rtc::$mono_backend;
|
||||
type Instant = $crate::fugit::Instant<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
32_768,
|
||||
>;
|
||||
type Duration = $crate::fugit::Duration<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
32_768,
|
||||
>;
|
||||
}
|
||||
|
||||
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||
};
|
||||
}
|
||||
|
||||
/// Create an RTC0 based monotonic and register the RTC0 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::rtc`] for more details.
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_rtc1_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_rtc_interrupt!(Rtc1, RTC1, Rtc1Token)
|
||||
}};
|
||||
macro_rules! nrf_rtc0_monotonic {
|
||||
($name:ident) => {
|
||||
$crate::__internal_create_nrf_rtc_struct!($name, Rtc0Backend, RTC0);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register the Rtc2 interrupt for the monotonic.
|
||||
/// Create an RTC1 based monotonic and register the RTC1 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::rtc`] for more details.
|
||||
#[macro_export]
|
||||
macro_rules! nrf_rtc1_monotonic {
|
||||
($name:ident) => {
|
||||
$crate::__internal_create_nrf_rtc_struct!($name, Rtc1Backend, RTC1);
|
||||
};
|
||||
}
|
||||
|
||||
/// Create an RTC2 based monotonic and register the RTC2 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::rtc`] for more details.
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")))
|
||||
)]
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_rtc2_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_rtc_interrupt!(Rtc2, RTC2, Rtc2Token)
|
||||
}};
|
||||
macro_rules! nrf_rtc2_monotonic {
|
||||
($name:ident) => {
|
||||
$crate::__internal_create_nrf_rtc_struct!($name, Rtc2Backend, RTC2);
|
||||
};
|
||||
}
|
||||
|
||||
struct TimerValueU24(u32);
|
||||
|
@ -104,19 +160,23 @@ impl From<TimerValueU24> for u64 {
|
|||
}
|
||||
|
||||
macro_rules! make_rtc {
|
||||
($mono_name:ident, $rtc:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// Monotonic timer queue implementation.
|
||||
($backend_name:ident, $rtc:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// RTC based [`TimerQueueBackend`].
|
||||
$(
|
||||
#[cfg_attr(docsrs, doc(cfg($($doc)*)))]
|
||||
)?
|
||||
pub struct $mono_name;
|
||||
pub struct $backend_name;
|
||||
|
||||
static $overflow: AtomicU32 = AtomicU32::new(0);
|
||||
static $tq: TimerQueue<$mono_name> = TimerQueue::new();
|
||||
static $tq: TimerQueue<$backend_name> = TimerQueue::new();
|
||||
|
||||
impl $mono_name {
|
||||
/// Start the timer monotonic.
|
||||
pub fn start(rtc: $rtc, _interrupt_token: impl crate::InterruptToken<Self>) {
|
||||
impl $backend_name {
|
||||
/// Starts the timer.
|
||||
///
|
||||
/// **Do not use this function directly.**
|
||||
///
|
||||
/// Use the prelude macros instead.
|
||||
pub fn _start(rtc: $rtc) {
|
||||
unsafe { rtc.prescaler.write(|w| w.bits(0)) };
|
||||
|
||||
// Disable interrupts, as preparation
|
||||
|
@ -166,67 +226,21 @@ macro_rules! make_rtc {
|
|||
// plus we are not using any external shared resources so we won't impact
|
||||
// basepri/source masking based critical sections.
|
||||
unsafe {
|
||||
crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, Interrupt::$rtc);
|
||||
pac::NVIC::unmask(Interrupt::$rtc);
|
||||
crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, pac::Interrupt::$rtc);
|
||||
pac::NVIC::unmask(pac::Interrupt::$rtc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to access the underlying timer queue
|
||||
#[doc(hidden)]
|
||||
pub fn __tq() -> &'static TimerQueue<$mono_name> {
|
||||
&$tq
|
||||
}
|
||||
impl TimerQueueBackend for $backend_name {
|
||||
type Ticks = u64;
|
||||
|
||||
/// Timeout at a specific time.
|
||||
#[inline]
|
||||
pub async fn timeout_at<F: Future>(
|
||||
instant: <Self as Monotonic>::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_at(instant, future).await
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_after(duration, future).await
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
$tq.delay(duration).await;
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
#[inline]
|
||||
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||
$tq.delay_until(instant).await;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!($mono_name);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!($mono_name);
|
||||
|
||||
impl Monotonic for $mono_name {
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
type Instant = fugit::TimerInstantU64<32_768>;
|
||||
type Duration = fugit::TimerDurationU64<32_768>;
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
fn now() -> Self::Ticks {
|
||||
let rtc = unsafe { &*$rtc::PTR };
|
||||
Self::Instant::from_ticks(calculate_now(
|
||||
calculate_now(
|
||||
|| $overflow.load(Ordering::Relaxed),
|
||||
|| TimerValueU24(rtc.counter.read().bits())
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
fn on_interrupt() {
|
||||
|
@ -243,28 +257,35 @@ macro_rules! make_rtc {
|
|||
}
|
||||
}
|
||||
|
||||
fn enable_timer() {}
|
||||
|
||||
fn disable_timer() {}
|
||||
|
||||
fn set_compare(mut instant: Self::Instant) {
|
||||
fn set_compare(mut instant: Self::Ticks) {
|
||||
let rtc = unsafe { &*$rtc::PTR };
|
||||
|
||||
const MAX: u64 = 0xff_ffff;
|
||||
|
||||
// Disable interrupts because this section is timing critical.
|
||||
// We rely on the fact that this entire section runs within one
|
||||
// RTC clock tick. (which it will do easily if it doesn't get
|
||||
// interrupted)
|
||||
critical_section::with(|_|{
|
||||
let now = Self::now();
|
||||
if let Some(diff) = instant.checked_duration_since(now) {
|
||||
// wrapping_sub deals with the u64 overflow corner case
|
||||
let diff = instant.wrapping_sub(now);
|
||||
let val = if diff <= MAX {
|
||||
// Now we know `instant` whill happen within one `MAX` time duration.
|
||||
|
||||
// Errata: Timer interrupts don't fire if they are scheduled less than
|
||||
// two ticks in the future. Make it three, because the timer could
|
||||
// tick right now.
|
||||
if diff.ticks() < 3 {
|
||||
instant = Self::Instant::from_ticks(now.ticks().wrapping_add(3));
|
||||
}
|
||||
unsafe { rtc.cc[0].write(|w| w.bits(instant.ticks() as u32 & 0xff_ffff)) };
|
||||
if diff < 3 {
|
||||
instant = now.wrapping_add(3);
|
||||
}
|
||||
|
||||
(instant & MAX) as u32
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
unsafe { rtc.cc[0].write(|w| w.bits(val)) };
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -274,13 +295,17 @@ macro_rules! make_rtc {
|
|||
}
|
||||
|
||||
fn pend_interrupt() {
|
||||
pac::NVIC::pend(Interrupt::$rtc);
|
||||
pac::NVIC::pend(pac::Interrupt::$rtc);
|
||||
}
|
||||
|
||||
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||
&$tq
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_rtc!(Rtc0, RTC0, RTC0_OVERFLOWS, RTC0_TQ);
|
||||
make_rtc!(Rtc1, RTC1, RTC1_OVERFLOWS, RTC1_TQ);
|
||||
make_rtc!(Rtc0Backend, RTC0, RTC0_OVERFLOWS, RTC0_TQ);
|
||||
make_rtc!(Rtc1Backend, RTC1, RTC1_OVERFLOWS, RTC1_TQ);
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
make_rtc!(Rtc2, RTC2, RTC2_OVERFLOWS, RTC2_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
|
||||
make_rtc!(Rtc2Backend, RTC2, RTC2_OVERFLOWS, RTC2_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! [`Monotonic`] impl for the 32-bit timers of the nRF series.
|
||||
//! [`Monotonic`](rtic_time::Monotonic) implementation for the 32-bit timers of the nRF series.
|
||||
//!
|
||||
//! Not all timers are available on all parts. Ensure that only the available
|
||||
//! timers are exposed by having the correct `nrf52*` feature enabled for `rtic-monotonics`.
|
||||
|
@ -6,139 +6,217 @@
|
|||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use rtic_monotonics::nrf::timer::*;
|
||||
//! use rtic_monotonics::nrf::timer::prelude::*;
|
||||
//! nrf_timer0_monotonic!(Mono);
|
||||
//!
|
||||
//! fn init() {
|
||||
//! # // This is normally provided by the selected PAC
|
||||
//! # let timer = unsafe { core::mem::transmute(()) };
|
||||
//! // Generate the required token
|
||||
//! let token = rtic_monotonics::create_nrf_timer0_monotonic_token!();
|
||||
//!
|
||||
//! // Start the monotonic
|
||||
//! Timer0::start(timer, token);
|
||||
//! Mono::start(timer);
|
||||
//! }
|
||||
//!
|
||||
//! async fn usage() {
|
||||
//! loop {
|
||||
//! // Use the monotonic
|
||||
//! Timer0::delay(100.millis()).await;
|
||||
//! let timestamp = Mono::now();
|
||||
//! Mono::delay(100.millis()).await;
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::{Monotonic, TimeoutError, TimerQueue};
|
||||
use atomic_polyfill::{AtomicU32, Ordering};
|
||||
use core::future::Future;
|
||||
/// Common definitions and traits for using the nRF Timer monotonics
|
||||
pub mod prelude {
|
||||
pub use crate::nrf_timer0_monotonic;
|
||||
pub use crate::nrf_timer1_monotonic;
|
||||
pub use crate::nrf_timer2_monotonic;
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
pub use crate::nrf_timer3_monotonic;
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
pub use crate::nrf_timer4_monotonic;
|
||||
|
||||
pub use crate::Monotonic;
|
||||
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||
use rtic_time::half_period_counter::calculate_now;
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf52810")]
|
||||
use nrf52810_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2};
|
||||
#[doc(hidden)]
|
||||
pub use nrf52810_pac::{self as pac, TIMER0, TIMER1, TIMER2};
|
||||
#[cfg(feature = "nrf52811")]
|
||||
use nrf52811_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2};
|
||||
#[doc(hidden)]
|
||||
pub use nrf52811_pac::{self as pac, TIMER0, TIMER1, TIMER2};
|
||||
#[cfg(feature = "nrf52832")]
|
||||
use nrf52832_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
|
||||
#[doc(hidden)]
|
||||
pub use nrf52832_pac::{self as pac, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
|
||||
#[cfg(feature = "nrf52833")]
|
||||
use nrf52833_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
|
||||
#[doc(hidden)]
|
||||
pub use nrf52833_pac::{self as pac, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
|
||||
#[cfg(feature = "nrf52840")]
|
||||
use nrf52840_pac::{self as pac, Interrupt, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
|
||||
#[doc(hidden)]
|
||||
pub use nrf52840_pac::{self as pac, TIMER0, TIMER1, TIMER2, TIMER3, TIMER4};
|
||||
#[cfg(feature = "nrf5340-app")]
|
||||
use nrf5340_app_pac::{
|
||||
self as pac, Interrupt, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
|
||||
#[doc(hidden)]
|
||||
pub use nrf5340_app_pac::{
|
||||
self as pac, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
|
||||
};
|
||||
#[cfg(feature = "nrf5340-net")]
|
||||
use nrf5340_net_pac::{
|
||||
self as pac, Interrupt, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
|
||||
#[doc(hidden)]
|
||||
pub use nrf5340_net_pac::{
|
||||
self as pac, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
|
||||
};
|
||||
#[cfg(feature = "nrf9160")]
|
||||
use nrf9160_pac::{
|
||||
self as pac, Interrupt, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2,
|
||||
#[doc(hidden)]
|
||||
pub use nrf9160_pac::{self as pac, TIMER0_NS as TIMER0, TIMER1_NS as TIMER1, TIMER2_NS as TIMER2};
|
||||
|
||||
use atomic_polyfill::{AtomicU32, Ordering};
|
||||
use rtic_time::{
|
||||
half_period_counter::calculate_now,
|
||||
timer_queue::{TimerQueue, TimerQueueBackend},
|
||||
};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_create_nrf_timer_interrupt {
|
||||
($mono_timer:ident, $timer:ident, $timer_token:ident) => {{
|
||||
($mono_backend:ident, $timer:ident) => {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn $timer() {
|
||||
$crate::nrf::timer::$mono_timer::__tq().on_monotonic_interrupt();
|
||||
use $crate::TimerQueueBackend;
|
||||
$crate::nrf::timer::$mono_backend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct $timer_token;
|
||||
|
||||
unsafe impl $crate::InterruptToken<$crate::nrf::timer::$mono_timer> for $timer_token {}
|
||||
|
||||
$timer_token
|
||||
}};
|
||||
}
|
||||
|
||||
/// Register the Timer0 interrupt for the monotonic.
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_timer0_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_timer_interrupt!(Timer0, TIMER0, Timer0Token)
|
||||
}};
|
||||
macro_rules! __internal_create_nrf_timer_struct {
|
||||
($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
|
||||
/// A `Monotonic` based on the nRF Timer peripheral.
|
||||
struct $name;
|
||||
|
||||
impl $name {
|
||||
/// Starts the `Monotonic`.
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(timer: $crate::nrf::timer::$timer) {
|
||||
$crate::__internal_create_nrf_timer_interrupt!($mono_backend, $timer);
|
||||
|
||||
const PRESCALER: u8 = match $tick_rate_hz {
|
||||
16_000_000 => 0,
|
||||
8_000_000 => 1,
|
||||
4_000_000 => 2,
|
||||
2_000_000 => 3,
|
||||
1_000_000 => 4,
|
||||
500_000 => 5,
|
||||
250_000 => 6,
|
||||
125_000 => 7,
|
||||
62_500 => 8,
|
||||
31_250 => 9,
|
||||
_ => panic!("Timer cannot run at desired tick rate!"),
|
||||
};
|
||||
|
||||
$crate::nrf::timer::$mono_backend::_start(timer, PRESCALER);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register the Timer1 interrupt for the monotonic.
|
||||
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||
type Backend = $crate::nrf::timer::$mono_backend;
|
||||
type Instant = $crate::fugit::Instant<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
type Duration = $crate::fugit::Duration<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
}
|
||||
|
||||
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||
};
|
||||
}
|
||||
|
||||
/// Create an Timer0 based monotonic and register the TIMER0 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::timer`] for more details.
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_timer1_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_timer_interrupt!(Timer1, TIMER1, Timer1Token)
|
||||
}};
|
||||
macro_rules! nrf_timer0_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_nrf_timer_struct!($name, Timer0Backend, TIMER0, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register the Timer2 interrupt for the monotonic.
|
||||
/// Create an Timer1 based monotonic and register the TIMER1 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::timer`] for more details.
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_timer2_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_timer_interrupt!(Timer2, TIMER2, Timer2Token)
|
||||
}};
|
||||
macro_rules! nrf_timer1_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_nrf_timer_struct!($name, Timer1Backend, TIMER1, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register the Timer3 interrupt for the monotonic.
|
||||
/// Create an Timer2 based monotonic and register the TIMER2 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::timer`] for more details.
|
||||
#[macro_export]
|
||||
macro_rules! nrf_timer2_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_nrf_timer_struct!($name, Timer2Backend, TIMER2, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Create an Timer3 based monotonic and register the TIMER3 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::timer`] for more details.
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")))
|
||||
)]
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_timer3_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_timer_interrupt!(Timer3, TIMER3, Timer3Token)
|
||||
}};
|
||||
macro_rules! nrf_timer3_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_nrf_timer_struct!($name, Timer3Backend, TIMER3, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register the Timer4 interrupt for the monotonic.
|
||||
/// Create an Timer4 based monotonic and register the TIMER4 interrupt for it.
|
||||
///
|
||||
/// See [`crate::nrf::timer`] for more details.
|
||||
#[cfg_attr(
|
||||
docsrs,
|
||||
doc(cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")))
|
||||
)]
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
#[macro_export]
|
||||
macro_rules! create_nrf_timer4_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_nrf_timer_interrupt!(Timer4, TIMER4, Timer4Token)
|
||||
}};
|
||||
macro_rules! nrf_timer4_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_nrf_timer_struct!($name, Timer4Backend, TIMER4, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! make_timer {
|
||||
($mono_name:ident, $timer:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// Monotonic timer queue implementation.
|
||||
($backend_name:ident, $timer:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// Timer peripheral based [`TimerQueueBackend`].
|
||||
$(
|
||||
#[cfg_attr(docsrs, doc(cfg($($doc)*)))]
|
||||
)?
|
||||
pub struct $mono_name;
|
||||
pub struct $backend_name;
|
||||
|
||||
static $overflow: AtomicU32 = AtomicU32::new(0);
|
||||
static $tq: TimerQueue<$mono_name> = TimerQueue::new();
|
||||
static $tq: TimerQueue<$backend_name> = TimerQueue::new();
|
||||
|
||||
impl $mono_name {
|
||||
/// Start the timer monotonic.
|
||||
pub fn start(timer: $timer, _interrupt_token: impl crate::InterruptToken<Self>) {
|
||||
// 1 MHz
|
||||
timer.prescaler.write(|w| unsafe { w.prescaler().bits(4) });
|
||||
impl $backend_name {
|
||||
/// Starts the timer.
|
||||
///
|
||||
/// **Do not use this function directly.**
|
||||
///
|
||||
/// Use the prelude macros instead.
|
||||
pub fn _start(timer: $timer, prescaler: u8) {
|
||||
timer.prescaler.write(|w| unsafe { w.prescaler().bits(prescaler) });
|
||||
timer.bitmode.write(|w| w.bitmode()._32bit());
|
||||
|
||||
// Disable interrupts, as preparation
|
||||
|
@ -184,70 +262,25 @@ macro_rules! make_timer {
|
|||
// plus we are not using any external shared resources so we won't impact
|
||||
// basepri/source masking based critical sections.
|
||||
unsafe {
|
||||
crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, Interrupt::$timer);
|
||||
pac::NVIC::unmask(Interrupt::$timer);
|
||||
crate::set_monotonic_prio(pac::NVIC_PRIO_BITS, pac::Interrupt::$timer);
|
||||
pac::NVIC::unmask(pac::Interrupt::$timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to access the underlying timer queue
|
||||
#[doc(hidden)]
|
||||
pub fn __tq() -> &'static TimerQueue<$mono_name> {
|
||||
&$tq
|
||||
}
|
||||
impl TimerQueueBackend for $backend_name {
|
||||
type Ticks = u64;
|
||||
|
||||
/// Timeout at a specific time.
|
||||
#[inline]
|
||||
pub async fn timeout_at<F: Future>(
|
||||
instant: <Self as Monotonic>::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_at(instant, future).await
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_after(duration, future).await
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
$tq.delay(duration).await;
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
#[inline]
|
||||
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||
$tq.delay_until(instant).await;
|
||||
}
|
||||
}
|
||||
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!($mono_name);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!($mono_name);
|
||||
|
||||
impl Monotonic for $mono_name {
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
type Instant = fugit::TimerInstantU64<1_000_000>;
|
||||
type Duration = fugit::TimerDurationU64<1_000_000>;
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
fn now() -> Self::Ticks {
|
||||
let timer = unsafe { &*$timer::PTR };
|
||||
|
||||
Self::Instant::from_ticks(calculate_now(
|
||||
calculate_now(
|
||||
|| $overflow.load(Ordering::Relaxed),
|
||||
|| {
|
||||
timer.tasks_capture[3].write(|w| unsafe { w.bits(1) });
|
||||
timer.cc[3].read().bits()
|
||||
}
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
fn on_interrupt() {
|
||||
|
@ -268,9 +301,9 @@ macro_rules! make_timer {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Instant) {
|
||||
fn set_compare(instant: Self::Ticks) {
|
||||
let timer = unsafe { &*$timer::PTR };
|
||||
timer.cc[0].write(|w| unsafe { w.cc().bits(instant.ticks() as u32) });
|
||||
timer.cc[0].write(|w| unsafe { w.cc().bits(instant as u32) });
|
||||
}
|
||||
|
||||
fn clear_compare_flag() {
|
||||
|
@ -279,16 +312,20 @@ macro_rules! make_timer {
|
|||
}
|
||||
|
||||
fn pend_interrupt() {
|
||||
pac::NVIC::pend(Interrupt::$timer);
|
||||
pac::NVIC::pend(pac::Interrupt::$timer);
|
||||
}
|
||||
|
||||
fn timer_queue() -> &'static TimerQueue<$backend_name> {
|
||||
&$tq
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_timer!(Timer0, TIMER0, TIMER0_OVERFLOWS, TIMER0_TQ);
|
||||
make_timer!(Timer1, TIMER1, TIMER1_OVERFLOWS, TIMER1_TQ);
|
||||
make_timer!(Timer2, TIMER2, TIMER2_OVERFLOWS, TIMER2_TQ);
|
||||
make_timer!(Timer0Backend, TIMER0, TIMER0_OVERFLOWS, TIMER0_TQ);
|
||||
make_timer!(Timer1Backend, TIMER1, TIMER1_OVERFLOWS, TIMER1_TQ);
|
||||
make_timer!(Timer2Backend, TIMER2, TIMER2_OVERFLOWS, TIMER2_TQ);
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
make_timer!(Timer3, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
|
||||
make_timer!(Timer3Backend, TIMER3, TIMER3_OVERFLOWS, TIMER3_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
|
||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||
make_timer!(Timer4, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
|
||||
make_timer!(Timer4Backend, TIMER4, TIMER4_OVERFLOWS, TIMER4_TQ, doc: (any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840")));
|
||||
|
|
|
@ -1,46 +1,56 @@
|
|||
//! [`Monotonic`] implementation for RP2040's Timer peripheral.
|
||||
//! [`Monotonic`](rtic_time::Monotonic) implementation for RP2040's Timer peripheral.
|
||||
//!
|
||||
//! Always runs at a fixed rate of 1 MHz.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use rtic_monotonics::rp2040::*;
|
||||
//! use rtic_monotonics::rp2040::prelude::*;
|
||||
//!
|
||||
//! rp2040_timer_monotonic!(Mono);
|
||||
//!
|
||||
//! fn init() {
|
||||
//! # // This is normally provided by the selected PAC
|
||||
//! # let timer = unsafe { core::mem::transmute(()) };
|
||||
//! # let mut resets = unsafe { core::mem::transmute(()) };
|
||||
//! // Generate the required token
|
||||
//! let token = rtic_monotonics::create_rp2040_monotonic_token!();
|
||||
//!
|
||||
//! #
|
||||
//! // Start the monotonic
|
||||
//! Timer::start(timer, &mut resets, token);
|
||||
//! Mono::start(timer, &mut resets);
|
||||
//! }
|
||||
//!
|
||||
//! async fn usage() {
|
||||
//! loop {
|
||||
//! // Use the monotonic
|
||||
//! Timer::delay(100.millis()).await;
|
||||
//! let timestamp = Mono::now();
|
||||
//! Mono::delay(100.millis()).await;
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use super::Monotonic;
|
||||
/// Common definitions and traits for using the RP2040 timer monotonic
|
||||
pub mod prelude {
|
||||
pub use crate::rp2040_timer_monotonic;
|
||||
|
||||
pub use crate::Monotonic;
|
||||
|
||||
pub use super::{TimeoutError, TimerQueue};
|
||||
use core::future::Future;
|
||||
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||
use rp2040_pac::{timer, Interrupt, NVIC, RESETS, TIMER};
|
||||
}
|
||||
|
||||
/// Timer implementing [`Monotonic`] which runs at 1 MHz.
|
||||
pub struct Timer;
|
||||
use crate::TimerQueueBackend;
|
||||
use rp2040_pac::{timer, Interrupt, NVIC};
|
||||
pub use rp2040_pac::{RESETS, TIMER};
|
||||
use rtic_time::timer_queue::TimerQueue;
|
||||
|
||||
impl Timer {
|
||||
/// Start a `Monotonic` based on RP2040's Timer.
|
||||
pub fn start(
|
||||
timer: TIMER,
|
||||
resets: &RESETS,
|
||||
_interrupt_token: impl crate::InterruptToken<Self>,
|
||||
) {
|
||||
/// Timer implementing [`TimerQueueBackend`].
|
||||
pub struct TimerBackend;
|
||||
|
||||
impl TimerBackend {
|
||||
/// Starts the monotonic timer.
|
||||
///
|
||||
/// **Do not use this function directly.**
|
||||
///
|
||||
/// Use the prelude macros instead.
|
||||
pub fn _start(timer: TIMER, resets: &RESETS) {
|
||||
resets.reset.modify(|_, w| w.timer().clear_bit());
|
||||
while resets.reset_done.read().timer().bit_is_clear() {}
|
||||
timer.inte.modify(|_, w| w.alarm_0().bit(true));
|
||||
|
@ -58,55 +68,12 @@ impl Timer {
|
|||
}
|
||||
}
|
||||
|
||||
static TIMER_QUEUE: TimerQueue<Timer> = TimerQueue::new();
|
||||
static TIMER_QUEUE: TimerQueue<TimerBackend> = TimerQueue::new();
|
||||
|
||||
// Forward timerqueue interface
|
||||
impl Timer {
|
||||
/// Used to access the underlying timer queue
|
||||
#[doc(hidden)]
|
||||
pub fn __tq() -> &'static TimerQueue<Timer> {
|
||||
&TIMER_QUEUE
|
||||
}
|
||||
impl TimerQueueBackend for TimerBackend {
|
||||
type Ticks = u64;
|
||||
|
||||
/// Timeout at a specific time.
|
||||
#[inline]
|
||||
pub async fn timeout_at<F: Future>(
|
||||
instant: <Self as Monotonic>::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
TIMER_QUEUE.timeout_at(instant, future).await
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
TIMER_QUEUE.timeout_after(duration, future).await
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
TIMER_QUEUE.delay(duration).await;
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
#[inline]
|
||||
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||
TIMER_QUEUE.delay_until(instant).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl Monotonic for Timer {
|
||||
type Instant = fugit::TimerInstantU64<1_000_000>;
|
||||
type Duration = fugit::TimerDurationU64<1_000_000>;
|
||||
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
fn now() -> Self::Ticks {
|
||||
let timer = Self::timer();
|
||||
|
||||
let mut hi0 = timer.timerawh.read().bits();
|
||||
|
@ -114,22 +81,24 @@ impl Monotonic for Timer {
|
|||
let low = timer.timerawl.read().bits();
|
||||
let hi1 = timer.timerawh.read().bits();
|
||||
if hi0 == hi1 {
|
||||
break Self::Instant::from_ticks((u64::from(hi0) << 32) | u64::from(low));
|
||||
break ((u64::from(hi0) << 32) | u64::from(low));
|
||||
}
|
||||
hi0 = hi1;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Instant) {
|
||||
fn set_compare(instant: Self::Ticks) {
|
||||
let now = Self::now();
|
||||
|
||||
let max = u32::MAX as u64;
|
||||
const MAX: u64 = u32::MAX as u64;
|
||||
|
||||
// Since the timer may or may not overflow based on the requested compare val, we check
|
||||
// how many ticks are left.
|
||||
let val = match instant.checked_duration_since(now) {
|
||||
Some(x) if x.ticks() <= max => instant.duration_since_epoch().ticks() & max, // Will not overflow
|
||||
_ => 0, // Will overflow or in the past, set the same value as after overflow to not get extra interrupts
|
||||
// `wrapping_sup` takes care of the u64 integer overflow special case.
|
||||
let val = if instant.wrapping_sub(now) <= MAX {
|
||||
instant & MAX
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Self::timer()
|
||||
|
@ -145,32 +114,55 @@ impl Monotonic for Timer {
|
|||
rp2040_pac::NVIC::pend(Interrupt::TIMER_IRQ_0);
|
||||
}
|
||||
|
||||
fn on_interrupt() {}
|
||||
|
||||
fn enable_timer() {}
|
||||
|
||||
fn disable_timer() {}
|
||||
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||
&TIMER_QUEUE
|
||||
}
|
||||
}
|
||||
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!(Timer);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!(Timer);
|
||||
|
||||
/// Register the Timer interrupt for the monotonic.
|
||||
/// Create an RP2040 timer based monotonic and register the necessary interrupt for it.
|
||||
///
|
||||
/// See [`crate::rp2040`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
#[macro_export]
|
||||
macro_rules! create_rp2040_monotonic_token {
|
||||
() => {{
|
||||
macro_rules! rp2040_timer_monotonic {
|
||||
($name:ident) => {
|
||||
/// A `Monotonic` based on the RP2040 Timer peripheral.
|
||||
struct $name;
|
||||
|
||||
impl $name {
|
||||
/// Starts the `Monotonic`.
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(timer: $crate::rp2040::TIMER, resets: &$crate::rp2040::RESETS) {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn TIMER_IRQ_0() {
|
||||
$crate::rp2040::Timer::__tq().on_monotonic_interrupt();
|
||||
use $crate::TimerQueueBackend;
|
||||
$crate::rp2040::TimerBackend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
|
||||
pub struct Rp2040Token;
|
||||
|
||||
unsafe impl $crate::InterruptToken<$crate::rp2040::Timer> for Rp2040Token {}
|
||||
|
||||
Rp2040Token
|
||||
}};
|
||||
$crate::rp2040::TimerBackend::_start(timer, resets);
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||
type Backend = $crate::rp2040::TimerBackend;
|
||||
type Instant = $crate::fugit::Instant<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
1_000_000,
|
||||
>;
|
||||
type Duration = $crate::fugit::Duration<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
1_000_000,
|
||||
>;
|
||||
}
|
||||
|
||||
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! [`Monotonic`] impl for the STM32.
|
||||
//! [`Monotonic`](rtic_time::Monotonic) implementations for STM32 chips.
|
||||
//!
|
||||
//! Not all timers are available on all parts. Ensure that only available
|
||||
//! timers are exposed by having the correct `stm32*` feature enabled for `rtic-monotonics`.
|
||||
|
@ -6,38 +6,56 @@
|
|||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use rtic_monotonics::stm32::*;
|
||||
//! use rtic_monotonics::stm32::Tim2 as Mono;
|
||||
//! use rtic_monotonics::Monotonic;
|
||||
//! use embassy_stm32::peripherals::TIM2;
|
||||
//! use embassy_stm32::rcc::low_level::RccPeripheral;
|
||||
//! use rtic_monotonics::stm32::prelude::*;
|
||||
//!
|
||||
//! // Define the monotonic and set it to 1MHz tick rate
|
||||
//! stm32_tim2_monotonic!(Mono, 1_000_000);
|
||||
//!
|
||||
//! fn init() {
|
||||
//! // Generate timer token to ensure correct timer interrupt handler is used.
|
||||
//! let token = rtic_monotonics::create_stm32_tim2_monotonic_token!();
|
||||
//!
|
||||
//! // If using `embassy-stm32` HAL, timer clock can be read out like this:
|
||||
//! let timer_clock_hz = TIM2::frequency();
|
||||
//! let timer_clock_hz = embassy_stm32::peripherals::TIM2::frequency();
|
||||
//! // Or define it manually if you are using other HAL or know correct frequency:
|
||||
//! let timer_clock_hz = 64_000_000;
|
||||
//!
|
||||
//! // Start the monotonic
|
||||
//! Mono::start(timer_clock_hz, token);
|
||||
//! Mono::start(timer_clock_hz);
|
||||
//! }
|
||||
//!
|
||||
//! async fn usage() {
|
||||
//! loop {
|
||||
//! // Use the monotonic
|
||||
//! let timestamp = Mono::now().ticks();
|
||||
//! let timestamp = Mono::now();
|
||||
//! Mono::delay(100.millis()).await;
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::{Monotonic, TimeoutError, TimerQueue};
|
||||
use atomic_polyfill::{AtomicU64, Ordering};
|
||||
/// Common definitions and traits for using the STM32 monotonics
|
||||
pub mod prelude {
|
||||
#[cfg(feature = "stm32_tim2")]
|
||||
pub use crate::stm32_tim2_monotonic;
|
||||
|
||||
#[cfg(feature = "stm32_tim3")]
|
||||
pub use crate::stm32_tim3_monotonic;
|
||||
|
||||
#[cfg(feature = "stm32_tim4")]
|
||||
pub use crate::stm32_tim4_monotonic;
|
||||
|
||||
#[cfg(feature = "stm32_tim5")]
|
||||
pub use crate::stm32_tim5_monotonic;
|
||||
|
||||
#[cfg(feature = "stm32_tim15")]
|
||||
pub use crate::stm32_tim15_monotonic;
|
||||
|
||||
pub use crate::Monotonic;
|
||||
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||
use rtic_time::half_period_counter::calculate_now;
|
||||
}
|
||||
|
||||
use atomic_polyfill::{AtomicU64, Ordering};
|
||||
use rtic_time::{
|
||||
half_period_counter::calculate_now,
|
||||
timer_queue::{TimerQueue, TimerQueueBackend},
|
||||
};
|
||||
use stm32_metapac as pac;
|
||||
|
||||
mod _generated {
|
||||
|
@ -48,116 +66,180 @@ mod _generated {
|
|||
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
|
||||
}
|
||||
|
||||
const TIMER_HZ: u32 = 1_000_000;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_create_stm32_timer_interrupt {
|
||||
($mono_timer:ident, $timer:ident, $timer_token:ident) => {{
|
||||
($mono_backend:ident, $interrupt_name:ident) => {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn $timer() {
|
||||
$crate::stm32::$mono_timer::__tq().on_monotonic_interrupt();
|
||||
unsafe extern "C" fn $interrupt_name() {
|
||||
use $crate::TimerQueueBackend;
|
||||
$crate::stm32::$mono_backend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct $timer_token;
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! __internal_create_stm32_timer_struct {
|
||||
($name:ident, $mono_backend:ident, $timer:ident, $tick_rate_hz:expr) => {
|
||||
struct $name;
|
||||
|
||||
unsafe impl $crate::InterruptToken<$crate::stm32::$mono_timer> for $timer_token {}
|
||||
impl $name {
|
||||
/// Starts the `Monotonic`.
|
||||
///
|
||||
/// - `tim_clock_hz`: `TIMx` peripheral clock frequency.
|
||||
///
|
||||
/// Panics if it is impossible to achieve the desired monotonic tick rate based
|
||||
/// on the given `tim_clock_hz` parameter. If that happens, adjust the desired monotonic tick rate.
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(tim_clock_hz: u32) {
|
||||
$crate::__internal_create_stm32_timer_interrupt!($mono_backend, $timer);
|
||||
|
||||
$timer_token
|
||||
}};
|
||||
$crate::stm32::$mono_backend::_start(tim_clock_hz, $tick_rate_hz);
|
||||
}
|
||||
}
|
||||
|
||||
/// Register TIM2 interrupt for the monotonic.
|
||||
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||
type Backend = $crate::stm32::$mono_backend;
|
||||
type Instant = $crate::fugit::Instant<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
type Duration = $crate::fugit::Duration<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
}
|
||||
|
||||
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||
};
|
||||
}
|
||||
|
||||
/// Create a TIM2 based monotonic and register the TIM2 interrupt for it.
|
||||
///
|
||||
/// See [`crate::stm32`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral.
|
||||
///
|
||||
#[cfg(feature = "stm32_tim2")]
|
||||
#[macro_export]
|
||||
macro_rules! create_stm32_tim2_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_stm32_timer_interrupt!(Tim2, TIM2, Tim2Token)
|
||||
}};
|
||||
macro_rules! stm32_tim2_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_stm32_timer_struct!($name, Tim2Backend, TIM2, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register TIM3 interrupt for the monotonic.
|
||||
/// Create a TIM3 based monotonic and register the TIM3 interrupt for it.
|
||||
///
|
||||
/// See [`crate::stm32`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral.
|
||||
///
|
||||
#[cfg(feature = "stm32_tim3")]
|
||||
#[macro_export]
|
||||
macro_rules! create_stm32_tim3_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_stm32_timer_interrupt!(Tim3, TIM3, Tim3Token)
|
||||
}};
|
||||
macro_rules! stm32_tim3_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_stm32_timer_struct!($name, Tim3Backend, TIM3, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register TIM4 interrupt for the monotonic.
|
||||
/// Create a TIM4 based monotonic and register the TIM4 interrupt for it.
|
||||
///
|
||||
/// See [`crate::stm32`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral.
|
||||
///
|
||||
#[cfg(feature = "stm32_tim4")]
|
||||
#[macro_export]
|
||||
macro_rules! create_stm32_tim4_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_stm32_timer_interrupt!(Tim4, TIM4, Tim4Token)
|
||||
}};
|
||||
macro_rules! stm32_tim4_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_stm32_timer_struct!($name, Tim4Backend, TIM4, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register TIM5 interrupt for the monotonic.
|
||||
/// Create a TIM5 based monotonic and register the TIM5 interrupt for it.
|
||||
///
|
||||
/// See [`crate::stm32`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral.
|
||||
///
|
||||
#[cfg(feature = "stm32_tim5")]
|
||||
#[macro_export]
|
||||
macro_rules! create_stm32_tim5_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_stm32_timer_interrupt!(Tim5, TIM5, Tim5Token)
|
||||
}};
|
||||
macro_rules! stm32_tim5_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_stm32_timer_struct!($name, Tim5Backend, TIM5, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
/// Register TIM12 interrupt for the monotonic.
|
||||
#[cfg(feature = "stm32_tim12")]
|
||||
#[macro_export]
|
||||
macro_rules! create_stm32_tim12_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_stm32_timer_interrupt!(Tim12, TIM12, Tim12Token)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Register TIM15 interrupt for the monotonic.
|
||||
/// Create a TIM15 based monotonic and register the TIM15 interrupt for it.
|
||||
///
|
||||
/// See [`crate::stm32`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral.
|
||||
///
|
||||
#[cfg(feature = "stm32_tim15")]
|
||||
#[macro_export]
|
||||
macro_rules! create_stm32_tim15_monotonic_token {
|
||||
() => {{
|
||||
$crate::__internal_create_stm32_timer_interrupt!(Tim15, TIM15, Tim15Token)
|
||||
}};
|
||||
macro_rules! stm32_tim15_monotonic {
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
$crate::__internal_create_stm32_timer_struct!($name, Tim15Backend, TIM15, $tick_rate_hz);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! make_timer {
|
||||
($mono_name:ident, $timer:ident, $bits:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// Monotonic timer queue implementation.
|
||||
($backend_name:ident, $timer:ident, $bits:ident, $overflow:ident, $tq:ident$(, doc: ($($doc:tt)*))?) => {
|
||||
/// Monotonic timer backend implementation.
|
||||
$(
|
||||
#[cfg_attr(docsrs, doc(cfg($($doc)*)))]
|
||||
)?
|
||||
|
||||
pub struct $mono_name;
|
||||
pub struct $backend_name;
|
||||
|
||||
use pac::$timer;
|
||||
|
||||
static $overflow: AtomicU64 = AtomicU64::new(0);
|
||||
static $tq: TimerQueue<$mono_name> = TimerQueue::new();
|
||||
static $tq: TimerQueue<$backend_name> = TimerQueue::new();
|
||||
|
||||
impl $mono_name {
|
||||
/// Starts the monotonic timer.
|
||||
impl $backend_name {
|
||||
/// Starts the timer.
|
||||
///
|
||||
/// - `tim_clock_hz`: `TIMx` peripheral clock frequency.
|
||||
/// - `_interrupt_token`: Required for correct timer interrupt handling.
|
||||
/// **Do not use this function directly.**
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(tim_clock_hz: u32, _interrupt_token: impl crate::InterruptToken<Self>) {
|
||||
/// Use the prelude macros instead.
|
||||
pub fn _start(tim_clock_hz: u32, timer_hz: u32) {
|
||||
_generated::$timer::enable();
|
||||
_generated::$timer::reset();
|
||||
|
||||
$timer.cr1().modify(|r| r.set_cen(false));
|
||||
|
||||
assert!((tim_clock_hz % TIMER_HZ) == 0, "Unable to find suitable timer prescaler value!");
|
||||
let psc = tim_clock_hz / TIMER_HZ - 1;
|
||||
assert!((tim_clock_hz % timer_hz) == 0, "Unable to find suitable timer prescaler value!");
|
||||
let psc = tim_clock_hz / timer_hz - 1;
|
||||
$timer.psc().write(|r| r.set_psc(psc as u16));
|
||||
|
||||
// Enable full-period interrupt.
|
||||
$timer.dier().modify(|r| r.set_uie(true));
|
||||
|
||||
// Configure and enable half-period interrupt
|
||||
$timer.ccr(2).write(|r| r.set_ccr($bits::MAX - ($bits::MAX >> 1)));
|
||||
$timer.ccr(2).write(|r| r.set_ccr(($bits::MAX - ($bits::MAX >> 1)).into()));
|
||||
$timer.dier().modify(|r| r.set_ccie(2, true));
|
||||
|
||||
// Trigger an update event to load the prescaler value to the clock.
|
||||
|
@ -183,73 +265,31 @@ macro_rules! make_timer {
|
|||
cortex_m::peripheral::NVIC::unmask(pac::Interrupt::$timer);
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to access the underlying timer queue
|
||||
#[doc(hidden)]
|
||||
pub fn __tq() -> &'static TimerQueue<$mono_name> {
|
||||
&$tq
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
$tq.delay(duration).await;
|
||||
}
|
||||
impl TimerQueueBackend for $backend_name {
|
||||
type Ticks = u64;
|
||||
|
||||
/// Timeout at a specific time.
|
||||
pub async fn timeout_at<F: core::future::Future>(
|
||||
instant: <Self as rtic_time::Monotonic>::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_at(instant, future).await
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: core::future::Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
$tq.timeout_after(duration, future).await
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
#[inline]
|
||||
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||
$tq.delay_until(instant).await;
|
||||
}
|
||||
}
|
||||
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!($mono_name);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!($mono_name);
|
||||
|
||||
impl Monotonic for $mono_name {
|
||||
type Instant = fugit::TimerInstantU64<TIMER_HZ>;
|
||||
type Duration = fugit::TimerDurationU64<TIMER_HZ>;
|
||||
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
Self::Instant::from_ticks(calculate_now(
|
||||
fn now() -> Self::Ticks {
|
||||
calculate_now(
|
||||
|| $overflow.load(Ordering::Relaxed),
|
||||
|| $timer.cnt().read().cnt()
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Instant) {
|
||||
fn set_compare(instant: Self::Ticks) {
|
||||
let now = Self::now();
|
||||
|
||||
// Since the timer may or may not overflow based on the requested compare val, we check how many ticks are left.
|
||||
let val = match instant.checked_duration_since(now) {
|
||||
None => 0, // In the past
|
||||
Some(x) if x.ticks() <= ($bits::MAX as u64) => instant.duration_since_epoch().ticks() as $bits, // Will not overflow
|
||||
Some(_x) => 0, // Will overflow
|
||||
// `wrapping_sup` takes care of the u64 integer overflow special case.
|
||||
let val = if instant.wrapping_sub(now) <= ($bits::MAX as u64) {
|
||||
instant as $bits
|
||||
} else {
|
||||
// In the past or will overflow
|
||||
0
|
||||
};
|
||||
|
||||
$timer.ccr(1).write(|r| r.set_ccr(val));
|
||||
$timer.ccr(1).write(|r| r.set_ccr(val.into()));
|
||||
}
|
||||
|
||||
fn clear_compare_flag() {
|
||||
|
@ -282,24 +322,25 @@ macro_rules! make_timer {
|
|||
assert!(prev % 2 == 0, "Monotonic must have missed an interrupt!");
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_queue() -> &'static TimerQueue<$backend_name> {
|
||||
&$tq
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "stm32_tim2")]
|
||||
make_timer!(Tim2, TIM2, u32, TIMER2_OVERFLOWS, TIMER2_TQ);
|
||||
make_timer!(Tim2Backend, TIM2, u32, TIMER2_OVERFLOWS, TIMER2_TQ);
|
||||
|
||||
#[cfg(feature = "stm32_tim3")]
|
||||
make_timer!(Tim3, TIM3, u16, TIMER3_OVERFLOWS, TIMER3_TQ);
|
||||
make_timer!(Tim3Backend, TIM3, u16, TIMER3_OVERFLOWS, TIMER3_TQ);
|
||||
|
||||
#[cfg(feature = "stm32_tim4")]
|
||||
make_timer!(Tim4, TIM4, u16, TIMER4_OVERFLOWS, TIMER4_TQ);
|
||||
make_timer!(Tim4Backend, TIM4, u16, TIMER4_OVERFLOWS, TIMER4_TQ);
|
||||
|
||||
#[cfg(feature = "stm32_tim5")]
|
||||
make_timer!(Tim5, TIM5, u16, TIMER5_OVERFLOWS, TIMER5_TQ);
|
||||
|
||||
#[cfg(feature = "stm32_tim12")]
|
||||
make_timer!(Tim12, TIM12, u16, TIMER12_OVERFLOWS, TIMER12_TQ);
|
||||
make_timer!(Tim5Backend, TIM5, u16, TIMER5_OVERFLOWS, TIMER5_TQ);
|
||||
|
||||
#[cfg(feature = "stm32_tim15")]
|
||||
make_timer!(Tim15, TIM15, u16, TIMER15_OVERFLOWS, TIMER15_TQ);
|
||||
make_timer!(Tim15Backend, TIM15, u16, TIMER15_OVERFLOWS, TIMER15_TQ);
|
||||
|
|
|
@ -1,93 +1,79 @@
|
|||
//! [`Monotonic`] based on Cortex-M SysTick. Note: this implementation is inefficient as it
|
||||
//! [`Monotonic`](rtic_time::Monotonic) based on Cortex-M SysTick.
|
||||
//! Note: this implementation is inefficient as it
|
||||
//! ticks and generates interrupts at a constant rate.
|
||||
//!
|
||||
//! Currently, the following tick rates are supported:
|
||||
//!
|
||||
//! | Feature | Tick rate | Precision |
|
||||
//! |:----------------:|----------:|----------:|
|
||||
//! | (none / default) | 1 kHz | 1 ms |
|
||||
//! | systick-100hz | 100 Hz | 10 ms |
|
||||
//! | systick-10khz | 10 kHz | 0.1 ms |
|
||||
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use rtic_monotonics::systick::*;
|
||||
//! use rtic_monotonics::systick::prelude::*;
|
||||
//! systick_monotonic!(Mono, 1_000);
|
||||
//!
|
||||
//! fn init() {
|
||||
//! # // This is normally provided by the selected PAC
|
||||
//! # let systick = unsafe { core::mem::transmute(()) };
|
||||
//! // Generate the required token
|
||||
//! let systick_token = rtic_monotonics::create_systick_token!();
|
||||
//!
|
||||
//! #
|
||||
//! // Start the monotonic
|
||||
//! Systick::start(systick, 12_000_000, systick_token);
|
||||
//! Mono::start(systick, 12_000_000);
|
||||
//! }
|
||||
//!
|
||||
//! async fn usage() {
|
||||
//! loop {
|
||||
//! // Use the monotonic
|
||||
//! let timestamp = Mono::now();
|
||||
//! Systick::delay(100.millis()).await;
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use super::Monotonic;
|
||||
pub use super::{TimeoutError, TimerQueue};
|
||||
use atomic_polyfill::Ordering;
|
||||
use core::future::Future;
|
||||
use cortex_m::peripheral::SYST;
|
||||
pub use fugit;
|
||||
/// Common definitions and traits for using the systick monotonic
|
||||
pub mod prelude {
|
||||
pub use crate::systick_monotonic;
|
||||
|
||||
pub use crate::Monotonic;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "systick-64bit")] {
|
||||
pub use fugit::{self, ExtU64, ExtU64Ceil};
|
||||
} else {
|
||||
pub use fugit::{self, ExtU32, ExtU32Ceil};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use cortex_m::peripheral::SYST;
|
||||
|
||||
use atomic_polyfill::Ordering;
|
||||
use rtic_time::timer_queue::TimerQueue;
|
||||
|
||||
use crate::TimerQueueBackend;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "systick-64bit")] {
|
||||
pub use fugit::{ExtU64, ExtU64Ceil};
|
||||
use atomic_polyfill::AtomicU64;
|
||||
static SYSTICK_CNT: AtomicU64 = AtomicU64::new(0);
|
||||
} else {
|
||||
pub use fugit::{ExtU32, ExtU32Ceil};
|
||||
use atomic_polyfill::AtomicU32;
|
||||
static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0);
|
||||
}
|
||||
}
|
||||
static SYSTICK_TIMER_QUEUE: TimerQueue<Systick> = TimerQueue::new();
|
||||
|
||||
// Features should be additive, here systick-100hz gets picked if both
|
||||
// `systick-100hz` and `systick-10khz` are enabled.
|
||||
static SYSTICK_TIMER_QUEUE: TimerQueue<SystickBackend> = TimerQueue::new();
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "systick-100hz")]
|
||||
{
|
||||
const TIMER_HZ: u32 = 100;
|
||||
} else if #[cfg(feature = "systick-10khz")]
|
||||
{
|
||||
const TIMER_HZ: u32 = 10_000;
|
||||
} else {
|
||||
// Default case is 1 kHz
|
||||
const TIMER_HZ: u32 = 1_000;
|
||||
}
|
||||
}
|
||||
/// Systick based [`TimerQueueBackend`].
|
||||
pub struct SystickBackend;
|
||||
|
||||
/// Systick implementing [`Monotonic`] which runs at 1 kHz, 100Hz or 10 kHz.
|
||||
pub struct Systick;
|
||||
|
||||
impl Systick {
|
||||
/// Start a `Monotonic` based on SysTick.
|
||||
impl SystickBackend {
|
||||
/// Starts the monotonic timer.
|
||||
///
|
||||
/// The `sysclk` parameter is the speed at which SysTick runs at. This value should come from
|
||||
/// the clock generation function of the used HAL.
|
||||
/// **Do not use this function directly.**
|
||||
///
|
||||
/// Notice that the actual rate of the timer is a best approximation based on the given
|
||||
/// `sysclk` and `TIMER_HZ`.
|
||||
///
|
||||
/// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue.
|
||||
pub fn start(
|
||||
mut systick: cortex_m::peripheral::SYST,
|
||||
sysclk: u32,
|
||||
_interrupt_token: impl crate::InterruptToken<Self>,
|
||||
) {
|
||||
// + TIMER_HZ / 2 provides round to nearest instead of round to 0.
|
||||
// - 1 as the counter range is inclusive [0, reload]
|
||||
let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1;
|
||||
/// Use the prelude macros instead.
|
||||
pub fn _start(mut systick: SYST, sysclk: u32, timer_hz: u32) {
|
||||
assert!(
|
||||
(sysclk % timer_hz) == 0,
|
||||
"timer_hz cannot evenly divide sysclk! Please adjust the timer or sysclk frequency."
|
||||
);
|
||||
let reload = sysclk / timer_hz - 1;
|
||||
|
||||
assert!(reload <= 0x00ff_ffff);
|
||||
assert!(reload > 0);
|
||||
|
@ -98,7 +84,7 @@ impl Systick {
|
|||
systick.enable_interrupt();
|
||||
systick.enable_counter();
|
||||
|
||||
SYSTICK_TIMER_QUEUE.initialize(Systick {});
|
||||
SYSTICK_TIMER_QUEUE.initialize(SystickBackend {});
|
||||
}
|
||||
|
||||
fn systick() -> SYST {
|
||||
|
@ -106,67 +92,24 @@ impl Systick {
|
|||
}
|
||||
}
|
||||
|
||||
// Forward timerqueue interface
|
||||
impl Systick {
|
||||
/// Used to access the underlying timer queue
|
||||
#[doc(hidden)]
|
||||
pub fn __tq() -> &'static TimerQueue<Systick> {
|
||||
&SYSTICK_TIMER_QUEUE
|
||||
}
|
||||
|
||||
/// Timeout at a specific time.
|
||||
pub async fn timeout_at<F: Future>(
|
||||
instant: <Self as Monotonic>::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
SYSTICK_TIMER_QUEUE.timeout_at(instant, future).await
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
SYSTICK_TIMER_QUEUE.timeout_after(duration, future).await
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
SYSTICK_TIMER_QUEUE.delay(duration).await;
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
#[inline]
|
||||
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||
SYSTICK_TIMER_QUEUE.delay_until(instant).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl Monotonic for Systick {
|
||||
impl TimerQueueBackend for SystickBackend {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "systick-64bit")] {
|
||||
type Instant = fugit::TimerInstantU64<TIMER_HZ>;
|
||||
type Duration = fugit::TimerDurationU64<TIMER_HZ>;
|
||||
type Ticks = u64;
|
||||
} else {
|
||||
type Instant = fugit::TimerInstantU32<TIMER_HZ>;
|
||||
type Duration = fugit::TimerDurationU32<TIMER_HZ>;
|
||||
type Ticks = u32;
|
||||
}
|
||||
}
|
||||
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
fn now() -> Self::Ticks {
|
||||
if Self::systick().has_wrapped() {
|
||||
SYSTICK_CNT.fetch_add(1, Ordering::AcqRel);
|
||||
}
|
||||
|
||||
Self::Instant::from_ticks(SYSTICK_CNT.load(Ordering::Relaxed))
|
||||
SYSTICK_CNT.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
fn set_compare(_: Self::Instant) {
|
||||
fn set_compare(_: Self::Ticks) {
|
||||
// No need to do something here, we get interrupts anyway.
|
||||
}
|
||||
|
||||
|
@ -184,39 +127,66 @@ impl Monotonic for Systick {
|
|||
}
|
||||
}
|
||||
|
||||
fn enable_timer() {}
|
||||
|
||||
fn disable_timer() {}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "systick-64bit")] {
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!(Systick);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!(Systick);
|
||||
} else {
|
||||
rtic_time::embedded_hal_delay_impl_fugit32!(Systick);
|
||||
|
||||
#[cfg(feature = "embedded-hal-async")]
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit32!(Systick);
|
||||
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||
&SYSTICK_TIMER_QUEUE
|
||||
}
|
||||
}
|
||||
|
||||
/// Register the Systick interrupt for the monotonic.
|
||||
/// Create a Systick based monotonic and register the Systick interrupt for it.
|
||||
///
|
||||
/// See [`crate::systick`] for more details.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `name` - The name that the monotonic type will have.
|
||||
/// * `tick_rate_hz` - The tick rate of the timer peripheral.
|
||||
/// Can be omitted; defaults to 1kHz.
|
||||
#[macro_export]
|
||||
macro_rules! create_systick_token {
|
||||
() => {{
|
||||
macro_rules! systick_monotonic {
|
||||
($name:ident) => {
|
||||
$crate::systick_monotonic($name, 1_000);
|
||||
};
|
||||
($name:ident, $tick_rate_hz:expr) => {
|
||||
/// A `Monotonic` based on SysTick.
|
||||
struct $name;
|
||||
|
||||
impl $name {
|
||||
/// Starts the `Monotonic`.
|
||||
///
|
||||
/// The `sysclk` parameter is the speed at which SysTick runs at. This value should come from
|
||||
/// the clock generation function of the used HAL.
|
||||
///
|
||||
/// Panics if it is impossible to achieve the desired monotonic tick rate based
|
||||
/// on the given `sysclk` parameter. If that happens, adjust the desired monotonic tick rate.
|
||||
///
|
||||
/// This method must be called only once.
|
||||
pub fn start(systick: $crate::systick::SYST, sysclk: u32) {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case)]
|
||||
unsafe extern "C" fn SysTick() {
|
||||
$crate::systick::Systick::__tq().on_monotonic_interrupt();
|
||||
use $crate::TimerQueueBackend;
|
||||
$crate::systick::SystickBackend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
|
||||
pub struct SystickToken;
|
||||
|
||||
unsafe impl $crate::InterruptToken<$crate::systick::Systick> for SystickToken {}
|
||||
|
||||
SystickToken
|
||||
}};
|
||||
$crate::systick::SystickBackend::_start(systick, sysclk, $tick_rate_hz);
|
||||
}
|
||||
}
|
||||
|
||||
impl $crate::TimerQueueBasedMonotonic for $name {
|
||||
type Backend = $crate::systick::SystickBackend;
|
||||
type Instant = $crate::fugit::Instant<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
type Duration = $crate::fugit::Duration<
|
||||
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
|
||||
1,
|
||||
{ $tick_rate_hz },
|
||||
>;
|
||||
}
|
||||
|
||||
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
|
||||
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,11 +5,18 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||
|
||||
## Unreleased
|
||||
## Unreleased - v2.0.0
|
||||
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
- Full rewrite of the `Monotonic` API.
|
||||
- Now split into multiple traits:
|
||||
- `Monotonic` - A user-facing trait that defines what the functionality of a monotonic is.
|
||||
- `TimerQueueBackend` - The set of functionality a backend must provide in order to be used with the `TimerQueue`.
|
||||
- `TimerQueue` is now purely based on ticks and has no concept of real time.
|
||||
- The `TimerQueueBasedMonotonic` trait implements a `Monotonic` based on a `TimerQueueBackend`, translating ticks into `Instant` and `Duration`.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "rtic-time"
|
||||
version = "1.3.0"
|
||||
version = "2.0.0"
|
||||
|
||||
edition = "2021"
|
||||
authors = [
|
||||
|
@ -11,7 +11,7 @@ authors = [
|
|||
"Per Lindgren <per.lindgren@ltu.se>",
|
||||
]
|
||||
categories = ["concurrency", "embedded", "no-std", "asynchronous"]
|
||||
description = "rtic-time lib TODO"
|
||||
description = "Basic definitions and utilities that can be used to keep track of time"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rtic-rs/rtic"
|
||||
|
||||
|
@ -21,11 +21,11 @@ repository = "https://github.com/rtic-rs/rtic"
|
|||
critical-section = "1"
|
||||
futures-util = { version = "0.3.25", default-features = false }
|
||||
rtic-common = { version = "1.0.0", path = "../rtic-common" }
|
||||
embedded-hal = { version = "1.0.0" }
|
||||
embedded-hal-async = { version = "1.0.0" }
|
||||
fugit = "0.3.7"
|
||||
|
||||
[dev-dependencies]
|
||||
embedded-hal = { version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
fugit = "0.3.7"
|
||||
parking_lot = "0.12"
|
||||
cassette = "0.2"
|
||||
cooked-waker = "5.0.0"
|
||||
|
|
29
rtic-time/README.md
Normal file
29
rtic-time/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
# rtic-time
|
||||
|
||||
Basic definitions and utilities that can be used to keep track of time.
|
||||
|
||||
[![crates.io](https://img.shields.io/crates/v/rtic-time)](https://crates.io/crates/rtic-time)
|
||||
[![docs.rs](https://docs.rs/rtic-time/badge.svg)](https://docs.rs/rtic-time)
|
||||
[![matrix](https://img.shields.io/matrix/rtic:matrix.org)](https://matrix.to/#/#rtic:matrix.org)
|
||||
|
||||
|
||||
## Content
|
||||
|
||||
The main contribution of this crate is to define the [`Monotonic`](https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html) trait. It serves as a standardized interface for libraries to interact with the system's monotonic timers.
|
||||
|
||||
Additionally, this crate provides tools and utilities that help with implementing monotonic timers.
|
||||
|
||||
## Implementations of the `Monotonic` trait
|
||||
|
||||
For implementations of [`Monotonic`](https://docs.rs/rtic-time/latest/rtic_time/trait.Monotonic.html)
|
||||
on various hardware, see [`rtic-monotonics`](https://docs.rs/rtic-monotonics/).
|
||||
|
||||
|
||||
## Chat
|
||||
|
||||
Join us and talk about RTIC in the [Matrix room][matrix-room].
|
||||
|
||||
Weekly meeting minutes can be found over at [RTIC HackMD][hackmd].
|
||||
|
||||
[matrix-room]: https://matrix.to/#/#rtic:matrix.org
|
||||
[hackmd]: https://rtic.rs/meeting
|
|
@ -5,285 +5,60 @@
|
|||
|
||||
#![no_std]
|
||||
#![deny(missing_docs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::pin::Pin;
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use core::task::{Poll, Waker};
|
||||
use futures_util::{
|
||||
future::{select, Either},
|
||||
pin_mut,
|
||||
};
|
||||
use linked_list::{Link, LinkedList};
|
||||
pub use monotonic::Monotonic;
|
||||
use rtic_common::dropper::OnDrop;
|
||||
#![allow(async_fn_in_trait)]
|
||||
|
||||
pub mod half_period_counter;
|
||||
mod linked_list;
|
||||
mod monotonic;
|
||||
|
||||
/// Holds a waker and at which time instant this waker shall be awoken.
|
||||
struct WaitingWaker<Mono: Monotonic> {
|
||||
waker: Waker,
|
||||
release_at: Mono::Instant,
|
||||
was_popped: AtomicBool,
|
||||
}
|
||||
|
||||
impl<Mono: Monotonic> Clone for WaitingWaker<Mono> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
waker: self.waker.clone(),
|
||||
release_at: self.release_at,
|
||||
was_popped: AtomicBool::new(self.was_popped.load(Ordering::Relaxed)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Mono: Monotonic> PartialEq for WaitingWaker<Mono> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.release_at == other.release_at
|
||||
}
|
||||
}
|
||||
|
||||
impl<Mono: Monotonic> PartialOrd for WaitingWaker<Mono> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
self.release_at.partial_cmp(&other.release_at)
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic timer queue for async executors.
|
||||
///
|
||||
/// # Blocking
|
||||
///
|
||||
/// The internal priority queue uses global critical sections to manage access. This means that
|
||||
/// `await`ing a delay will cause a lock of the entire system for O(n) time. In practice the lock
|
||||
/// duration is ~10 clock cycles per element in the queue.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This timer queue is based on an intrusive linked list, and by extension the links are strored
|
||||
/// on the async stacks of callers. The links are deallocated on `drop` or when the wait is
|
||||
/// complete.
|
||||
///
|
||||
/// Do not call `mem::forget` on an awaited future, or there will be dragons!
|
||||
pub struct TimerQueue<Mono: Monotonic> {
|
||||
queue: LinkedList<WaitingWaker<Mono>>,
|
||||
initialized: AtomicBool,
|
||||
}
|
||||
pub mod monotonic;
|
||||
pub mod timer_queue;
|
||||
|
||||
/// This indicates that there was a timeout.
|
||||
pub struct TimeoutError;
|
||||
|
||||
/// This is needed to make the async closure in `delay_until` accept that we "share"
|
||||
/// the link possible between threads.
|
||||
struct LinkPtr<Mono: Monotonic>(*mut Option<linked_list::Link<WaitingWaker<Mono>>>);
|
||||
/// Re-export for macros
|
||||
pub use embedded_hal;
|
||||
/// Re-export for macros
|
||||
pub use embedded_hal_async;
|
||||
|
||||
impl<Mono: Monotonic> Clone for LinkPtr<Mono> {
|
||||
fn clone(&self) -> Self {
|
||||
LinkPtr(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Mono: Monotonic> LinkPtr<Mono> {
|
||||
/// This will dereference the pointer stored within and give out an `&mut`.
|
||||
unsafe fn get(&mut self) -> &mut Option<linked_list::Link<WaitingWaker<Mono>>> {
|
||||
&mut *self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Mono: Monotonic> Send for LinkPtr<Mono> {}
|
||||
unsafe impl<Mono: Monotonic> Sync for LinkPtr<Mono> {}
|
||||
|
||||
impl<Mono: Monotonic> TimerQueue<Mono> {
|
||||
/// Make a new queue.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
queue: LinkedList::new(),
|
||||
initialized: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Forwards the `Monotonic::now()` method.
|
||||
#[inline(always)]
|
||||
pub fn now(&self) -> Mono::Instant {
|
||||
Mono::now()
|
||||
}
|
||||
|
||||
/// Takes the initialized monotonic to initialize the TimerQueue.
|
||||
pub fn initialize(&self, monotonic: Mono) {
|
||||
self.initialized.store(true, Ordering::SeqCst);
|
||||
|
||||
// Don't run drop on `Mono`
|
||||
core::mem::forget(monotonic);
|
||||
}
|
||||
|
||||
/// Call this in the interrupt handler of the hardware timer supporting the `Monotonic`
|
||||
/// # A monotonic clock / counter definition.
|
||||
///
|
||||
/// # Safety
|
||||
/// ## Correctness
|
||||
///
|
||||
/// It's always safe to call, but it must only be called from the interrupt of the
|
||||
/// monotonic timer for correct operation.
|
||||
pub unsafe fn on_monotonic_interrupt(&self) {
|
||||
Mono::clear_compare_flag();
|
||||
Mono::on_interrupt();
|
||||
/// The trait enforces that proper time-math is implemented between `Instant` and `Duration`. This
|
||||
/// is a requirement on the time library that the user chooses to use.
|
||||
pub trait Monotonic {
|
||||
/// The type for instant, defining an instant in time.
|
||||
///
|
||||
/// **Note:** In all APIs in RTIC that use instants from this monotonic, this type will be used.
|
||||
type Instant: Ord
|
||||
+ Copy
|
||||
+ core::ops::Add<Self::Duration, Output = Self::Instant>
|
||||
+ core::ops::Sub<Self::Duration, Output = Self::Instant>
|
||||
+ core::ops::Sub<Self::Instant, Output = Self::Duration>;
|
||||
|
||||
loop {
|
||||
let mut release_at = None;
|
||||
let head = self.queue.pop_if(|head| {
|
||||
release_at = Some(head.release_at);
|
||||
/// The type for duration, defining a duration of time.
|
||||
///
|
||||
/// **Note:** In all APIs in RTIC that use duration from this monotonic, this type will be used.
|
||||
type Duration: Copy;
|
||||
|
||||
let should_pop = Mono::now() >= head.release_at;
|
||||
head.was_popped.store(should_pop, Ordering::Relaxed);
|
||||
/// Get the current time.
|
||||
fn now() -> Self::Instant;
|
||||
|
||||
should_pop
|
||||
});
|
||||
|
||||
match (head, release_at) {
|
||||
(Some(link), _) => {
|
||||
link.waker.wake();
|
||||
}
|
||||
(None, Some(instant)) => {
|
||||
Mono::enable_timer();
|
||||
Mono::set_compare(instant);
|
||||
|
||||
if Mono::now() >= instant {
|
||||
// The time for the next instant passed while handling it,
|
||||
// continue dequeueing
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
(None, None) => {
|
||||
// Queue is empty
|
||||
Mono::disable_timer();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Timeout at a specific time.
|
||||
pub async fn timeout_at<F: Future>(
|
||||
&self,
|
||||
instant: Mono::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
let delay = self.delay_until(instant);
|
||||
|
||||
pin_mut!(future);
|
||||
pin_mut!(delay);
|
||||
|
||||
match select(future, delay).await {
|
||||
Either::Left((r, _)) => Ok(r),
|
||||
Either::Right(_) => Err(TimeoutError),
|
||||
}
|
||||
}
|
||||
|
||||
/// Timeout after at least a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: Future>(
|
||||
&self,
|
||||
duration: Mono::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
let now = Mono::now();
|
||||
let mut timeout = now + duration;
|
||||
if now != timeout {
|
||||
timeout = timeout + Mono::TICK_PERIOD;
|
||||
}
|
||||
|
||||
// Wait for one period longer, because by definition timers have an uncertainty
|
||||
// of one period, so waiting for 'at least' needs to compensate for that.
|
||||
self.timeout_at(timeout, future).await
|
||||
}
|
||||
|
||||
/// Delay for at least some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(&self, duration: Mono::Duration) {
|
||||
let now = Mono::now();
|
||||
let mut timeout = now + duration;
|
||||
if now != timeout {
|
||||
timeout = timeout + Mono::TICK_PERIOD;
|
||||
}
|
||||
|
||||
// Wait for one period longer, because by definition timers have an uncertainty
|
||||
// of one period, so waiting for 'at least' needs to compensate for that.
|
||||
self.delay_until(timeout).await;
|
||||
}
|
||||
/// Delay for some duration of time.
|
||||
async fn delay(duration: Self::Duration);
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
pub async fn delay_until(&self, instant: Mono::Instant) {
|
||||
if !self.initialized.load(Ordering::Relaxed) {
|
||||
panic!(
|
||||
"The timer queue is not initialized with a monotonic, you need to run `initialize`"
|
||||
);
|
||||
}
|
||||
|
||||
let mut link_ptr: Option<linked_list::Link<WaitingWaker<Mono>>> = None;
|
||||
|
||||
// Make this future `Drop`-safe
|
||||
// SAFETY(link_ptr): Shadow the original definition of `link_ptr` so we can't abuse it.
|
||||
let mut link_ptr =
|
||||
LinkPtr(&mut link_ptr as *mut Option<linked_list::Link<WaitingWaker<Mono>>>);
|
||||
let mut link_ptr2 = link_ptr.clone();
|
||||
|
||||
let queue = &self.queue;
|
||||
let marker = &AtomicUsize::new(0);
|
||||
|
||||
let dropper = OnDrop::new(|| {
|
||||
queue.delete(marker.load(Ordering::Relaxed));
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
if Mono::now() >= instant {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
// SAFETY: This pointer is only dereferenced here and on drop of the future
|
||||
// which happens outside this `poll_fn`'s stack frame, so this mutable access cannot
|
||||
// happen at the same time as `dropper` runs.
|
||||
let link = unsafe { link_ptr2.get() };
|
||||
if link.is_none() {
|
||||
let link_ref = link.insert(Link::new(WaitingWaker {
|
||||
waker: cx.waker().clone(),
|
||||
release_at: instant,
|
||||
was_popped: AtomicBool::new(false),
|
||||
}));
|
||||
|
||||
// SAFETY(new_unchecked): The address to the link is stable as it is defined
|
||||
//outside this stack frame.
|
||||
// SAFETY(insert): `link_ref` lifetime comes from `link_ptr` that is shadowed, and
|
||||
// we make sure in `dropper` that the link is removed from the queue before
|
||||
// dropping `link_ptr` AND `dropper` makes sure that the shadowed `link_ptr` lives
|
||||
// until the end of the stack frame.
|
||||
let (head_updated, addr) = unsafe { queue.insert(Pin::new_unchecked(link_ref)) };
|
||||
|
||||
marker.store(addr, Ordering::Relaxed);
|
||||
|
||||
if head_updated {
|
||||
// Pend the monotonic handler if the queue head was updated.
|
||||
Mono::pend_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
|
||||
// SAFETY: We only run this and dereference the pointer if we have
|
||||
// exited the `poll_fn` below in the `drop(dropper)` call. The other dereference
|
||||
// of this pointer is in the `poll_fn`.
|
||||
if let Some(link) = unsafe { link_ptr.get() } {
|
||||
if link.val.was_popped.load(Ordering::Relaxed) {
|
||||
// If it was popped from the queue there is no need to run delete
|
||||
dropper.defuse();
|
||||
}
|
||||
} else {
|
||||
// Make sure that our link is deleted from the list before we drop this stack
|
||||
drop(dropper);
|
||||
}
|
||||
}
|
||||
async fn delay_until(instant: Self::Instant);
|
||||
|
||||
/// Timeout at a specific time.
|
||||
async fn timeout_at<F: core::future::Future>(
|
||||
instant: Self::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError>;
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
async fn timeout_after<F: core::future::Future>(
|
||||
duration: Self::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError>;
|
||||
}
|
||||
|
|
|
@ -1,236 +1,8 @@
|
|||
//! A monotonic clock / counter definition.
|
||||
//! Structs and traits surrounding the [`Monotonic`](crate::Monotonic) trait.
|
||||
|
||||
/// # A monotonic clock / counter definition.
|
||||
///
|
||||
/// ## Correctness
|
||||
///
|
||||
/// The trait enforces that proper time-math is implemented between `Instant` and `Duration`. This
|
||||
/// is a requirement on the time library that the user chooses to use.
|
||||
pub trait Monotonic {
|
||||
/// The time at time zero.
|
||||
const ZERO: Self::Instant;
|
||||
|
||||
/// The duration between two timer ticks.
|
||||
const TICK_PERIOD: Self::Duration;
|
||||
|
||||
/// The type for instant, defining an instant in time.
|
||||
///
|
||||
/// **Note:** In all APIs in RTIC that use instants from this monotonic, this type will be used.
|
||||
type Instant: Ord
|
||||
+ Copy
|
||||
+ core::ops::Add<Self::Duration, Output = Self::Instant>
|
||||
+ core::ops::Sub<Self::Duration, Output = Self::Instant>
|
||||
+ core::ops::Sub<Self::Instant, Output = Self::Duration>;
|
||||
|
||||
/// The type for duration, defining an duration of time.
|
||||
///
|
||||
/// **Note:** In all APIs in RTIC that use duration from this monotonic, this type will be used.
|
||||
type Duration;
|
||||
|
||||
/// Get the current time.
|
||||
fn now() -> Self::Instant;
|
||||
|
||||
/// Set the compare value of the timer interrupt.
|
||||
///
|
||||
/// **Note:** This method does not need to handle race conditions of the monotonic, the timer
|
||||
/// queue in RTIC checks this.
|
||||
fn set_compare(instant: Self::Instant);
|
||||
|
||||
/// This method used to be required by an errata workaround
|
||||
/// for the nrf52 family, but it has been disabled as the
|
||||
/// workaround was erroneous.
|
||||
#[deprecated(
|
||||
since = "1.2.0",
|
||||
note = "this method is erroneous and has been disabled"
|
||||
)]
|
||||
fn should_dequeue_check(_: Self::Instant) -> bool {
|
||||
panic!("This method should not be used as it is erroneous.")
|
||||
}
|
||||
|
||||
/// Clear the compare interrupt flag.
|
||||
fn clear_compare_flag();
|
||||
|
||||
/// Pend the timer's interrupt.
|
||||
fn pend_interrupt();
|
||||
|
||||
/// Optional. Runs on interrupt before any timer queue handling.
|
||||
fn on_interrupt() {}
|
||||
|
||||
/// Optional. This is used to save power, this is called when the timer queue is not empty.
|
||||
///
|
||||
/// Enabling and disabling the monotonic needs to propagate to `now` so that an instant
|
||||
/// based of `now()` is still valid.
|
||||
///
|
||||
/// NOTE: This may be called more than once.
|
||||
fn enable_timer() {}
|
||||
|
||||
/// Optional. This is used to save power, this is called when the timer queue is empty.
|
||||
///
|
||||
/// Enabling and disabling the monotonic needs to propagate to `now` so that an instant
|
||||
/// based of `now()` is still valid.
|
||||
///
|
||||
/// NOTE: This may be called more than once.
|
||||
fn disable_timer() {}
|
||||
}
|
||||
|
||||
/// Creates impl blocks for [`embedded_hal::delay::DelayNs`][DelayNs],
|
||||
/// based on [`fugit::ExtU64Ceil`][ExtU64Ceil].
|
||||
///
|
||||
/// [DelayNs]: https://docs.rs/embedded-hal/latest/embedded_hal/delay/trait.DelayNs.html
|
||||
/// [ExtU64Ceil]: https://docs.rs/fugit/latest/fugit/trait.ExtU64Ceil.html
|
||||
#[macro_export]
|
||||
macro_rules! embedded_hal_delay_impl_fugit64 {
|
||||
($t:ty) => {
|
||||
impl ::embedded_hal::delay::DelayNs for $t {
|
||||
fn delay_ns(&mut self, ns: u32) {
|
||||
use ::fugit::ExtU64Ceil;
|
||||
|
||||
let now = Self::now();
|
||||
let mut done = now + u64::from(ns).nanos_at_least();
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done += Self::TICK_PERIOD;
|
||||
}
|
||||
|
||||
while Self::now() < done {}
|
||||
}
|
||||
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
use ::fugit::ExtU64Ceil;
|
||||
|
||||
let now = Self::now();
|
||||
let mut done = now + u64::from(us).micros_at_least();
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done += Self::TICK_PERIOD;
|
||||
}
|
||||
|
||||
while Self::now() < done {}
|
||||
}
|
||||
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
use ::fugit::ExtU64Ceil;
|
||||
|
||||
let now = Self::now();
|
||||
let mut done = now + u64::from(ms).millis_at_least();
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done += Self::TICK_PERIOD;
|
||||
}
|
||||
|
||||
while Self::now() < done {}
|
||||
}
|
||||
}
|
||||
pub use timer_queue_based_monotonic::{
|
||||
TimerQueueBasedDuration, TimerQueueBasedInstant, TimerQueueBasedMonotonic,
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates impl blocks for [`embedded_hal_async::delay::DelayNs`][DelayNs],
|
||||
/// based on [`fugit::ExtU64Ceil`][ExtU64Ceil].
|
||||
///
|
||||
/// [DelayNs]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/delay/trait.DelayNs.html
|
||||
/// [ExtU64Ceil]: https://docs.rs/fugit/latest/fugit/trait.ExtU64Ceil.html
|
||||
#[macro_export]
|
||||
macro_rules! embedded_hal_async_delay_impl_fugit64 {
|
||||
($t:ty) => {
|
||||
impl ::embedded_hal_async::delay::DelayNs for $t {
|
||||
#[inline]
|
||||
async fn delay_ns(&mut self, ns: u32) {
|
||||
use ::fugit::ExtU64Ceil;
|
||||
Self::delay(u64::from(ns).nanos_at_least()).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn delay_us(&mut self, us: u32) {
|
||||
use ::fugit::ExtU64Ceil;
|
||||
Self::delay(u64::from(us).micros_at_least()).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn delay_ms(&mut self, ms: u32) {
|
||||
use ::fugit::ExtU64Ceil;
|
||||
Self::delay(u64::from(ms).millis_at_least()).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates impl blocks for [`embedded_hal::delay::DelayNs`][DelayNs],
|
||||
/// based on [`fugit::ExtU32Ceil`][ExtU32Ceil].
|
||||
///
|
||||
/// [DelayNs]: https://docs.rs/embedded-hal/latest/embedded_hal/delay/trait.DelayNs.html
|
||||
/// [ExtU32Ceil]: https://docs.rs/fugit/latest/fugit/trait.ExtU32Ceil.html
|
||||
#[macro_export]
|
||||
macro_rules! embedded_hal_delay_impl_fugit32 {
|
||||
($t:ty) => {
|
||||
impl ::embedded_hal::delay::DelayNs for $t {
|
||||
fn delay_ns(&mut self, ns: u32) {
|
||||
use ::fugit::ExtU32Ceil;
|
||||
|
||||
let now = Self::now();
|
||||
let mut done = now + ns.nanos_at_least();
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done += Self::TICK_PERIOD;
|
||||
}
|
||||
|
||||
while Self::now() < done {}
|
||||
}
|
||||
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
use ::fugit::ExtU32Ceil;
|
||||
|
||||
let now = Self::now();
|
||||
let mut done = now + us.micros_at_least();
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done += Self::TICK_PERIOD;
|
||||
}
|
||||
|
||||
while Self::now() < done {}
|
||||
}
|
||||
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
use ::fugit::ExtU32Ceil;
|
||||
|
||||
let now = Self::now();
|
||||
let mut done = now + ms.millis_at_least();
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done += Self::TICK_PERIOD;
|
||||
}
|
||||
|
||||
while Self::now() < done {}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates impl blocks for [`embedded_hal_async::delay::DelayNs`][DelayNs],
|
||||
/// based on [`fugit::ExtU32Ceil`][ExtU32Ceil].
|
||||
///
|
||||
/// [DelayNs]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/delay/trait.DelayNs.html
|
||||
/// [ExtU32Ceil]: https://docs.rs/fugit/latest/fugit/trait.ExtU32Ceil.html
|
||||
#[macro_export]
|
||||
macro_rules! embedded_hal_async_delay_impl_fugit32 {
|
||||
($t:ty) => {
|
||||
impl ::embedded_hal_async::delay::DelayNs for $t {
|
||||
#[inline]
|
||||
async fn delay_ns(&mut self, ns: u32) {
|
||||
use ::fugit::ExtU32Ceil;
|
||||
Self::delay(ns.nanos_at_least()).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn delay_us(&mut self, us: u32) {
|
||||
use ::fugit::ExtU32Ceil;
|
||||
Self::delay(us.micros_at_least()).await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn delay_ms(&mut self, ms: u32) {
|
||||
use ::fugit::ExtU32Ceil;
|
||||
Self::delay(ms.millis_at_least()).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
mod embedded_hal_macros;
|
||||
mod timer_queue_based_monotonic;
|
||||
|
|
77
rtic-time/src/monotonic/embedded_hal_macros.rs
Normal file
77
rtic-time/src/monotonic/embedded_hal_macros.rs
Normal file
|
@ -0,0 +1,77 @@
|
|||
//! Macros that implement embedded-hal traits for Monotonics
|
||||
|
||||
/// Implements [`embedded_hal::delay::DelayNs`] for a given monotonic.
|
||||
#[macro_export]
|
||||
macro_rules! impl_embedded_hal_delay_fugit {
|
||||
($t:ty) => {
|
||||
impl $crate::embedded_hal::delay::DelayNs for $t {
|
||||
fn delay_ns(&mut self, ns: u32) {
|
||||
let now = <Self as $crate::Monotonic>::now();
|
||||
let mut done =
|
||||
now + <Self as $crate::Monotonic>::Duration::nanos_at_least(ns.into());
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done = done + <Self as $crate::Monotonic>::Duration::from_ticks(1);
|
||||
}
|
||||
|
||||
while <Self as $crate::Monotonic>::now() < done {}
|
||||
}
|
||||
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
let now = <Self as $crate::Monotonic>::now();
|
||||
let mut done =
|
||||
now + <Self as $crate::Monotonic>::Duration::micros_at_least(us.into());
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done = done + <Self as $crate::Monotonic>::Duration::from_ticks(1);
|
||||
}
|
||||
|
||||
while <Self as $crate::Monotonic>::now() < done {}
|
||||
}
|
||||
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
let now = <Self as $crate::Monotonic>::now();
|
||||
let mut done =
|
||||
now + <Self as $crate::Monotonic>::Duration::millis_at_least(ms.into());
|
||||
if now != done {
|
||||
// Compensate for sub-tick uncertainty
|
||||
done = done + <Self as $crate::Monotonic>::Duration::from_ticks(1);
|
||||
}
|
||||
|
||||
while <Self as $crate::Monotonic>::now() < done {}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implements [`embedded_hal_async::delay::DelayNs`] for a given monotonic.
|
||||
#[macro_export]
|
||||
macro_rules! impl_embedded_hal_async_delay_fugit {
|
||||
($t:ty) => {
|
||||
impl $crate::embedded_hal_async::delay::DelayNs for $t {
|
||||
#[inline]
|
||||
async fn delay_ns(&mut self, ns: u32) {
|
||||
<Self as $crate::Monotonic>::delay(
|
||||
<Self as $crate::Monotonic>::Duration::nanos_at_least(ns.into()),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn delay_us(&mut self, us: u32) {
|
||||
<Self as $crate::Monotonic>::delay(
|
||||
<Self as $crate::Monotonic>::Duration::micros_at_least(us.into()),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn delay_ms(&mut self, ms: u32) {
|
||||
<Self as $crate::Monotonic>::delay(
|
||||
<Self as $crate::Monotonic>::Duration::millis_at_least(ms.into()),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
113
rtic-time/src/monotonic/timer_queue_based_monotonic.rs
Normal file
113
rtic-time/src/monotonic/timer_queue_based_monotonic.rs
Normal file
|
@ -0,0 +1,113 @@
|
|||
use crate::{timer_queue::TimerQueueBackend, TimeoutError};
|
||||
|
||||
use crate::Monotonic;
|
||||
|
||||
/// A [`Monotonic`] that is backed by the [`TimerQueue`](crate::timer_queue::TimerQueue).
|
||||
pub trait TimerQueueBasedMonotonic {
|
||||
/// The backend for the timer queue
|
||||
type Backend: TimerQueueBackend;
|
||||
|
||||
/// The type for instant, defining an instant in time.
|
||||
///
|
||||
/// **Note:** In all APIs in RTIC that use instants from this monotonic, this type will be used.
|
||||
type Instant: TimerQueueBasedInstant<Ticks = <Self::Backend as TimerQueueBackend>::Ticks>
|
||||
+ core::ops::Add<Self::Duration, Output = Self::Instant>
|
||||
+ core::ops::Sub<Self::Duration, Output = Self::Instant>
|
||||
+ core::ops::Sub<Self::Instant, Output = Self::Duration>;
|
||||
|
||||
/// The type for duration, defining a duration of time.
|
||||
///
|
||||
/// **Note:** In all APIs in RTIC that use duration from this monotonic, this type will be used.
|
||||
type Duration: TimerQueueBasedDuration<Ticks = <Self::Backend as TimerQueueBackend>::Ticks>;
|
||||
}
|
||||
|
||||
impl<T: TimerQueueBasedMonotonic> Monotonic for T {
|
||||
type Instant = T::Instant;
|
||||
type Duration = T::Duration;
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
Self::Instant::from_ticks(T::Backend::timer_queue().now())
|
||||
}
|
||||
|
||||
async fn delay(duration: Self::Duration) {
|
||||
T::Backend::timer_queue().delay(duration.ticks()).await
|
||||
}
|
||||
|
||||
async fn delay_until(instant: Self::Instant) {
|
||||
T::Backend::timer_queue().delay_until(instant.ticks()).await
|
||||
}
|
||||
|
||||
async fn timeout_at<F: core::future::Future>(
|
||||
instant: Self::Instant,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
T::Backend::timer_queue()
|
||||
.timeout_at(instant.ticks(), future)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn timeout_after<F: core::future::Future>(
|
||||
duration: Self::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
T::Backend::timer_queue()
|
||||
.timeout_after(duration.ticks(), future)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// An instant that can be used in [`TimerQueueBasedMonotonic`].
|
||||
pub trait TimerQueueBasedInstant: Ord + Copy {
|
||||
/// The internal type of the instant
|
||||
type Ticks;
|
||||
/// Convert from ticks to the instant
|
||||
fn from_ticks(ticks: Self::Ticks) -> Self;
|
||||
/// Convert the instant to ticks
|
||||
fn ticks(self) -> Self::Ticks;
|
||||
}
|
||||
|
||||
/// A duration that can be used in [`TimerQueueBasedMonotonic`].
|
||||
pub trait TimerQueueBasedDuration: Copy {
|
||||
/// The internal type of the duration
|
||||
type Ticks;
|
||||
/// Convert the duration to ticks
|
||||
fn ticks(self) -> Self::Ticks;
|
||||
}
|
||||
|
||||
impl<const NOM: u32, const DENOM: u32> TimerQueueBasedInstant for fugit::Instant<u64, NOM, DENOM> {
|
||||
type Ticks = u64;
|
||||
fn from_ticks(ticks: Self::Ticks) -> Self {
|
||||
Self::from_ticks(ticks)
|
||||
}
|
||||
fn ticks(self) -> Self::Ticks {
|
||||
Self::ticks(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const NOM: u32, const DENOM: u32> TimerQueueBasedInstant for fugit::Instant<u32, NOM, DENOM> {
|
||||
type Ticks = u32;
|
||||
fn from_ticks(ticks: Self::Ticks) -> Self {
|
||||
Self::from_ticks(ticks)
|
||||
}
|
||||
fn ticks(self) -> Self::Ticks {
|
||||
Self::ticks(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const NOM: u32, const DENOM: u32> TimerQueueBasedDuration
|
||||
for fugit::Duration<u64, NOM, DENOM>
|
||||
{
|
||||
type Ticks = u64;
|
||||
fn ticks(self) -> Self::Ticks {
|
||||
Self::ticks(&self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const NOM: u32, const DENOM: u32> TimerQueueBasedDuration
|
||||
for fugit::Duration<u32, NOM, DENOM>
|
||||
{
|
||||
type Ticks = u32;
|
||||
fn ticks(self) -> Self::Ticks {
|
||||
Self::ticks(&self)
|
||||
}
|
||||
}
|
281
rtic-time/src/timer_queue.rs
Normal file
281
rtic-time/src/timer_queue.rs
Normal file
|
@ -0,0 +1,281 @@
|
|||
//! A generic timer queue for async executors.
|
||||
|
||||
use crate::linked_list::{self, Link, LinkedList};
|
||||
use crate::TimeoutError;
|
||||
|
||||
use core::future::{poll_fn, Future};
|
||||
use core::pin::Pin;
|
||||
use core::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use core::task::{Poll, Waker};
|
||||
use futures_util::{
|
||||
future::{select, Either},
|
||||
pin_mut,
|
||||
};
|
||||
use rtic_common::dropper::OnDrop;
|
||||
|
||||
mod backend;
|
||||
mod tick_type;
|
||||
pub use backend::TimerQueueBackend;
|
||||
pub use tick_type::TimerQueueTicks;
|
||||
|
||||
/// Holds a waker and at which time instant this waker shall be awoken.
|
||||
struct WaitingWaker<Backend: TimerQueueBackend> {
|
||||
waker: Waker,
|
||||
release_at: Backend::Ticks,
|
||||
was_popped: AtomicBool,
|
||||
}
|
||||
|
||||
impl<Backend: TimerQueueBackend> Clone for WaitingWaker<Backend> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
waker: self.waker.clone(),
|
||||
release_at: self.release_at,
|
||||
was_popped: AtomicBool::new(self.was_popped.load(Ordering::Relaxed)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Backend: TimerQueueBackend> PartialEq for WaitingWaker<Backend> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.release_at == other.release_at
|
||||
}
|
||||
}
|
||||
|
||||
impl<Backend: TimerQueueBackend> PartialOrd for WaitingWaker<Backend> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.release_at.compare(other.release_at))
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic timer queue for async executors.
|
||||
///
|
||||
/// # Blocking
|
||||
///
|
||||
/// The internal priority queue uses global critical sections to manage access. This means that
|
||||
/// `await`ing a delay will cause a lock of the entire system for O(n) time. In practice the lock
|
||||
/// duration is ~10 clock cycles per element in the queue.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This timer queue is based on an intrusive linked list, and by extension the links are stored
|
||||
/// on the async stacks of callers. The links are deallocated on `drop` or when the wait is
|
||||
/// complete.
|
||||
///
|
||||
/// Do not call `mem::forget` on an awaited future, or there will be dragons!
|
||||
pub struct TimerQueue<Backend: TimerQueueBackend> {
|
||||
queue: LinkedList<WaitingWaker<Backend>>,
|
||||
initialized: AtomicBool,
|
||||
}
|
||||
|
||||
/// This is needed to make the async closure in `delay_until` accept that we "share"
|
||||
/// the link possible between threads.
|
||||
struct LinkPtr<Backend: TimerQueueBackend>(*mut Option<linked_list::Link<WaitingWaker<Backend>>>);
|
||||
|
||||
impl<Backend: TimerQueueBackend> Clone for LinkPtr<Backend> {
|
||||
fn clone(&self) -> Self {
|
||||
LinkPtr(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Backend: TimerQueueBackend> LinkPtr<Backend> {
|
||||
/// This will dereference the pointer stored within and give out an `&mut`.
|
||||
unsafe fn get(&mut self) -> &mut Option<linked_list::Link<WaitingWaker<Backend>>> {
|
||||
&mut *self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<Backend: TimerQueueBackend> Send for LinkPtr<Backend> {}
|
||||
unsafe impl<Backend: TimerQueueBackend> Sync for LinkPtr<Backend> {}
|
||||
|
||||
impl<Backend: TimerQueueBackend> TimerQueue<Backend> {
|
||||
/// Make a new queue.
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
queue: LinkedList::new(),
|
||||
initialized: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
/// Forwards the `Monotonic::now()` method.
|
||||
#[inline(always)]
|
||||
pub fn now(&self) -> Backend::Ticks {
|
||||
Backend::now()
|
||||
}
|
||||
|
||||
/// Takes the initialized monotonic to initialize the TimerQueue.
|
||||
pub fn initialize(&self, backend: Backend) {
|
||||
self.initialized.store(true, Ordering::SeqCst);
|
||||
|
||||
// Don't run drop on `Mono`
|
||||
core::mem::forget(backend);
|
||||
}
|
||||
|
||||
/// Call this in the interrupt handler of the hardware timer supporting the `Monotonic`
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It's always safe to call, but it must only be called from the interrupt of the
|
||||
/// monotonic timer for correct operation.
|
||||
pub unsafe fn on_monotonic_interrupt(&self) {
|
||||
Backend::clear_compare_flag();
|
||||
Backend::on_interrupt();
|
||||
|
||||
loop {
|
||||
let mut release_at = None;
|
||||
let head = self.queue.pop_if(|head| {
|
||||
release_at = Some(head.release_at);
|
||||
|
||||
let should_pop = Backend::now().is_at_least(head.release_at);
|
||||
head.was_popped.store(should_pop, Ordering::Relaxed);
|
||||
|
||||
should_pop
|
||||
});
|
||||
|
||||
match (head, release_at) {
|
||||
(Some(link), _) => {
|
||||
link.waker.wake();
|
||||
}
|
||||
(None, Some(instant)) => {
|
||||
Backend::enable_timer();
|
||||
Backend::set_compare(instant);
|
||||
|
||||
if Backend::now().is_at_least(instant) {
|
||||
// The time for the next instant passed while handling it,
|
||||
// continue dequeueing
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
(None, None) => {
|
||||
// Queue is empty
|
||||
Backend::disable_timer();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Timeout at a specific time.
|
||||
pub async fn timeout_at<F: Future>(
|
||||
&self,
|
||||
instant: Backend::Ticks,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
let delay = self.delay_until(instant);
|
||||
|
||||
pin_mut!(future);
|
||||
pin_mut!(delay);
|
||||
|
||||
match select(future, delay).await {
|
||||
Either::Left((r, _)) => Ok(r),
|
||||
Either::Right(_) => Err(TimeoutError),
|
||||
}
|
||||
}
|
||||
|
||||
/// Timeout after at least a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: Future>(
|
||||
&self,
|
||||
duration: Backend::Ticks,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
let now = Backend::now();
|
||||
let mut timeout = now.wrapping_add(duration);
|
||||
if now != timeout {
|
||||
timeout = timeout.wrapping_add(Backend::Ticks::ONE_TICK);
|
||||
}
|
||||
|
||||
// Wait for one period longer, because by definition timers have an uncertainty
|
||||
// of one period, so waiting for 'at least' needs to compensate for that.
|
||||
self.timeout_at(timeout, future).await
|
||||
}
|
||||
|
||||
/// Delay for at least some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(&self, duration: Backend::Ticks) {
|
||||
let now = Backend::now();
|
||||
let mut timeout = now.wrapping_add(duration);
|
||||
if now != timeout {
|
||||
timeout = timeout.wrapping_add(Backend::Ticks::ONE_TICK);
|
||||
}
|
||||
|
||||
// Wait for one period longer, because by definition timers have an uncertainty
|
||||
// of one period, so waiting for 'at least' needs to compensate for that.
|
||||
self.delay_until(timeout).await;
|
||||
}
|
||||
|
||||
/// Delay to some specific time instant.
|
||||
pub async fn delay_until(&self, instant: Backend::Ticks) {
|
||||
if !self.initialized.load(Ordering::Relaxed) {
|
||||
panic!(
|
||||
"The timer queue is not initialized with a monotonic, you need to run `initialize`"
|
||||
);
|
||||
}
|
||||
|
||||
let mut link_ptr: Option<linked_list::Link<WaitingWaker<Backend>>> = None;
|
||||
|
||||
// Make this future `Drop`-safe
|
||||
// SAFETY(link_ptr): Shadow the original definition of `link_ptr` so we can't abuse it.
|
||||
let mut link_ptr =
|
||||
LinkPtr(&mut link_ptr as *mut Option<linked_list::Link<WaitingWaker<Backend>>>);
|
||||
let mut link_ptr2 = link_ptr.clone();
|
||||
|
||||
let queue = &self.queue;
|
||||
let marker = &AtomicUsize::new(0);
|
||||
|
||||
let dropper = OnDrop::new(|| {
|
||||
queue.delete(marker.load(Ordering::Relaxed));
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
if Backend::now().is_at_least(instant) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
// SAFETY: This pointer is only dereferenced here and on drop of the future
|
||||
// which happens outside this `poll_fn`'s stack frame, so this mutable access cannot
|
||||
// happen at the same time as `dropper` runs.
|
||||
let link = unsafe { link_ptr2.get() };
|
||||
if link.is_none() {
|
||||
let link_ref = link.insert(Link::new(WaitingWaker {
|
||||
waker: cx.waker().clone(),
|
||||
release_at: instant,
|
||||
was_popped: AtomicBool::new(false),
|
||||
}));
|
||||
|
||||
// SAFETY(new_unchecked): The address to the link is stable as it is defined
|
||||
//outside this stack frame.
|
||||
// SAFETY(insert): `link_ref` lifetime comes from `link_ptr` that is shadowed, and
|
||||
// we make sure in `dropper` that the link is removed from the queue before
|
||||
// dropping `link_ptr` AND `dropper` makes sure that the shadowed `link_ptr` lives
|
||||
// until the end of the stack frame.
|
||||
let (head_updated, addr) = unsafe { queue.insert(Pin::new_unchecked(link_ref)) };
|
||||
|
||||
marker.store(addr, Ordering::Relaxed);
|
||||
|
||||
if head_updated {
|
||||
// Pend the monotonic handler if the queue head was updated.
|
||||
Backend::pend_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
|
||||
// SAFETY: We only run this and dereference the pointer if we have
|
||||
// exited the `poll_fn` below in the `drop(dropper)` call. The other dereference
|
||||
// of this pointer is in the `poll_fn`.
|
||||
if let Some(link) = unsafe { link_ptr.get() } {
|
||||
if link.val.was_popped.load(Ordering::Relaxed) {
|
||||
// If it was popped from the queue there is no need to run delete
|
||||
dropper.defuse();
|
||||
}
|
||||
} else {
|
||||
// Make sure that our link is deleted from the list before we drop this stack
|
||||
drop(dropper);
|
||||
}
|
||||
}
|
||||
}
|
44
rtic-time/src/timer_queue/backend.rs
Normal file
44
rtic-time/src/timer_queue/backend.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use super::{TimerQueue, TimerQueueTicks};
|
||||
|
||||
/// A backend definition for a monotonic clock/counter.
|
||||
pub trait TimerQueueBackend: 'static + Sized {
|
||||
/// The type for ticks.
|
||||
type Ticks: TimerQueueTicks;
|
||||
|
||||
/// Get the current time.
|
||||
fn now() -> Self::Ticks;
|
||||
|
||||
/// Set the compare value of the timer interrupt.
|
||||
///
|
||||
/// **Note:** This method does not need to handle race conditions of the monotonic, the timer
|
||||
/// queue in RTIC checks this.
|
||||
fn set_compare(instant: Self::Ticks);
|
||||
|
||||
/// Clear the compare interrupt flag.
|
||||
fn clear_compare_flag();
|
||||
|
||||
/// Pend the timer's interrupt.
|
||||
fn pend_interrupt();
|
||||
|
||||
/// Optional. Runs on interrupt before any timer queue handling.
|
||||
fn on_interrupt() {}
|
||||
|
||||
/// Optional. This is used to save power, this is called when the timer queue is not empty.
|
||||
///
|
||||
/// Enabling and disabling the monotonic needs to propagate to `now` so that an instant
|
||||
/// based of `now()` is still valid.
|
||||
///
|
||||
/// NOTE: This may be called more than once.
|
||||
fn enable_timer() {}
|
||||
|
||||
/// Optional. This is used to save power, this is called when the timer queue is empty.
|
||||
///
|
||||
/// Enabling and disabling the monotonic needs to propagate to `now` so that an instant
|
||||
/// based of `now()` is still valid.
|
||||
///
|
||||
/// NOTE: This may be called more than once.
|
||||
fn disable_timer() {}
|
||||
|
||||
/// Returns a reference to the underlying timer queue.
|
||||
fn timer_queue() -> &'static TimerQueue<Self>;
|
||||
}
|
49
rtic-time/src/timer_queue/tick_type.rs
Normal file
49
rtic-time/src/timer_queue/tick_type.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use core::cmp;
|
||||
|
||||
/// The ticks of a timer.
|
||||
pub trait TimerQueueTicks: Copy + PartialEq + Eq {
|
||||
/// Represents a single tick.
|
||||
const ONE_TICK: Self;
|
||||
|
||||
/// Compares to another tick count.
|
||||
///
|
||||
/// Takes into account timer wrapping; if the difference is more than
|
||||
/// half the value range, the result will be flipped.
|
||||
fn compare(self, other: Self) -> cmp::Ordering;
|
||||
|
||||
/// True if `self` is at the same time as `other` or later.
|
||||
///
|
||||
/// Takes into account timer wrapping; if the difference is more than
|
||||
/// half the value range, the result will be negated.
|
||||
fn is_at_least(self, other: Self) -> bool {
|
||||
match self.compare(other) {
|
||||
cmp::Ordering::Less => false,
|
||||
cmp::Ordering::Equal => true,
|
||||
cmp::Ordering::Greater => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapping addition.
|
||||
fn wrapping_add(self, other: Self) -> Self;
|
||||
}
|
||||
|
||||
impl TimerQueueTicks for u32 {
|
||||
const ONE_TICK: Self = 1;
|
||||
|
||||
fn compare(self, other: Self) -> cmp::Ordering {
|
||||
(self.wrapping_sub(other) as i32).cmp(&0)
|
||||
}
|
||||
fn wrapping_add(self, other: Self) -> Self {
|
||||
u32::wrapping_add(self, other)
|
||||
}
|
||||
}
|
||||
impl TimerQueueTicks for u64 {
|
||||
const ONE_TICK: Self = 1;
|
||||
|
||||
fn compare(self, other: Self) -> cmp::Ordering {
|
||||
(self.wrapping_sub(other) as i64).cmp(&0)
|
||||
}
|
||||
fn wrapping_add(self, other: Self) -> Self {
|
||||
u64::wrapping_add(self, other)
|
||||
}
|
||||
}
|
|
@ -15,46 +15,31 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
|
||||
use ::fugit::ExtU64Ceil;
|
||||
use cooked_waker::{IntoWaker, WakeRef};
|
||||
use fugit::ExtU64Ceil;
|
||||
use parking_lot::Mutex;
|
||||
use rtic_time::{Monotonic, TimeoutError, TimerQueue};
|
||||
use rtic_time::{
|
||||
monotonic::TimerQueueBasedMonotonic,
|
||||
timer_queue::{TimerQueue, TimerQueueBackend},
|
||||
Monotonic,
|
||||
};
|
||||
|
||||
const SUBTICKS_PER_TICK: u32 = 10;
|
||||
struct SubtickTestTimer;
|
||||
static TIMER_QUEUE: TimerQueue<SubtickTestTimer> = TimerQueue::new();
|
||||
struct SubtickTestTimerBackend;
|
||||
static TIMER_QUEUE: TimerQueue<SubtickTestTimerBackend> = TimerQueue::new();
|
||||
static NOW_SUBTICKS: AtomicU64 = AtomicU64::new(0);
|
||||
static COMPARE_TICKS: Mutex<Option<u64>> = Mutex::new(None);
|
||||
|
||||
impl Monotonic for SubtickTestTimer {
|
||||
const ZERO: Self::Instant = Self::Instant::from_ticks(0);
|
||||
const TICK_PERIOD: Self::Duration = Self::Duration::from_ticks(1);
|
||||
|
||||
type Instant = fugit::Instant<u64, SUBTICKS_PER_TICK, 1000>;
|
||||
type Duration = fugit::Duration<u64, SUBTICKS_PER_TICK, 1000>;
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
Self::Instant::from_ticks(
|
||||
NOW_SUBTICKS.load(Ordering::Relaxed) / u64::from(SUBTICKS_PER_TICK),
|
||||
)
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Instant) {
|
||||
*COMPARE_TICKS.lock() = Some(instant.ticks());
|
||||
}
|
||||
|
||||
fn clear_compare_flag() {}
|
||||
|
||||
fn pend_interrupt() {
|
||||
unsafe {
|
||||
Self::__tq().on_monotonic_interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubtickTestTimer {
|
||||
pub fn init() {
|
||||
Self::__tq().initialize(Self)
|
||||
SubtickTestTimerBackend::init();
|
||||
}
|
||||
}
|
||||
|
||||
impl SubtickTestTimerBackend {
|
||||
fn init() {
|
||||
Self::timer_queue().initialize(Self)
|
||||
}
|
||||
|
||||
pub fn tick() -> u64 {
|
||||
|
@ -70,7 +55,7 @@ impl SubtickTestTimer {
|
|||
// );
|
||||
if subticks == 0 && Some(ticks) == *compare {
|
||||
unsafe {
|
||||
Self::__tq().on_monotonic_interrupt();
|
||||
Self::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,29 +70,41 @@ impl SubtickTestTimer {
|
|||
pub fn now_subticks() -> u64 {
|
||||
NOW_SUBTICKS.load(Ordering::Relaxed)
|
||||
}
|
||||
}
|
||||
|
||||
fn __tq() -> &'static TimerQueue<Self> {
|
||||
impl TimerQueueBackend for SubtickTestTimerBackend {
|
||||
type Ticks = u64;
|
||||
|
||||
fn now() -> Self::Ticks {
|
||||
NOW_SUBTICKS.load(Ordering::Relaxed) / u64::from(SUBTICKS_PER_TICK)
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Ticks) {
|
||||
*COMPARE_TICKS.lock() = Some(instant);
|
||||
}
|
||||
|
||||
fn clear_compare_flag() {}
|
||||
|
||||
fn pend_interrupt() {
|
||||
unsafe {
|
||||
Self::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||
&TIMER_QUEUE
|
||||
}
|
||||
|
||||
/// Delay for some duration of time.
|
||||
#[inline]
|
||||
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||
Self::__tq().delay(duration).await;
|
||||
}
|
||||
|
||||
/// Timeout after a specific duration.
|
||||
#[inline]
|
||||
pub async fn timeout_after<F: core::future::Future>(
|
||||
duration: <Self as Monotonic>::Duration,
|
||||
future: F,
|
||||
) -> Result<F::Output, TimeoutError> {
|
||||
Self::__tq().timeout_after(duration, future).await
|
||||
}
|
||||
impl TimerQueueBasedMonotonic for SubtickTestTimer {
|
||||
type Backend = SubtickTestTimerBackend;
|
||||
|
||||
type Instant = fugit::Instant<u64, SUBTICKS_PER_TICK, 1000>;
|
||||
type Duration = fugit::Duration<u64, SUBTICKS_PER_TICK, 1000>;
|
||||
}
|
||||
|
||||
rtic_time::embedded_hal_delay_impl_fugit64!(SubtickTestTimer);
|
||||
rtic_time::embedded_hal_async_delay_impl_fugit64!(SubtickTestTimer);
|
||||
rtic_time::impl_embedded_hal_delay_fugit!(SubtickTestTimer);
|
||||
rtic_time::impl_embedded_hal_async_delay_fugit!(SubtickTestTimer);
|
||||
|
||||
// A simple struct that counts the number of times it is awoken. Can't
|
||||
// be awoken by value (because that would discard the counter), so we
|
||||
|
@ -144,7 +141,7 @@ impl<F: FnOnce()> Drop for OnDrop<F> {
|
|||
macro_rules! subtick_test {
|
||||
(@run $start:expr, $actual_duration:expr, $delay_fn:expr) => {{
|
||||
// forward clock to $start
|
||||
SubtickTestTimer::forward_to_subtick($start);
|
||||
SubtickTestTimerBackend::forward_to_subtick($start);
|
||||
|
||||
// call wait function
|
||||
let delay_fn = $delay_fn;
|
||||
|
@ -164,7 +161,7 @@ macro_rules! subtick_test {
|
|||
};
|
||||
|
||||
assert_eq!(wakecounter.get(), 0);
|
||||
SubtickTestTimer::tick();
|
||||
SubtickTestTimerBackend::tick();
|
||||
}
|
||||
|
||||
let expected_wakeups = {
|
||||
|
@ -177,7 +174,7 @@ macro_rules! subtick_test {
|
|||
assert_eq!(wakecounter.get(), expected_wakeups);
|
||||
|
||||
// Tick again to test that we don't get a second wake
|
||||
SubtickTestTimer::tick();
|
||||
SubtickTestTimerBackend::tick();
|
||||
assert_eq!(wakecounter.get(), expected_wakeups);
|
||||
|
||||
assert_eq!(
|
||||
|
@ -191,9 +188,9 @@ macro_rules! subtick_test {
|
|||
|
||||
(@run_blocking $start:expr, $actual_duration:expr, $delay_fn:expr) => {{
|
||||
// forward clock to $start
|
||||
SubtickTestTimer::forward_to_subtick($start);
|
||||
SubtickTestTimerBackend::forward_to_subtick($start);
|
||||
|
||||
let t_start = SubtickTestTimer::now_subticks();
|
||||
let t_start = SubtickTestTimerBackend::now_subticks();
|
||||
|
||||
let finished = AtomicBool::new(false);
|
||||
std::thread::scope(|s|{
|
||||
|
@ -204,13 +201,13 @@ macro_rules! subtick_test {
|
|||
s.spawn(||{
|
||||
sleep(Duration::from_millis(10));
|
||||
while !finished.load(Ordering::Relaxed) {
|
||||
SubtickTestTimer::tick();
|
||||
SubtickTestTimerBackend::tick();
|
||||
sleep(Duration::from_millis(10));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let t_end = SubtickTestTimer::now_subticks();
|
||||
let t_end = SubtickTestTimerBackend::now_subticks();
|
||||
let measured_duration = t_end - t_start;
|
||||
assert_eq!(
|
||||
$actual_duration,
|
||||
|
|
|
@ -2,63 +2,24 @@
|
|||
//!
|
||||
//! To run this test, you need to activate the `critical-section/std` feature.
|
||||
|
||||
use cassette::Cassette;
|
||||
use parking_lot::Mutex;
|
||||
use rtic_time::timer_queue::{TimerQueue, TimerQueueBackend};
|
||||
|
||||
mod peripheral {
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
task::{Poll, Waker},
|
||||
};
|
||||
|
||||
use cassette::Cassette;
|
||||
use parking_lot::Mutex;
|
||||
use rtic_time::{Monotonic, TimerQueue};
|
||||
|
||||
static NOW: Mutex<Option<Instant>> = Mutex::new(None);
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
|
||||
pub struct Duration(u64);
|
||||
|
||||
impl Duration {
|
||||
pub const fn from_ticks(millis: u64) -> Self {
|
||||
Self(millis)
|
||||
}
|
||||
|
||||
pub fn as_ticks(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Add<Duration> for Duration {
|
||||
type Output = Duration;
|
||||
|
||||
fn add(self, rhs: Duration) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Duration> for Instant {
|
||||
fn from(value: Duration) -> Self {
|
||||
Instant(value.0)
|
||||
}
|
||||
}
|
||||
use super::TestMonoBackend;
|
||||
|
||||
static NOW: AtomicU64 = AtomicU64::new(0);
|
||||
static WAKERS: Mutex<Vec<Waker>> = Mutex::new(Vec::new());
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
|
||||
pub struct Instant(u64);
|
||||
|
||||
impl Instant {
|
||||
const ZERO: Self = Self(0);
|
||||
|
||||
pub fn tick() -> bool {
|
||||
// If we've never ticked before, initialize the clock.
|
||||
if NOW.lock().is_none() {
|
||||
*NOW.lock() = Some(Instant::ZERO);
|
||||
}
|
||||
// We've ticked before, add one to the clock
|
||||
else {
|
||||
let now = Instant::now();
|
||||
let new_time = now + Duration(1);
|
||||
*NOW.lock() = Some(new_time);
|
||||
}
|
||||
NOW.fetch_add(1, Ordering::Release);
|
||||
|
||||
let had_wakers = !WAKERS.lock().is_empty();
|
||||
// Wake up all things waiting for a specific time to happen.
|
||||
|
@ -66,22 +27,18 @@ impl Instant {
|
|||
waker.wake_by_ref();
|
||||
}
|
||||
|
||||
let had_interrupt = TestMono::tick(false);
|
||||
let had_interrupt = TestMonoBackend::tick(false);
|
||||
|
||||
had_interrupt || had_wakers
|
||||
}
|
||||
|
||||
pub fn now() -> Self {
|
||||
NOW.lock().clone().unwrap_or(Instant::ZERO)
|
||||
pub fn now() -> u64 {
|
||||
NOW.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
pub fn elapsed(&self) -> Duration {
|
||||
Duration(Self::now().0 - self.0)
|
||||
}
|
||||
|
||||
pub async fn wait_until(time: Instant) {
|
||||
pub async fn wait_until(time: u64) {
|
||||
core::future::poll_fn(|ctx| {
|
||||
if Instant::now() >= time {
|
||||
if now() >= time {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
WAKERS.lock().push(ctx.waker().clone());
|
||||
|
@ -92,51 +49,21 @@ impl Instant {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Instant {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
static COMPARE: Mutex<Option<u64>> = Mutex::new(None);
|
||||
static TIMER_QUEUE: TimerQueue<TestMonoBackend> = TimerQueue::new();
|
||||
|
||||
impl core::ops::Add<Duration> for Instant {
|
||||
type Output = Instant;
|
||||
pub struct TestMonoBackend;
|
||||
|
||||
fn add(self, rhs: Duration) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub<Duration> for Instant {
|
||||
type Output = Instant;
|
||||
|
||||
fn sub(self, rhs: Duration) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Sub<Instant> for Instant {
|
||||
type Output = Duration;
|
||||
|
||||
fn sub(self, rhs: Instant) -> Self::Output {
|
||||
Duration(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
static COMPARE: Mutex<Option<Instant>> = Mutex::new(None);
|
||||
static TIMER_QUEUE: TimerQueue<TestMono> = TimerQueue::new();
|
||||
|
||||
pub struct TestMono;
|
||||
|
||||
impl TestMono {
|
||||
impl TestMonoBackend {
|
||||
pub fn tick(force_interrupt: bool) -> bool {
|
||||
let now = Instant::now();
|
||||
let now = peripheral::now();
|
||||
|
||||
let compare_reached = Some(now) == Self::compare();
|
||||
let interrupt = compare_reached || force_interrupt;
|
||||
|
||||
if interrupt {
|
||||
unsafe {
|
||||
TestMono::queue().on_monotonic_interrupt();
|
||||
TestMonoBackend::timer_queue().on_monotonic_interrupt();
|
||||
}
|
||||
true
|
||||
} else {
|
||||
|
@ -144,35 +71,26 @@ impl TestMono {
|
|||
}
|
||||
}
|
||||
|
||||
/// Initialize the monotonic.
|
||||
pub fn init() {
|
||||
Self::queue().initialize(Self);
|
||||
}
|
||||
|
||||
/// Used to access the underlying timer queue
|
||||
pub fn queue() -> &'static TimerQueue<TestMono> {
|
||||
&TIMER_QUEUE
|
||||
}
|
||||
|
||||
pub fn compare() -> Option<Instant> {
|
||||
pub fn compare() -> Option<u64> {
|
||||
COMPARE.lock().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Monotonic for TestMono {
|
||||
const ZERO: Self::Instant = Instant::ZERO;
|
||||
const TICK_PERIOD: Self::Duration = Duration::from_ticks(1);
|
||||
|
||||
type Instant = Instant;
|
||||
|
||||
type Duration = Duration;
|
||||
|
||||
fn now() -> Self::Instant {
|
||||
Instant::now()
|
||||
impl TestMonoBackend {
|
||||
fn init() {
|
||||
Self::timer_queue().initialize(Self);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Instant) {
|
||||
let _ = COMPARE.lock().insert(instant);
|
||||
impl TimerQueueBackend for TestMonoBackend {
|
||||
type Ticks = u64;
|
||||
|
||||
fn now() -> Self::Ticks {
|
||||
peripheral::now()
|
||||
}
|
||||
|
||||
fn set_compare(instant: Self::Ticks) {
|
||||
*COMPARE.lock() = Some(instant);
|
||||
}
|
||||
|
||||
fn clear_compare_flag() {}
|
||||
|
@ -180,42 +98,40 @@ impl Monotonic for TestMono {
|
|||
fn pend_interrupt() {
|
||||
Self::tick(true);
|
||||
}
|
||||
|
||||
fn timer_queue() -> &'static TimerQueue<Self> {
|
||||
&TIMER_QUEUE
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timer_queue() {
|
||||
TestMono::init();
|
||||
let start = Instant::ZERO;
|
||||
TestMonoBackend::init();
|
||||
let start = 0;
|
||||
|
||||
let build_delay_test = |pre_delay: Option<u64>, delay: u64| {
|
||||
let delay = Duration::from_ticks(delay);
|
||||
let pre_delay = pre_delay.map(Duration::from_ticks);
|
||||
|
||||
let total = if let Some(pre_delay) = pre_delay {
|
||||
pre_delay + delay
|
||||
} else {
|
||||
delay
|
||||
};
|
||||
let total_millis = total.as_ticks();
|
||||
|
||||
async move {
|
||||
// A `pre_delay` simulates a delay in scheduling,
|
||||
// without the `pre_delay` being present in the timer
|
||||
// queue
|
||||
if let Some(pre_delay) = pre_delay {
|
||||
Instant::wait_until(start + pre_delay).await;
|
||||
peripheral::wait_until(start + pre_delay).await;
|
||||
}
|
||||
|
||||
TestMono::queue().delay(delay).await;
|
||||
TestMonoBackend::timer_queue().delay(delay).await;
|
||||
|
||||
let elapsed = start.elapsed().as_ticks();
|
||||
println!("{total_millis} ticks delay reached after {elapsed} ticks");
|
||||
let elapsed = peripheral::now() - start;
|
||||
println!("{total} ticks delay reached after {elapsed} ticks");
|
||||
|
||||
// Expect a delay of one longer, to compensate for timer uncertainty
|
||||
if elapsed != total_millis + 1 {
|
||||
panic!(
|
||||
"{total_millis} ticks delay was not on time ({elapsed} ticks passed instead)"
|
||||
);
|
||||
if elapsed != total + 1 {
|
||||
panic!("{total} ticks delay was not on time ({elapsed} ticks passed instead)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -259,31 +175,31 @@ fn timer_queue() {
|
|||
// We only poll the waiting futures if an
|
||||
// interrupt occured or if an artificial delay
|
||||
// has passed.
|
||||
if Instant::tick() {
|
||||
if peripheral::tick() {
|
||||
poll!(d1, d2, d3);
|
||||
}
|
||||
|
||||
if Instant::now() == 0.into() {
|
||||
if peripheral::now() == 0 {
|
||||
// First, we want to be waiting for our 300 tick delay
|
||||
assert_eq!(TestMono::compare(), Some(301.into()));
|
||||
assert_eq!(TestMonoBackend::compare(), Some(301));
|
||||
}
|
||||
|
||||
if Instant::now() == 100.into() {
|
||||
if peripheral::now() == 100 {
|
||||
// After 100 ticks, we enqueue a new delay that is supposed to last
|
||||
// until the 200-tick-mark
|
||||
assert_eq!(TestMono::compare(), Some(201.into()));
|
||||
assert_eq!(TestMonoBackend::compare(), Some(201));
|
||||
}
|
||||
|
||||
if Instant::now() == 201.into() {
|
||||
if peripheral::now() == 201 {
|
||||
// After 200 ticks, we dequeue the 200-tick-mark delay and
|
||||
// requeue the 300 tick delay
|
||||
assert_eq!(TestMono::compare(), Some(301.into()));
|
||||
assert_eq!(TestMonoBackend::compare(), Some(301));
|
||||
}
|
||||
|
||||
if Instant::now() == 301.into() {
|
||||
if peripheral::now() == 301 {
|
||||
// After 300 ticks, we dequeue the 300-tick-mark delay and
|
||||
// go to the 400 tick delay that is already enqueued
|
||||
assert_eq!(TestMono::compare(), Some(401.into()));
|
||||
assert_eq!(TestMonoBackend::compare(), Some(401));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,9 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
|||
### Added
|
||||
|
||||
- Unstable support for ESP32-C6
|
||||
### Changed
|
||||
|
||||
- Remove unused dependency `rtic-monotonics`
|
||||
|
||||
## [v2.1.1] - 2024-03-13
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ cortex-m = { version = "0.7.0", optional = true }
|
|||
bare-metal = "1.0.0"
|
||||
# portable-atomic = { version = "0.3.19" }
|
||||
atomic-polyfill = "1"
|
||||
rtic-monotonics = { path = "../rtic-monotonics", version = "1.4.0", optional = true }
|
||||
rtic-macros = { path = "../rtic-macros", version = "=2.1.0" }
|
||||
rtic-core = "1"
|
||||
critical-section = "1"
|
||||
|
@ -71,7 +70,4 @@ riscv-clint-backend = [
|
|||
]
|
||||
|
||||
# needed for testing
|
||||
test-critical-section = [
|
||||
"cortex-m/critical-section-single-core",
|
||||
"rtic-monotonics/systick-100hz",
|
||||
]
|
||||
test-critical-section = ["cortex-m/critical-section-single-core"]
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
pub use rtic_core::{prelude as mutex_prelude, Exclusive, Mutex};
|
||||
pub use rtic_macros::app;
|
||||
// pub use rtic_monotonic::{self, Monotonic};
|
||||
|
||||
/// module `mutex::prelude` provides `Mutex` and multi-lock variants. Recommended over `mutex_prelude`
|
||||
pub mod mutex {
|
||||
|
|
|
@ -64,25 +64,28 @@ impl Package {
|
|||
}
|
||||
Package::RticMonotonics => {
|
||||
let features = if partial {
|
||||
&["cortex-m-systick", "rp2040", "nrf52840"][..]
|
||||
&[
|
||||
"cortex-m-systick",
|
||||
"rp2040",
|
||||
"nrf52840",
|
||||
"imxrt_gpt1,imxrt-ral/imxrt1062",
|
||||
"stm32_tim2,stm32h725ag",
|
||||
][..]
|
||||
} else {
|
||||
&[
|
||||
"cortex-m-systick,embedded-hal-async",
|
||||
"cortex-m-systick,systick-100hz,embedded-hal-async",
|
||||
"cortex-m-systick,systick-10khz,embedded-hal-async",
|
||||
"cortex-m-systick,embedded-hal-async,systick-64bit",
|
||||
"cortex-m-systick,systick-100hz,embedded-hal-async,systick-64bit",
|
||||
"cortex-m-systick,systick-10khz,embedded-hal-async,systick-64bit",
|
||||
"rp2040,embedded-hal-async",
|
||||
"nrf52810,embedded-hal-async",
|
||||
"nrf52811,embedded-hal-async",
|
||||
"nrf52832,embedded-hal-async",
|
||||
"nrf52833,embedded-hal-async",
|
||||
"nrf52840,embedded-hal-async",
|
||||
"nrf5340-app,embedded-hal-async",
|
||||
"nrf5340-net,embedded-hal-async",
|
||||
"nrf9160,embedded-hal-async",
|
||||
"imxrt_gpt1,imxrt-ral/imxrt1062,embedded-hal-async",
|
||||
"cortex-m-systick",
|
||||
"cortex-m-systick,systick-64bit",
|
||||
"rp2040",
|
||||
"nrf52810",
|
||||
"nrf52811",
|
||||
"nrf52832",
|
||||
"nrf52833",
|
||||
"nrf52840",
|
||||
"nrf5340-app",
|
||||
"nrf5340-net",
|
||||
"nrf9160",
|
||||
"imxrt_gpt1,imxrt_gpt2,imxrt-ral/imxrt1062",
|
||||
"stm32_tim2,stm32_tim3,stm32_tim4,stm32_tim5,stm32_tim15,stm32h725ag",
|
||||
][..]
|
||||
};
|
||||
|
||||
|
|
|
@ -299,7 +299,26 @@ pub fn cargo_doc<'c>(
|
|||
backend: Backends,
|
||||
arguments: &'c Option<ExtraArguments>,
|
||||
) -> Vec<FinalRunResult<'c>> {
|
||||
let features = Some(backend.to_target().and_features(backend.to_rtic_feature()));
|
||||
let extra_doc_features = [
|
||||
"rtic-monotonics/cortex-m-systick",
|
||||
"rtic-monotonics/rp2040",
|
||||
"rtic-monotonics/nrf52840",
|
||||
"imxrt-ral/imxrt1011",
|
||||
"rtic-monotonics/imxrt_gpt1",
|
||||
"rtic-monotonics/imxrt_gpt2",
|
||||
"rtic-monotonics/stm32h725ag",
|
||||
"rtic-monotonics/stm32_tim2",
|
||||
"rtic-monotonics/stm32_tim3",
|
||||
"rtic-monotonics/stm32_tim4",
|
||||
"rtic-monotonics/stm32_tim5",
|
||||
"rtic-monotonics/stm32_tim15",
|
||||
];
|
||||
|
||||
let features = Some(format!(
|
||||
"{},{}",
|
||||
backend.to_target().and_features(backend.to_rtic_feature()),
|
||||
extra_doc_features.join(",")
|
||||
));
|
||||
|
||||
let command = CargoCommand::Doc {
|
||||
cargoarg,
|
||||
|
|
Loading…
Reference in a new issue