From 20d3dc87f95f844e747a7e93036ce9ddac369081 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 1 Jan 2021 22:41:59 +0100 Subject: Rename examples -> embassy-nrf-examples --- Cargo.toml | 2 +- embassy-nrf-examples/.cargo/config | 27 ++++ embassy-nrf-examples/Cargo.toml | 32 ++++ embassy-nrf-examples/build.rs | 31 ++++ embassy-nrf-examples/memory.x | 7 + embassy-nrf-examples/src/bin/buffered_uart.rs | 84 ++++++++++ .../src/bin/executor_fairness_test.rs | 74 +++++++++ embassy-nrf-examples/src/bin/gpiote.rs | 83 ++++++++++ embassy-nrf-examples/src/bin/gpiote_port.rs | 62 ++++++++ embassy-nrf-examples/src/bin/multiprio.rs | 176 +++++++++++++++++++++ embassy-nrf-examples/src/bin/qspi.rs | 134 ++++++++++++++++ embassy-nrf-examples/src/bin/rtc_async.rs | 65 ++++++++ embassy-nrf-examples/src/bin/rtc_raw.rs | 63 ++++++++ embassy-nrf-examples/src/bin/uart.rs | 107 +++++++++++++ embassy-nrf-examples/src/example_common.rs | 18 +++ examples/.cargo/config | 27 ---- examples/Cargo.toml | 32 ---- examples/build.rs | 31 ---- examples/memory.x | 7 - examples/src/bin/buffered_uart.rs | 84 ---------- examples/src/bin/executor_fairness_test.rs | 74 --------- examples/src/bin/gpiote.rs | 83 ---------- examples/src/bin/gpiote_port.rs | 62 -------- examples/src/bin/multiprio.rs | 176 --------------------- examples/src/bin/qspi.rs | 134 ---------------- examples/src/bin/rtc_async.rs | 65 -------- examples/src/bin/rtc_raw.rs | 63 -------- examples/src/bin/uart.rs | 107 ------------- examples/src/example_common.rs | 18 --- test-build.sh | 6 +- 30 files changed, 967 insertions(+), 967 deletions(-) create mode 100644 embassy-nrf-examples/.cargo/config create mode 100644 embassy-nrf-examples/Cargo.toml create mode 100644 embassy-nrf-examples/build.rs create mode 100644 embassy-nrf-examples/memory.x create mode 100644 embassy-nrf-examples/src/bin/buffered_uart.rs create mode 100644 embassy-nrf-examples/src/bin/executor_fairness_test.rs create mode 100644 embassy-nrf-examples/src/bin/gpiote.rs create mode 100644 embassy-nrf-examples/src/bin/gpiote_port.rs create mode 100644 embassy-nrf-examples/src/bin/multiprio.rs create mode 100644 embassy-nrf-examples/src/bin/qspi.rs create mode 100644 embassy-nrf-examples/src/bin/rtc_async.rs create mode 100644 embassy-nrf-examples/src/bin/rtc_raw.rs create mode 100644 embassy-nrf-examples/src/bin/uart.rs create mode 100644 embassy-nrf-examples/src/example_common.rs delete mode 100644 examples/.cargo/config delete mode 100644 examples/Cargo.toml delete mode 100644 examples/build.rs delete mode 100644 examples/memory.x delete mode 100644 examples/src/bin/buffered_uart.rs delete mode 100644 examples/src/bin/executor_fairness_test.rs delete mode 100644 examples/src/bin/gpiote.rs delete mode 100644 examples/src/bin/gpiote_port.rs delete mode 100644 examples/src/bin/multiprio.rs delete mode 100644 examples/src/bin/qspi.rs delete mode 100644 examples/src/bin/rtc_async.rs delete mode 100644 examples/src/bin/rtc_raw.rs delete mode 100644 examples/src/bin/uart.rs delete mode 100644 examples/src/example_common.rs diff --git a/Cargo.toml b/Cargo.toml index 792804046..5ba9ba7d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,8 @@ members = [ "embassy", "embassy-nrf", + "embassy-nrf-examples", "embassy-macros", - "examples", ] exclude = [ diff --git a/embassy-nrf-examples/.cargo/config b/embassy-nrf-examples/.cargo/config new file mode 100644 index 000000000..3f319ae55 --- /dev/null +++ b/embassy-nrf-examples/.cargo/config @@ -0,0 +1,27 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-run --chip nRF52840_xxAA --defmt" + +rustflags = [ + # LLD (shipped with the Rust toolchain) is used as the default linker + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + + # if you run into problems with LLD switch to the GNU linker by commenting out + # this line + # "-C", "linker=arm-none-eabi-ld", + + # if you need to link to pre-compiled C libraries provided by a C toolchain + # use GCC as the linker by commenting out both lines above and then + # uncommenting the three lines below + # "-C", "linker=arm-none-eabi-gcc", + # "-C", "link-arg=-Wl,-Tlink.x", + # "-C", "link-arg=-nostartfiles", +] + +[build] +# Pick ONE of these compilation targets +# 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) diff --git a/embassy-nrf-examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml new file mode 100644 index 000000000..0c812db1d --- /dev/null +++ b/embassy-nrf-examples/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-nrf-examples" +version = "0.1.0" + +[features] +default = [ + "defmt-default", +] +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] + + +[dependencies] +embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } +embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] } + +defmt = "0.1.3" +defmt-rtt = "0.1.0" + +cortex-m = { version = "0.6.3" } +cortex-m-rt = "0.6.13" +embedded-hal = { version = "0.2.4" } +panic-probe = "0.1.0" +nrf52840-hal = { version = "0.12.0" } +futures = { version = "0.3.8", default-features = false, features = ["async-await"] } +cortex-m-rtic = { git = "https://github.com/rtic-rs/cortex-m-rtic", branch = "master"} diff --git a/embassy-nrf-examples/build.rs b/embassy-nrf-examples/build.rs new file mode 100644 index 000000000..d534cc3df --- /dev/null +++ b/embassy-nrf-examples/build.rs @@ -0,0 +1,31 @@ +//! This build script copies the `memory.x` file from the crate root into +//! a directory where the linker can always find it at build time. +//! For many projects this is optional, as the linker always searches the +//! project root directory -- wherever `Cargo.toml` is. However, if you +//! are using a workspace or have a more complicated build setup, this +//! build script becomes required. Additionally, by requesting that +//! Cargo re-run the build script whenever `memory.x` is changed, +//! updating `memory.x` ensures a rebuild of the application with the +//! new memory settings. + +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; + +fn main() { + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/embassy-nrf-examples/memory.x b/embassy-nrf-examples/memory.x new file mode 100644 index 000000000..9b04edec0 --- /dev/null +++ b/embassy-nrf-examples/memory.x @@ -0,0 +1,7 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */ + FLASH : ORIGIN = 0x00000000, LENGTH = 1024K + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs new file mode 100644 index 000000000..6e15fbcfa --- /dev/null +++ b/embassy-nrf-examples/src/bin/buffered_uart.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use cortex_m_rt::entry; +use defmt::panic; +use futures::pin_mut; +use nrf52840_hal::gpio; + +use embassy::executor::{task, Executor}; +use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; +use embassy::util::Forever; +use embassy_nrf::buffered_uarte; +use embassy_nrf::interrupt; + +#[task] +async fn run() { + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + let port0 = gpio::p0::Parts::new(p.P0); + + let pins = buffered_uarte::Pins { + rxd: port0.p0_08.into_floating_input().degrade(), + txd: port0 + .p0_06 + .into_push_pull_output(gpio::Level::Low) + .degrade(), + cts: None, + rts: None, + }; + + let irq = interrupt::take!(UARTE0_UART0); + let u = buffered_uarte::BufferedUarte::new( + p.UARTE0, + irq, + pins, + buffered_uarte::Parity::EXCLUDED, + buffered_uarte::Baudrate::BAUD115200, + ); + pin_mut!(u); + + info!("uarte initialized!"); + + unwrap!(u.write_all(b"Hello!\r\n").await); + info!("wrote hello in uart!"); + + // Simple demo, reading 8-char chunks and echoing them back reversed. + loop { + info!("reading..."); + let mut buf = [0u8; 8]; + unwrap!(u.read_exact(&mut buf).await); + info!("read done, got {:[u8]}", buf); + + // Reverse buf + for i in 0..4 { + let tmp = buf[i]; + buf[i] = buf[7 - i]; + buf[7 - i] = tmp; + } + + info!("writing..."); + unwrap!(u.write_all(&buf).await); + info!("write done"); + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); + unwrap!(executor.spawn(run())); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/bin/executor_fairness_test.rs b/embassy-nrf-examples/src/bin/executor_fairness_test.rs new file mode 100644 index 000000000..9b2c1bd26 --- /dev/null +++ b/embassy-nrf-examples/src/bin/executor_fairness_test.rs @@ -0,0 +1,74 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::task::Poll; +use cortex_m_rt::entry; +use defmt::panic; +use embassy::executor::{task, Executor}; +use embassy::time::{Duration, Instant, Timer}; +use embassy::util::Forever; +use embassy_nrf::pac; +use embassy_nrf::{interrupt, rtc}; +use nrf52840_hal::clocks; + +#[task] +async fn run1() { + loop { + info!("DING DONG"); + Timer::after(Duration::from_ticks(16000)).await; + } +} + +#[task] +async fn run2() { + loop { + Timer::at(Instant::from_ticks(0)).await; + } +} + +#[task] +async fn run3() { + futures::future::poll_fn(|cx| { + cx.waker().wake_by_ref(); + Poll::<()>::Pending + }) + .await; +} + +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + clocks::Clocks::new(p.CLOCK) + .enable_ext_hfosc() + .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) + .start_lfclk(); + + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); + rtc.start(); + + unsafe { embassy::time::set_clock(rtc) }; + + let alarm = ALARM.put(rtc.alarm0()); + let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev)); + + unwrap!(executor.spawn(run1())); + unwrap!(executor.spawn(run2())); + unwrap!(executor.spawn(run3())); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/bin/gpiote.rs b/embassy-nrf-examples/src/bin/gpiote.rs new file mode 100644 index 000000000..afa1b85d5 --- /dev/null +++ b/embassy-nrf-examples/src/bin/gpiote.rs @@ -0,0 +1,83 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use cortex_m_rt::entry; +use defmt::panic; +use nrf52840_hal::gpio; + +use embassy::executor::{task, Executor}; +use embassy::util::Forever; +use embassy_nrf::gpiote; +use embassy_nrf::interrupt; + +#[task] +async fn run() { + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let port0 = gpio::p0::Parts::new(p.P0); + + let g = gpiote::Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); + + info!("Starting!"); + + let pin1 = port0.p0_11.into_pullup_input().degrade(); + let button1 = async { + let ch = unwrap!(g.new_input_channel(pin1, gpiote::InputChannelPolarity::HiToLo)); + + loop { + ch.wait().await; + info!("Button 1 pressed") + } + }; + + let pin2 = port0.p0_12.into_pullup_input().degrade(); + let button2 = async { + let ch = unwrap!(g.new_input_channel(pin2, gpiote::InputChannelPolarity::LoToHi)); + + loop { + ch.wait().await; + info!("Button 2 released") + } + }; + + let pin3 = port0.p0_24.into_pullup_input().degrade(); + let button3 = async { + let ch = unwrap!(g.new_input_channel(pin3, gpiote::InputChannelPolarity::Toggle)); + + loop { + ch.wait().await; + info!("Button 3 toggled") + } + }; + + let pin4 = port0.p0_25.into_pullup_input().degrade(); + let button4 = async { + let ch = unwrap!(g.new_input_channel(pin4, gpiote::InputChannelPolarity::Toggle)); + + loop { + ch.wait().await; + info!("Button 4 toggled") + } + }; + + futures::join!(button1, button2, button3, button4); +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); + unwrap!(executor.spawn(run())); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs new file mode 100644 index 000000000..f5aa81322 --- /dev/null +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -0,0 +1,62 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::mem; +use cortex_m_rt::entry; +use defmt::panic; +use nrf52840_hal::gpio; + +use embassy::executor::{task, Executor}; +use embassy::util::Forever; +use embassy_nrf::gpiote::{Gpiote, PortInputPolarity}; +use embassy_nrf::interrupt; + +async fn button(g: &Gpiote, n: usize, pin: gpio::Pin>) { + loop { + g.wait_port_input(&pin, PortInputPolarity::Low).await; + info!("Button {:?} pressed!", n); + g.wait_port_input(&pin, PortInputPolarity::High).await; + info!("Button {:?} released!", n); + } +} + +#[task] +async fn run() { + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + let port0 = gpio::p0::Parts::new(p.P0); + + let g = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); + info!( + "sizeof Signal<()> = {:usize}", + mem::size_of::>() + ); + info!("sizeof gpiote = {:usize}", mem::size_of::()); + + info!("Starting!"); + + let button1 = button(&g, 1, port0.p0_11.into_pullup_input().degrade()); + let button2 = button(&g, 2, port0.p0_12.into_pullup_input().degrade()); + let button3 = button(&g, 3, port0.p0_24.into_pullup_input().degrade()); + let button4 = button(&g, 4, port0.p0_25.into_pullup_input().degrade()); + futures::join!(button1, button2, button3, button4); +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); + unwrap!(executor.spawn(run())); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/bin/multiprio.rs b/embassy-nrf-examples/src/bin/multiprio.rs new file mode 100644 index 000000000..c821e3dba --- /dev/null +++ b/embassy-nrf-examples/src/bin/multiprio.rs @@ -0,0 +1,176 @@ +//! This example showcases how to create multiple Executor instances to run tasks at +//! different priority levels. +//! +//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling +//! there's work in the queue, and `wfe` for waiting for work. +//! +//! Medium and high priority executors run in two interrupts with different priorities. +//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since +//! when there's work the interrupt will trigger and run the executor. +//! +//! Sample output below. Note that high priority ticks can interrupt everything else, and +//! medium priority computations can interrupt low priority computations, making them to appear +//! to take significantly longer time. +//! +//! ```not_rust +//! [med] Starting long computation +//! [med] done in 992 ms +//! [high] tick! +//! [low] Starting long computation +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! [low] done in 3972 ms +//! [med] Starting long computation +//! [high] tick! +//! [high] tick! +//! [med] done in 993 ms +//! ``` +//! +//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. +//! You will get an output like the following. Note that no computation is ever interrupted. +//! +//! ```not_rust +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [low] Starting long computation +//! [low] done in 992 ms +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! [low] Starting long computation +//! [low] done in 992 ms +//! [high] tick! +//! [med] Starting long computation +//! [med] done in 496 ms +//! [high] tick! +//! ``` +//! + +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use cortex_m::peripheral::NVIC; +use cortex_m_rt::entry; +use defmt::panic; +use nrf52840_hal::clocks; + +use embassy::executor::{task, Executor}; +use embassy::time::{Duration, Instant, Timer}; +use embassy::util::Forever; +use embassy_nrf::{interrupt, pac, rtc}; + +#[task] +async fn run_high() { + loop { + info!(" [high] tick!"); + Timer::after(Duration::from_ticks(27374)).await; + } +} + +#[task] +async fn run_med() { + loop { + let start = Instant::now(); + info!(" [med] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(32_000_000); // ~1 second + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!(" [med] done in {:u64} ms", ms); + + Timer::after(Duration::from_ticks(23421)).await; + } +} + +#[task] +async fn run_low() { + loop { + let start = Instant::now(); + info!("[low] Starting long computation"); + + // Spin-wait to simulate a long CPU computation + cortex_m::asm::delay(64_000_000); // ~2 seconds + + let end = Instant::now(); + let ms = end.duration_since(start).as_ticks() / 33; + info!("[low] done in {:u64} ms", ms); + + Timer::after(Duration::from_ticks(32983)).await; + } +} + +static RTC: Forever> = Forever::new(); +static ALARM_LOW: Forever> = Forever::new(); +static EXECUTOR_LOW: Forever = Forever::new(); +static ALARM_MED: Forever> = Forever::new(); +static EXECUTOR_MED: Forever = Forever::new(); +static ALARM_HIGH: Forever> = Forever::new(); +static EXECUTOR_HIGH: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + clocks::Clocks::new(p.CLOCK) + .enable_ext_hfosc() + .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) + .start_lfclk(); + + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); + rtc.start(); + unsafe { embassy::time::set_clock(rtc) }; + + let alarm_low = ALARM_LOW.put(rtc.alarm0()); + let executor_low = EXECUTOR_LOW.put(Executor::new_with_alarm(alarm_low, cortex_m::asm::sev)); + let alarm_med = ALARM_MED.put(rtc.alarm1()); + let executor_med = EXECUTOR_MED.put(Executor::new_with_alarm(alarm_med, || { + NVIC::pend(interrupt::SWI0_EGU0) + })); + let alarm_high = ALARM_HIGH.put(rtc.alarm2()); + let executor_high = EXECUTOR_HIGH.put(Executor::new_with_alarm(alarm_high, || { + NVIC::pend(interrupt::SWI1_EGU1) + })); + + unsafe { + let mut nvic: NVIC = core::mem::transmute(()); + nvic.set_priority(interrupt::SWI0_EGU0, 7 << 5); + nvic.set_priority(interrupt::SWI1_EGU1, 6 << 5); + NVIC::unmask(interrupt::SWI0_EGU0); + NVIC::unmask(interrupt::SWI1_EGU1); + } + + unwrap!(executor_low.spawn(run_low())); + unwrap!(executor_med.spawn(run_med())); + unwrap!(executor_high.spawn(run_high())); + + loop { + executor_low.run(); + cortex_m::asm::wfe(); + } +} + +#[interrupt] +unsafe fn SWI0_EGU0() { + EXECUTOR_MED.steal().run() +} + +#[interrupt] +unsafe fn SWI1_EGU1() { + EXECUTOR_HIGH.steal().run() +} diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs new file mode 100644 index 000000000..a7d47f79c --- /dev/null +++ b/embassy-nrf-examples/src/bin/qspi.rs @@ -0,0 +1,134 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use cortex_m_rt::entry; +use defmt::{assert_eq, panic, *}; +use nrf52840_hal::gpio; + +use embassy::executor::{task, Executor}; +use embassy::flash::Flash; +use embassy::util::Forever; +use embassy_nrf::{interrupt, qspi}; + +const PAGE_SIZE: usize = 4096; + +// Workaround for alignment requirements. +// Nicer API will probably come in the future. +#[repr(C, align(4))] +struct AlignedBuf([u8; 4096]); + +#[task] +async fn run() { + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + let port0 = gpio::p0::Parts::new(p.P0); + + let pins = qspi::Pins { + csn: port0 + .p0_17 + .into_push_pull_output(gpio::Level::High) + .degrade(), + sck: port0 + .p0_19 + .into_push_pull_output(gpio::Level::High) + .degrade(), + io0: port0 + .p0_20 + .into_push_pull_output(gpio::Level::High) + .degrade(), + io1: port0 + .p0_21 + .into_push_pull_output(gpio::Level::High) + .degrade(), + io2: Some( + port0 + .p0_22 + .into_push_pull_output(gpio::Level::High) + .degrade(), + ), + io3: Some( + port0 + .p0_23 + .into_push_pull_output(gpio::Level::High) + .degrade(), + ), + }; + + let config = qspi::Config { + pins, + read_opcode: qspi::ReadOpcode::READ4IO, + write_opcode: qspi::WriteOpcode::PP4IO, + xip_offset: 0, + write_page_size: qspi::WritePageSize::_256BYTES, + deep_power_down: None, + }; + + let irq = interrupt::take!(QSPI); + let mut q = qspi::Qspi::new(p.QSPI, irq, config); + + let mut id = [1; 3]; + q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); + info!("id: {:[u8]}", id); + + // Read status register + let mut status = [0; 1]; + q.custom_instruction(0x05, &[], &mut status).await.unwrap(); + + info!("status: {:?}", status[0]); + + if status[0] & 0x40 == 0 { + status[0] |= 0x40; + + q.custom_instruction(0x01, &status, &mut []).await.unwrap(); + + info!("enabled quad in status"); + } + + let mut buf = AlignedBuf([0u8; PAGE_SIZE]); + + let pattern = |a: u32| (a ^ (a >> 8) ^ (a >> 16) ^ (a >> 24)) as u8; + + for i in 0..8 { + info!("page {:?}: erasing... ", i); + q.erase(i * PAGE_SIZE).await.unwrap(); + + for j in 0..PAGE_SIZE { + buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); + } + + info!("programming..."); + q.write(i * PAGE_SIZE, &buf.0).await.unwrap(); + } + + for i in 0..8 { + info!("page {:?}: reading... ", i); + q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); + + info!("verifying..."); + for j in 0..PAGE_SIZE { + assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32)); + } + } + + info!("done!") +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); + unwrap!(executor.spawn(run())); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/bin/rtc_async.rs b/embassy-nrf-examples/src/bin/rtc_async.rs new file mode 100644 index 000000000..dcdeb7049 --- /dev/null +++ b/embassy-nrf-examples/src/bin/rtc_async.rs @@ -0,0 +1,65 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::mem::MaybeUninit; +use cortex_m_rt::entry; +use defmt::panic; +use embassy::executor::{task, Executor}; +use embassy::time::{Clock, Duration, Timer}; +use embassy::util::Forever; +use embassy_nrf::pac; +use embassy_nrf::{interrupt, rtc}; +use nrf52840_hal::clocks; + +#[task] +async fn run1() { + loop { + info!("BIG INFREQUENT TICK"); + Timer::after(Duration::from_ticks(64000)).await; + } +} + +#[task] +async fn run2() { + loop { + info!("tick"); + Timer::after(Duration::from_ticks(13000)).await; + } +} + +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + clocks::Clocks::new(p.CLOCK) + .enable_ext_hfosc() + .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) + .start_lfclk(); + + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); + rtc.start(); + + unsafe { embassy::time::set_clock(rtc) }; + + let alarm = ALARM.put(rtc.alarm0()); + let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev)); + + unwrap!(executor.spawn(run1())); + unwrap!(executor.spawn(run2())); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/bin/rtc_raw.rs b/embassy-nrf-examples/src/bin/rtc_raw.rs new file mode 100644 index 000000000..438585460 --- /dev/null +++ b/embassy-nrf-examples/src/bin/rtc_raw.rs @@ -0,0 +1,63 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::mem::MaybeUninit; +use cortex_m_rt::entry; +use defmt::panic; +use embassy::time::{Alarm, Clock}; +use embassy_nrf::{interrupt, rtc}; +use nrf52840_hal::clocks; + +static mut RTC: MaybeUninit> = MaybeUninit::uninit(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + clocks::Clocks::new(p.CLOCK) + .enable_ext_hfosc() + .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) + .start_lfclk(); + + let irq = interrupt::take!(RTC1); + + let rtc: &'static _ = unsafe { + let ptr = RTC.as_mut_ptr(); + ptr.write(rtc::RTC::new(p.RTC1, irq)); + &*ptr + }; + + let alarm = rtc.alarm0(); + + rtc.start(); + + alarm.set_callback(|| info!("ALARM TRIGGERED")); + alarm.set(53719); + + info!("initialized!"); + + let mut val = 0; + let mut printval = 0; + loop { + let val2 = rtc.now(); + if val2 < val { + info!( + "timer ran backwards! {:u32} -> {:u32}", + val as u32, val2 as u32 + ); + } + val = val2; + + if val > printval + 32768 { + info!("tick {:u32}", val as u32); + printval = val; + } + } +} diff --git a/embassy-nrf-examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs new file mode 100644 index 000000000..107936686 --- /dev/null +++ b/embassy-nrf-examples/src/bin/uart.rs @@ -0,0 +1,107 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use cortex_m_rt::entry; +use defmt::panic; +use embassy::executor::{task, Executor}; +use embassy::time::{Duration, Timer}; +use embassy::util::Forever; +use embassy_nrf::{interrupt, pac, rtc, uarte}; +use futures::future::{select, Either}; +use nrf52840_hal::clocks; +use nrf52840_hal::gpio; + +#[task] +async fn run(mut uart: uarte::Uarte) { + info!("uarte initialized!"); + + // Message must be in SRAM + let mut buf = [0; 8]; + buf.copy_from_slice(b"Hello!\r\n"); + + uart.send(&buf).await; + info!("wrote hello in uart!"); + + info!("reading..."); + loop { + let received = match select( + uart.receive(&mut buf), + Timer::after(Duration::from_millis(10)), + ) + .await + { + Either::Left((buf, _)) => buf, + Either::Right((_, read)) => { + let (buf, n) = read.stop().await; + &buf[..n] + } + }; + + if received.len() > 0 { + info!("read done, got {:[u8]}", received); + + // Echo back received data + uart.send(received).await; + } + } +} + +static RTC: Forever> = Forever::new(); +static ALARM: Forever> = Forever::new(); +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = unwrap!(embassy_nrf::pac::Peripherals::take()); + + clocks::Clocks::new(p.CLOCK) + .enable_ext_hfosc() + .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) + .start_lfclk(); + + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); + rtc.start(); + + unsafe { embassy::time::set_clock(rtc) }; + + let alarm = ALARM.put(rtc.alarm0()); + let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev)); + + // Init UART + let port0 = gpio::p0::Parts::new(p.P0); + + let pins = uarte::Pins { + rxd: port0.p0_08.into_floating_input().degrade(), + txd: port0 + .p0_06 + .into_push_pull_output(gpio::Level::Low) + .degrade(), + cts: None, + rts: None, + }; + + // NOTE(unsafe): Safe becasue we do not use `mem::forget` anywhere. + let uart = unsafe { + uarte::Uarte::new( + p.UARTE0, + interrupt::take!(UARTE0_UART0), + pins, + uarte::Parity::EXCLUDED, + uarte::Baudrate::BAUD115200, + ) + }; + + unwrap!(executor.spawn(run(uart))); + + loop { + executor.run(); + cortex_m::asm::wfe(); + } +} diff --git a/embassy-nrf-examples/src/example_common.rs b/embassy-nrf-examples/src/example_common.rs new file mode 100644 index 000000000..60bb02082 --- /dev/null +++ b/embassy-nrf-examples/src/example_common.rs @@ -0,0 +1,18 @@ +#![macro_use] + +use defmt_rtt as _; // global logger +use nrf52840_hal as _; +use panic_probe as _; + +pub use defmt::*; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +#[defmt::timestamp] +fn timestamp() -> u64 { + static COUNT: AtomicUsize = AtomicUsize::new(0); + // NOTE(no-CAS) `timestamps` runs with interrupts disabled + let n = COUNT.load(Ordering::Relaxed); + COUNT.store(n + 1, Ordering::Relaxed); + n as u64 +} diff --git a/examples/.cargo/config b/examples/.cargo/config deleted file mode 100644 index 3f319ae55..000000000 --- a/examples/.cargo/config +++ /dev/null @@ -1,27 +0,0 @@ -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-run --chip nRF52840_xxAA --defmt" - -rustflags = [ - # LLD (shipped with the Rust toolchain) is used as the default linker - "-C", "link-arg=--nmagic", - "-C", "link-arg=-Tlink.x", - "-C", "link-arg=-Tdefmt.x", - - # if you run into problems with LLD switch to the GNU linker by commenting out - # this line - # "-C", "linker=arm-none-eabi-ld", - - # if you need to link to pre-compiled C libraries provided by a C toolchain - # use GCC as the linker by commenting out both lines above and then - # uncommenting the three lines below - # "-C", "linker=arm-none-eabi-gcc", - # "-C", "link-arg=-Wl,-Tlink.x", - # "-C", "link-arg=-nostartfiles", -] - -[build] -# Pick ONE of these compilation targets -# 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) diff --git a/examples/Cargo.toml b/examples/Cargo.toml deleted file mode 100644 index c845c1bfb..000000000 --- a/examples/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -authors = ["Dario Nieuwenhuis "] -edition = "2018" -name = "embassy-examples" -version = "0.1.0" - -[features] -default = [ - "defmt-default", -] -defmt-default = [] -defmt-trace = [] -defmt-debug = [] -defmt-info = [] -defmt-warn = [] -defmt-error = [] - - -[dependencies] -embassy = { version = "0.1.0", path = "../embassy", features = ["defmt", "defmt-trace"] } -embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "52840"] } - -defmt = "0.1.3" -defmt-rtt = "0.1.0" - -cortex-m = { version = "0.6.3" } -cortex-m-rt = "0.6.13" -embedded-hal = { version = "0.2.4" } -panic-probe = "0.1.0" -nrf52840-hal = { version = "0.12.0" } -futures = { version = "0.3.8", default-features = false, features = ["async-await"] } -cortex-m-rtic = { git = "https://github.com/rtic-rs/cortex-m-rtic", branch = "master"} diff --git a/examples/build.rs b/examples/build.rs deleted file mode 100644 index d534cc3df..000000000 --- a/examples/build.rs +++ /dev/null @@ -1,31 +0,0 @@ -//! This build script copies the `memory.x` file from the crate root into -//! a directory where the linker can always find it at build time. -//! For many projects this is optional, as the linker always searches the -//! project root directory -- wherever `Cargo.toml` is. However, if you -//! are using a workspace or have a more complicated build setup, this -//! build script becomes required. Additionally, by requesting that -//! Cargo re-run the build script whenever `memory.x` is changed, -//! updating `memory.x` ensures a rebuild of the application with the -//! new memory settings. - -use std::env; -use std::fs::File; -use std::io::Write; -use std::path::PathBuf; - -fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); - - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); -} diff --git a/examples/memory.x b/examples/memory.x deleted file mode 100644 index 9b04edec0..000000000 --- a/examples/memory.x +++ /dev/null @@ -1,7 +0,0 @@ -MEMORY -{ - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */ - FLASH : ORIGIN = 0x00000000, LENGTH = 1024K - RAM : ORIGIN = 0x20000000, LENGTH = 256K -} diff --git a/examples/src/bin/buffered_uart.rs b/examples/src/bin/buffered_uart.rs deleted file mode 100644 index 6e15fbcfa..000000000 --- a/examples/src/bin/buffered_uart.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use cortex_m_rt::entry; -use defmt::panic; -use futures::pin_mut; -use nrf52840_hal::gpio; - -use embassy::executor::{task, Executor}; -use embassy::io::{AsyncBufRead, AsyncBufReadExt, AsyncWrite, AsyncWriteExt}; -use embassy::util::Forever; -use embassy_nrf::buffered_uarte; -use embassy_nrf::interrupt; - -#[task] -async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - let port0 = gpio::p0::Parts::new(p.P0); - - let pins = buffered_uarte::Pins { - rxd: port0.p0_08.into_floating_input().degrade(), - txd: port0 - .p0_06 - .into_push_pull_output(gpio::Level::Low) - .degrade(), - cts: None, - rts: None, - }; - - let irq = interrupt::take!(UARTE0_UART0); - let u = buffered_uarte::BufferedUarte::new( - p.UARTE0, - irq, - pins, - buffered_uarte::Parity::EXCLUDED, - buffered_uarte::Baudrate::BAUD115200, - ); - pin_mut!(u); - - info!("uarte initialized!"); - - unwrap!(u.write_all(b"Hello!\r\n").await); - info!("wrote hello in uart!"); - - // Simple demo, reading 8-char chunks and echoing them back reversed. - loop { - info!("reading..."); - let mut buf = [0u8; 8]; - unwrap!(u.read_exact(&mut buf).await); - info!("read done, got {:[u8]}", buf); - - // Reverse buf - for i in 0..4 { - let tmp = buf[i]; - buf[i] = buf[7 - i]; - buf[7 - i] = tmp; - } - - info!("writing..."); - unwrap!(u.write_all(&buf).await); - info!("write done"); - } -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); - unwrap!(executor.spawn(run())); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/executor_fairness_test.rs b/examples/src/bin/executor_fairness_test.rs deleted file mode 100644 index 9b2c1bd26..000000000 --- a/examples/src/bin/executor_fairness_test.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::task::Poll; -use cortex_m_rt::entry; -use defmt::panic; -use embassy::executor::{task, Executor}; -use embassy::time::{Duration, Instant, Timer}; -use embassy::util::Forever; -use embassy_nrf::pac; -use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; - -#[task] -async fn run1() { - loop { - info!("DING DONG"); - Timer::after(Duration::from_ticks(16000)).await; - } -} - -#[task] -async fn run2() { - loop { - Timer::at(Instant::from_ticks(0)).await; - } -} - -#[task] -async fn run3() { - futures::future::poll_fn(|cx| { - cx.waker().wake_by_ref(); - Poll::<()>::Pending - }) - .await; -} - -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - - let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); - rtc.start(); - - unsafe { embassy::time::set_clock(rtc) }; - - let alarm = ALARM.put(rtc.alarm0()); - let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev)); - - unwrap!(executor.spawn(run1())); - unwrap!(executor.spawn(run2())); - unwrap!(executor.spawn(run3())); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/gpiote.rs b/examples/src/bin/gpiote.rs deleted file mode 100644 index afa1b85d5..000000000 --- a/examples/src/bin/gpiote.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use cortex_m_rt::entry; -use defmt::panic; -use nrf52840_hal::gpio; - -use embassy::executor::{task, Executor}; -use embassy::util::Forever; -use embassy_nrf::gpiote; -use embassy_nrf::interrupt; - -#[task] -async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - let port0 = gpio::p0::Parts::new(p.P0); - - let g = gpiote::Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); - - info!("Starting!"); - - let pin1 = port0.p0_11.into_pullup_input().degrade(); - let button1 = async { - let ch = unwrap!(g.new_input_channel(pin1, gpiote::InputChannelPolarity::HiToLo)); - - loop { - ch.wait().await; - info!("Button 1 pressed") - } - }; - - let pin2 = port0.p0_12.into_pullup_input().degrade(); - let button2 = async { - let ch = unwrap!(g.new_input_channel(pin2, gpiote::InputChannelPolarity::LoToHi)); - - loop { - ch.wait().await; - info!("Button 2 released") - } - }; - - let pin3 = port0.p0_24.into_pullup_input().degrade(); - let button3 = async { - let ch = unwrap!(g.new_input_channel(pin3, gpiote::InputChannelPolarity::Toggle)); - - loop { - ch.wait().await; - info!("Button 3 toggled") - } - }; - - let pin4 = port0.p0_25.into_pullup_input().degrade(); - let button4 = async { - let ch = unwrap!(g.new_input_channel(pin4, gpiote::InputChannelPolarity::Toggle)); - - loop { - ch.wait().await; - info!("Button 4 toggled") - } - }; - - futures::join!(button1, button2, button3, button4); -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); - unwrap!(executor.spawn(run())); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/gpiote_port.rs b/examples/src/bin/gpiote_port.rs deleted file mode 100644 index f5aa81322..000000000 --- a/examples/src/bin/gpiote_port.rs +++ /dev/null @@ -1,62 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::mem; -use cortex_m_rt::entry; -use defmt::panic; -use nrf52840_hal::gpio; - -use embassy::executor::{task, Executor}; -use embassy::util::Forever; -use embassy_nrf::gpiote::{Gpiote, PortInputPolarity}; -use embassy_nrf::interrupt; - -async fn button(g: &Gpiote, n: usize, pin: gpio::Pin>) { - loop { - g.wait_port_input(&pin, PortInputPolarity::Low).await; - info!("Button {:?} pressed!", n); - g.wait_port_input(&pin, PortInputPolarity::High).await; - info!("Button {:?} released!", n); - } -} - -#[task] -async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - let port0 = gpio::p0::Parts::new(p.P0); - - let g = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); - info!( - "sizeof Signal<()> = {:usize}", - mem::size_of::>() - ); - info!("sizeof gpiote = {:usize}", mem::size_of::()); - - info!("Starting!"); - - let button1 = button(&g, 1, port0.p0_11.into_pullup_input().degrade()); - let button2 = button(&g, 2, port0.p0_12.into_pullup_input().degrade()); - let button3 = button(&g, 3, port0.p0_24.into_pullup_input().degrade()); - let button4 = button(&g, 4, port0.p0_25.into_pullup_input().degrade()); - futures::join!(button1, button2, button3, button4); -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); - unwrap!(executor.spawn(run())); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/multiprio.rs b/examples/src/bin/multiprio.rs deleted file mode 100644 index c821e3dba..000000000 --- a/examples/src/bin/multiprio.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! This example showcases how to create multiple Executor instances to run tasks at -//! different priority levels. -//! -//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling -//! there's work in the queue, and `wfe` for waiting for work. -//! -//! Medium and high priority executors run in two interrupts with different priorities. -//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since -//! when there's work the interrupt will trigger and run the executor. -//! -//! Sample output below. Note that high priority ticks can interrupt everything else, and -//! medium priority computations can interrupt low priority computations, making them to appear -//! to take significantly longer time. -//! -//! ```not_rust -//! [med] Starting long computation -//! [med] done in 992 ms -//! [high] tick! -//! [low] Starting long computation -//! [med] Starting long computation -//! [high] tick! -//! [high] tick! -//! [med] done in 993 ms -//! [med] Starting long computation -//! [high] tick! -//! [high] tick! -//! [med] done in 993 ms -//! [low] done in 3972 ms -//! [med] Starting long computation -//! [high] tick! -//! [high] tick! -//! [med] done in 993 ms -//! ``` -//! -//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor. -//! You will get an output like the following. Note that no computation is ever interrupted. -//! -//! ```not_rust -//! [high] tick! -//! [med] Starting long computation -//! [med] done in 496 ms -//! [low] Starting long computation -//! [low] done in 992 ms -//! [med] Starting long computation -//! [med] done in 496 ms -//! [high] tick! -//! [low] Starting long computation -//! [low] done in 992 ms -//! [high] tick! -//! [med] Starting long computation -//! [med] done in 496 ms -//! [high] tick! -//! ``` -//! - -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use cortex_m::peripheral::NVIC; -use cortex_m_rt::entry; -use defmt::panic; -use nrf52840_hal::clocks; - -use embassy::executor::{task, Executor}; -use embassy::time::{Duration, Instant, Timer}; -use embassy::util::Forever; -use embassy_nrf::{interrupt, pac, rtc}; - -#[task] -async fn run_high() { - loop { - info!(" [high] tick!"); - Timer::after(Duration::from_ticks(27374)).await; - } -} - -#[task] -async fn run_med() { - loop { - let start = Instant::now(); - info!(" [med] Starting long computation"); - - // Spin-wait to simulate a long CPU computation - cortex_m::asm::delay(32_000_000); // ~1 second - - let end = Instant::now(); - let ms = end.duration_since(start).as_ticks() / 33; - info!(" [med] done in {:u64} ms", ms); - - Timer::after(Duration::from_ticks(23421)).await; - } -} - -#[task] -async fn run_low() { - loop { - let start = Instant::now(); - info!("[low] Starting long computation"); - - // Spin-wait to simulate a long CPU computation - cortex_m::asm::delay(64_000_000); // ~2 seconds - - let end = Instant::now(); - let ms = end.duration_since(start).as_ticks() / 33; - info!("[low] done in {:u64} ms", ms); - - Timer::after(Duration::from_ticks(32983)).await; - } -} - -static RTC: Forever> = Forever::new(); -static ALARM_LOW: Forever> = Forever::new(); -static EXECUTOR_LOW: Forever = Forever::new(); -static ALARM_MED: Forever> = Forever::new(); -static EXECUTOR_MED: Forever = Forever::new(); -static ALARM_HIGH: Forever> = Forever::new(); -static EXECUTOR_HIGH: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - - let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); - rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; - - let alarm_low = ALARM_LOW.put(rtc.alarm0()); - let executor_low = EXECUTOR_LOW.put(Executor::new_with_alarm(alarm_low, cortex_m::asm::sev)); - let alarm_med = ALARM_MED.put(rtc.alarm1()); - let executor_med = EXECUTOR_MED.put(Executor::new_with_alarm(alarm_med, || { - NVIC::pend(interrupt::SWI0_EGU0) - })); - let alarm_high = ALARM_HIGH.put(rtc.alarm2()); - let executor_high = EXECUTOR_HIGH.put(Executor::new_with_alarm(alarm_high, || { - NVIC::pend(interrupt::SWI1_EGU1) - })); - - unsafe { - let mut nvic: NVIC = core::mem::transmute(()); - nvic.set_priority(interrupt::SWI0_EGU0, 7 << 5); - nvic.set_priority(interrupt::SWI1_EGU1, 6 << 5); - NVIC::unmask(interrupt::SWI0_EGU0); - NVIC::unmask(interrupt::SWI1_EGU1); - } - - unwrap!(executor_low.spawn(run_low())); - unwrap!(executor_med.spawn(run_med())); - unwrap!(executor_high.spawn(run_high())); - - loop { - executor_low.run(); - cortex_m::asm::wfe(); - } -} - -#[interrupt] -unsafe fn SWI0_EGU0() { - EXECUTOR_MED.steal().run() -} - -#[interrupt] -unsafe fn SWI1_EGU1() { - EXECUTOR_HIGH.steal().run() -} diff --git a/examples/src/bin/qspi.rs b/examples/src/bin/qspi.rs deleted file mode 100644 index a7d47f79c..000000000 --- a/examples/src/bin/qspi.rs +++ /dev/null @@ -1,134 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use cortex_m_rt::entry; -use defmt::{assert_eq, panic, *}; -use nrf52840_hal::gpio; - -use embassy::executor::{task, Executor}; -use embassy::flash::Flash; -use embassy::util::Forever; -use embassy_nrf::{interrupt, qspi}; - -const PAGE_SIZE: usize = 4096; - -// Workaround for alignment requirements. -// Nicer API will probably come in the future. -#[repr(C, align(4))] -struct AlignedBuf([u8; 4096]); - -#[task] -async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - let port0 = gpio::p0::Parts::new(p.P0); - - let pins = qspi::Pins { - csn: port0 - .p0_17 - .into_push_pull_output(gpio::Level::High) - .degrade(), - sck: port0 - .p0_19 - .into_push_pull_output(gpio::Level::High) - .degrade(), - io0: port0 - .p0_20 - .into_push_pull_output(gpio::Level::High) - .degrade(), - io1: port0 - .p0_21 - .into_push_pull_output(gpio::Level::High) - .degrade(), - io2: Some( - port0 - .p0_22 - .into_push_pull_output(gpio::Level::High) - .degrade(), - ), - io3: Some( - port0 - .p0_23 - .into_push_pull_output(gpio::Level::High) - .degrade(), - ), - }; - - let config = qspi::Config { - pins, - read_opcode: qspi::ReadOpcode::READ4IO, - write_opcode: qspi::WriteOpcode::PP4IO, - xip_offset: 0, - write_page_size: qspi::WritePageSize::_256BYTES, - deep_power_down: None, - }; - - let irq = interrupt::take!(QSPI); - let mut q = qspi::Qspi::new(p.QSPI, irq, config); - - let mut id = [1; 3]; - q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); - info!("id: {:[u8]}", id); - - // Read status register - let mut status = [0; 1]; - q.custom_instruction(0x05, &[], &mut status).await.unwrap(); - - info!("status: {:?}", status[0]); - - if status[0] & 0x40 == 0 { - status[0] |= 0x40; - - q.custom_instruction(0x01, &status, &mut []).await.unwrap(); - - info!("enabled quad in status"); - } - - let mut buf = AlignedBuf([0u8; PAGE_SIZE]); - - let pattern = |a: u32| (a ^ (a >> 8) ^ (a >> 16) ^ (a >> 24)) as u8; - - for i in 0..8 { - info!("page {:?}: erasing... ", i); - q.erase(i * PAGE_SIZE).await.unwrap(); - - for j in 0..PAGE_SIZE { - buf.0[j] = pattern((j + i * PAGE_SIZE) as u32); - } - - info!("programming..."); - q.write(i * PAGE_SIZE, &buf.0).await.unwrap(); - } - - for i in 0..8 { - info!("page {:?}: reading... ", i); - q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap(); - - info!("verifying..."); - for j in 0..PAGE_SIZE { - assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32)); - } - } - - info!("done!") -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let executor = EXECUTOR.put(Executor::new(cortex_m::asm::sev)); - unwrap!(executor.spawn(run())); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/rtc_async.rs b/examples/src/bin/rtc_async.rs deleted file mode 100644 index dcdeb7049..000000000 --- a/examples/src/bin/rtc_async.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::mem::MaybeUninit; -use cortex_m_rt::entry; -use defmt::panic; -use embassy::executor::{task, Executor}; -use embassy::time::{Clock, Duration, Timer}; -use embassy::util::Forever; -use embassy_nrf::pac; -use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; - -#[task] -async fn run1() { - loop { - info!("BIG INFREQUENT TICK"); - Timer::after(Duration::from_ticks(64000)).await; - } -} - -#[task] -async fn run2() { - loop { - info!("tick"); - Timer::after(Duration::from_ticks(13000)).await; - } -} - -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - - let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); - rtc.start(); - - unsafe { embassy::time::set_clock(rtc) }; - - let alarm = ALARM.put(rtc.alarm0()); - let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev)); - - unwrap!(executor.spawn(run1())); - unwrap!(executor.spawn(run2())); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/bin/rtc_raw.rs b/examples/src/bin/rtc_raw.rs deleted file mode 100644 index 438585460..000000000 --- a/examples/src/bin/rtc_raw.rs +++ /dev/null @@ -1,63 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::mem::MaybeUninit; -use cortex_m_rt::entry; -use defmt::panic; -use embassy::time::{Alarm, Clock}; -use embassy_nrf::{interrupt, rtc}; -use nrf52840_hal::clocks; - -static mut RTC: MaybeUninit> = MaybeUninit::uninit(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - - let irq = interrupt::take!(RTC1); - - let rtc: &'static _ = unsafe { - let ptr = RTC.as_mut_ptr(); - ptr.write(rtc::RTC::new(p.RTC1, irq)); - &*ptr - }; - - let alarm = rtc.alarm0(); - - rtc.start(); - - alarm.set_callback(|| info!("ALARM TRIGGERED")); - alarm.set(53719); - - info!("initialized!"); - - let mut val = 0; - let mut printval = 0; - loop { - let val2 = rtc.now(); - if val2 < val { - info!( - "timer ran backwards! {:u32} -> {:u32}", - val as u32, val2 as u32 - ); - } - val = val2; - - if val > printval + 32768 { - info!("tick {:u32}", val as u32); - printval = val; - } - } -} diff --git a/examples/src/bin/uart.rs b/examples/src/bin/uart.rs deleted file mode 100644 index 107936686..000000000 --- a/examples/src/bin/uart.rs +++ /dev/null @@ -1,107 +0,0 @@ -#![no_std] -#![no_main] -#![feature(type_alias_impl_trait)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use cortex_m_rt::entry; -use defmt::panic; -use embassy::executor::{task, Executor}; -use embassy::time::{Duration, Timer}; -use embassy::util::Forever; -use embassy_nrf::{interrupt, pac, rtc, uarte}; -use futures::future::{select, Either}; -use nrf52840_hal::clocks; -use nrf52840_hal::gpio; - -#[task] -async fn run(mut uart: uarte::Uarte) { - info!("uarte initialized!"); - - // Message must be in SRAM - let mut buf = [0; 8]; - buf.copy_from_slice(b"Hello!\r\n"); - - uart.send(&buf).await; - info!("wrote hello in uart!"); - - info!("reading..."); - loop { - let received = match select( - uart.receive(&mut buf), - Timer::after(Duration::from_millis(10)), - ) - .await - { - Either::Left((buf, _)) => buf, - Either::Right((_, read)) => { - let (buf, n) = read.stop().await; - &buf[..n] - } - }; - - if received.len() > 0 { - info!("read done, got {:[u8]}", received); - - // Echo back received data - uart.send(received).await; - } - } -} - -static RTC: Forever> = Forever::new(); -static ALARM: Forever> = Forever::new(); -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - - clocks::Clocks::new(p.CLOCK) - .enable_ext_hfosc() - .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass) - .start_lfclk(); - - let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); - rtc.start(); - - unsafe { embassy::time::set_clock(rtc) }; - - let alarm = ALARM.put(rtc.alarm0()); - let executor = EXECUTOR.put(Executor::new_with_alarm(alarm, cortex_m::asm::sev)); - - // Init UART - let port0 = gpio::p0::Parts::new(p.P0); - - let pins = uarte::Pins { - rxd: port0.p0_08.into_floating_input().degrade(), - txd: port0 - .p0_06 - .into_push_pull_output(gpio::Level::Low) - .degrade(), - cts: None, - rts: None, - }; - - // NOTE(unsafe): Safe becasue we do not use `mem::forget` anywhere. - let uart = unsafe { - uarte::Uarte::new( - p.UARTE0, - interrupt::take!(UARTE0_UART0), - pins, - uarte::Parity::EXCLUDED, - uarte::Baudrate::BAUD115200, - ) - }; - - unwrap!(executor.spawn(run(uart))); - - loop { - executor.run(); - cortex_m::asm::wfe(); - } -} diff --git a/examples/src/example_common.rs b/examples/src/example_common.rs deleted file mode 100644 index 60bb02082..000000000 --- a/examples/src/example_common.rs +++ /dev/null @@ -1,18 +0,0 @@ -#![macro_use] - -use defmt_rtt as _; // global logger -use nrf52840_hal as _; -use panic_probe as _; - -pub use defmt::*; - -use core::sync::atomic::{AtomicUsize, Ordering}; - -#[defmt::timestamp] -fn timestamp() -> u64 { - static COUNT: AtomicUsize = AtomicUsize::new(0); - // NOTE(no-CAS) `timestamps` runs with interrupts disabled - let n = COUNT.load(Ordering::Relaxed); - COUNT.store(n + 1, Ordering::Relaxed); - n as u64 -} diff --git a/test-build.sh b/test-build.sh index 52bf7bb7b..f67cc5b2b 100755 --- a/test-build.sh +++ b/test-build.sh @@ -2,9 +2,6 @@ set -euxo pipefail -# examples -(cd examples; cargo build --target thumbv7em-none-eabi --bins) - # embassy std (cd embassy; cargo build --features log,std) @@ -14,6 +11,9 @@ set -euxo pipefail (cd embassy; cargo build --target thumbv7em-none-eabi --features defmt) # embassy-nrf + +(cd embassy-nrf-examples; cargo build --target thumbv7em-none-eabi --bins) + (cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52810) #(cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52811) # nrf52811-hal doesn't exist yet (cd embassy-nrf; cargo build --target thumbv7em-none-eabi --features 52832) -- cgit