From dff03ecfc74d6af716637888338ebfa99ab7a027 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 2 Jun 2021 01:30:07 +0200 Subject: Move examples to a subdirectory --- .github/workflows/rust.yml | 16 +- .vscode/settings.json | 4 +- Cargo.example.toml | 9 +- embassy-nrf-examples/.cargo/config.toml | 21 -- embassy-nrf-examples/Cargo.toml | 31 --- embassy-nrf-examples/build.rs | 31 --- embassy-nrf-examples/memory.x | 7 - embassy-nrf-examples/src/bin/blinky.rs | 28 --- embassy-nrf-examples/src/bin/buffered_uart.rs | 68 ------- .../src/bin/executor_fairness_test.rs | 47 ----- embassy-nrf-examples/src/bin/gpiote_channel.rs | 72 ------- embassy-nrf-examples/src/bin/gpiote_port.rs | 43 ---- embassy-nrf-examples/src/bin/multiprio.rs | 162 --------------- embassy-nrf-examples/src/bin/ppi.rs | 87 -------- embassy-nrf-examples/src/bin/pwm.rs | 104 ---------- embassy-nrf-examples/src/bin/qspi.rs | 84 -------- embassy-nrf-examples/src/bin/qspi_lowpower.rs | 85 -------- embassy-nrf-examples/src/bin/raw_spawn.rs | 65 ------ embassy-nrf-examples/src/bin/spim.rs | 76 ------- embassy-nrf-examples/src/bin/timer.rs | 37 ---- embassy-nrf-examples/src/bin/twim.rs | 35 ---- embassy-nrf-examples/src/bin/twim_lowpower.rs | 54 ----- embassy-nrf-examples/src/bin/uart.rs | 43 ---- embassy-nrf-examples/src/bin/uart_idle.rs | 46 ----- embassy-nrf-examples/src/example_common.rs | 17 -- embassy-rp-examples/.cargo/config.toml | 19 -- embassy-rp-examples/Cargo.toml | 32 --- embassy-rp-examples/build.rs | 31 --- embassy-rp-examples/memory.x | 5 - embassy-rp-examples/src/bin/blinky.rs | 31 --- embassy-rp-examples/src/bin/button.rs | 29 --- embassy-rp-examples/src/bin/uart.rs | 25 --- embassy-rp-examples/src/example_common.rs | 12 -- embassy-std-examples/Cargo.toml | 14 -- embassy-std-examples/src/bin/serial.rs | 59 ------ embassy-std-examples/src/bin/tick.rs | 31 --- embassy-std-examples/src/serial_port.rs | 71 ------- embassy-stm32-examples/.cargo/config.toml | 21 -- embassy-stm32-examples/Cargo.toml | 35 ---- embassy-stm32-examples/build.rs | 31 --- embassy-stm32-examples/memory.x | 7 - embassy-stm32-examples/src/bin/blinky.rs | 54 ----- embassy-stm32-examples/src/bin/button.rs | 59 ------ embassy-stm32-examples/src/bin/button_exti.rs | 83 -------- embassy-stm32-examples/src/bin/spi.rs | 71 ------- embassy-stm32-examples/src/bin/usart.rs | 86 -------- embassy-stm32-examples/src/bin/usart_dma.rs | 90 --------- embassy-stm32-examples/src/example_common.rs | 17 -- examples/nrf/.cargo/config.toml | 21 ++ examples/nrf/Cargo.toml | 31 +++ examples/nrf/build.rs | 31 +++ examples/nrf/memory.x | 7 + examples/nrf/src/bin/blinky.rs | 28 +++ examples/nrf/src/bin/buffered_uart.rs | 68 +++++++ examples/nrf/src/bin/executor_fairness_test.rs | 47 +++++ examples/nrf/src/bin/gpiote_channel.rs | 72 +++++++ examples/nrf/src/bin/gpiote_port.rs | 43 ++++ examples/nrf/src/bin/multiprio.rs | 162 +++++++++++++++ examples/nrf/src/bin/ppi.rs | 87 ++++++++ examples/nrf/src/bin/pwm.rs | 104 ++++++++++ examples/nrf/src/bin/qspi.rs | 84 ++++++++ examples/nrf/src/bin/qspi_lowpower.rs | 85 ++++++++ examples/nrf/src/bin/raw_spawn.rs | 65 ++++++ examples/nrf/src/bin/spim.rs | 76 +++++++ examples/nrf/src/bin/timer.rs | 37 ++++ examples/nrf/src/bin/twim.rs | 35 ++++ examples/nrf/src/bin/twim_lowpower.rs | 54 +++++ examples/nrf/src/bin/uart.rs | 43 ++++ examples/nrf/src/bin/uart_idle.rs | 46 +++++ examples/nrf/src/example_common.rs | 17 ++ examples/rp/.cargo/config.toml | 19 ++ examples/rp/Cargo.toml | 32 +++ examples/rp/build.rs | 31 +++ examples/rp/memory.x | 5 + examples/rp/src/bin/blinky.rs | 31 +++ examples/rp/src/bin/button.rs | 29 +++ examples/rp/src/bin/uart.rs | 25 +++ examples/rp/src/example_common.rs | 12 ++ examples/std/Cargo.toml | 21 ++ examples/std/src/bin/net.rs | 103 ++++++++++ examples/std/src/bin/serial.rs | 59 ++++++ examples/std/src/bin/tick.rs | 31 +++ examples/std/src/serial_port.rs | 71 +++++++ examples/std/src/tuntap.rs | 225 +++++++++++++++++++++ examples/stm32f4/.cargo/config.toml | 21 ++ examples/stm32f4/Cargo.toml | 35 ++++ examples/stm32f4/build.rs | 31 +++ examples/stm32f4/memory.x | 7 + examples/stm32f4/src/bin/blinky.rs | 54 +++++ examples/stm32f4/src/bin/button.rs | 59 ++++++ examples/stm32f4/src/bin/button_exti.rs | 83 ++++++++ examples/stm32f4/src/bin/spi.rs | 71 +++++++ examples/stm32f4/src/bin/usart.rs | 86 ++++++++ examples/stm32f4/src/bin/usart_dma.rs | 90 +++++++++ examples/stm32f4/src/example_common.rs | 17 ++ 95 files changed, 2507 insertions(+), 2169 deletions(-) delete mode 100644 embassy-nrf-examples/.cargo/config.toml delete mode 100644 embassy-nrf-examples/Cargo.toml delete mode 100644 embassy-nrf-examples/build.rs delete mode 100644 embassy-nrf-examples/memory.x delete mode 100644 embassy-nrf-examples/src/bin/blinky.rs delete mode 100644 embassy-nrf-examples/src/bin/buffered_uart.rs delete mode 100644 embassy-nrf-examples/src/bin/executor_fairness_test.rs delete mode 100644 embassy-nrf-examples/src/bin/gpiote_channel.rs delete mode 100644 embassy-nrf-examples/src/bin/gpiote_port.rs delete mode 100644 embassy-nrf-examples/src/bin/multiprio.rs delete mode 100644 embassy-nrf-examples/src/bin/ppi.rs delete mode 100644 embassy-nrf-examples/src/bin/pwm.rs delete mode 100644 embassy-nrf-examples/src/bin/qspi.rs delete mode 100644 embassy-nrf-examples/src/bin/qspi_lowpower.rs delete mode 100644 embassy-nrf-examples/src/bin/raw_spawn.rs delete mode 100644 embassy-nrf-examples/src/bin/spim.rs delete mode 100644 embassy-nrf-examples/src/bin/timer.rs delete mode 100644 embassy-nrf-examples/src/bin/twim.rs delete mode 100644 embassy-nrf-examples/src/bin/twim_lowpower.rs delete mode 100644 embassy-nrf-examples/src/bin/uart.rs delete mode 100644 embassy-nrf-examples/src/bin/uart_idle.rs delete mode 100644 embassy-nrf-examples/src/example_common.rs delete mode 100644 embassy-rp-examples/.cargo/config.toml delete mode 100644 embassy-rp-examples/Cargo.toml delete mode 100644 embassy-rp-examples/build.rs delete mode 100644 embassy-rp-examples/memory.x delete mode 100644 embassy-rp-examples/src/bin/blinky.rs delete mode 100644 embassy-rp-examples/src/bin/button.rs delete mode 100644 embassy-rp-examples/src/bin/uart.rs delete mode 100644 embassy-rp-examples/src/example_common.rs delete mode 100644 embassy-std-examples/Cargo.toml delete mode 100644 embassy-std-examples/src/bin/serial.rs delete mode 100644 embassy-std-examples/src/bin/tick.rs delete mode 100644 embassy-std-examples/src/serial_port.rs delete mode 100644 embassy-stm32-examples/.cargo/config.toml delete mode 100644 embassy-stm32-examples/Cargo.toml delete mode 100644 embassy-stm32-examples/build.rs delete mode 100644 embassy-stm32-examples/memory.x delete mode 100644 embassy-stm32-examples/src/bin/blinky.rs delete mode 100644 embassy-stm32-examples/src/bin/button.rs delete mode 100644 embassy-stm32-examples/src/bin/button_exti.rs delete mode 100644 embassy-stm32-examples/src/bin/spi.rs delete mode 100644 embassy-stm32-examples/src/bin/usart.rs delete mode 100644 embassy-stm32-examples/src/bin/usart_dma.rs delete mode 100644 embassy-stm32-examples/src/example_common.rs create mode 100644 examples/nrf/.cargo/config.toml create mode 100644 examples/nrf/Cargo.toml create mode 100644 examples/nrf/build.rs create mode 100644 examples/nrf/memory.x create mode 100644 examples/nrf/src/bin/blinky.rs create mode 100644 examples/nrf/src/bin/buffered_uart.rs create mode 100644 examples/nrf/src/bin/executor_fairness_test.rs create mode 100644 examples/nrf/src/bin/gpiote_channel.rs create mode 100644 examples/nrf/src/bin/gpiote_port.rs create mode 100644 examples/nrf/src/bin/multiprio.rs create mode 100644 examples/nrf/src/bin/ppi.rs create mode 100644 examples/nrf/src/bin/pwm.rs create mode 100644 examples/nrf/src/bin/qspi.rs create mode 100644 examples/nrf/src/bin/qspi_lowpower.rs create mode 100644 examples/nrf/src/bin/raw_spawn.rs create mode 100644 examples/nrf/src/bin/spim.rs create mode 100644 examples/nrf/src/bin/timer.rs create mode 100644 examples/nrf/src/bin/twim.rs create mode 100644 examples/nrf/src/bin/twim_lowpower.rs create mode 100644 examples/nrf/src/bin/uart.rs create mode 100644 examples/nrf/src/bin/uart_idle.rs create mode 100644 examples/nrf/src/example_common.rs create mode 100644 examples/rp/.cargo/config.toml create mode 100644 examples/rp/Cargo.toml create mode 100644 examples/rp/build.rs create mode 100644 examples/rp/memory.x create mode 100644 examples/rp/src/bin/blinky.rs create mode 100644 examples/rp/src/bin/button.rs create mode 100644 examples/rp/src/bin/uart.rs create mode 100644 examples/rp/src/example_common.rs create mode 100644 examples/std/Cargo.toml create mode 100644 examples/std/src/bin/net.rs create mode 100644 examples/std/src/bin/serial.rs create mode 100644 examples/std/src/bin/tick.rs create mode 100644 examples/std/src/serial_port.rs create mode 100644 examples/std/src/tuntap.rs create mode 100644 examples/stm32f4/.cargo/config.toml create mode 100644 examples/stm32f4/Cargo.toml create mode 100644 examples/stm32f4/build.rs create mode 100644 examples/stm32f4/memory.x create mode 100644 examples/stm32f4/src/bin/blinky.rs create mode 100644 examples/stm32f4/src/bin/button.rs create mode 100644 examples/stm32f4/src/bin/button_exti.rs create mode 100644 examples/stm32f4/src/bin/spi.rs create mode 100644 examples/stm32f4/src/bin/usart.rs create mode 100644 examples/stm32f4/src/bin/usart_dma.rs create mode 100644 examples/stm32f4/src/example_common.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 542107005..3fdc10ab2 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -26,12 +26,10 @@ jobs: - package: embassy target: thumbv6m-none-eabi features: defmt - - package: embassy-std-examples - target: x86_64-unknown-linux-gnu - - package: embassy-net-examples + + - package: examples/std target: x86_64-unknown-linux-gnu - - package: embassy-nrf-examples - target: thumbv7em-none-eabi + - package: embassy-nrf target: thumbv7em-none-eabi features: nrf52805 @@ -59,8 +57,12 @@ jobs: - package: embassy-nrf target: thumbv7em-none-eabi features: nrf52840,defmt - - package: embassy-rp-examples + - package: examples/nrf + target: thumbv7em-none-eabi + + - package: examples/rp target: thumbv6m-none-eabi + - package: embassy-stm32 target: thumbv7em-none-eabi features: stm32f411ce,defmt @@ -76,7 +78,7 @@ jobs: - package: embassy-stm32 target: thumbv6m-none-eabi features: stm32l053r8,defmt - - package: embassy-stm32-examples + - package: examples/stm32f4 target: thumbv7em-none-eabi steps: diff --git a/.vscode/settings.json b/.vscode/settings.json index ca242662b..4c6c3bece 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,8 +3,8 @@ "editor.formatOnSave": true, "rust-analyzer.checkOnSave.allFeatures": false, "rust-analyzer.checkOnSave.allTargets": false, - "rust-analyzer.cargo.target": "thumbv7em-none-eabi", - "rust-analyzer.checkOnSave.target": "thumbv7em-none-eabi", + //"rust-analyzer.cargo.target": "thumbv7em-none-eabi", + //"rust-analyzer.checkOnSave.target": "thumbv7em-none-eabi", "rust-analyzer.procMacro.enable": true, "rust-analyzer.cargo.loadOutDirsFromCheck": true, "files.watcherExclude": { diff --git a/Cargo.example.toml b/Cargo.example.toml index 010487b51..da3a80299 100644 --- a/Cargo.example.toml +++ b/Cargo.example.toml @@ -25,20 +25,21 @@ members = [ # nRF #"embassy-nrf", - #"embassy-nrf-examples", + #"examples/nrf", # stm32 #"embassy-stm32", - #"embassy-stm32-examples", #"stm32-metapac", + # uncomment ONLY ONE example crate. + #"examples/stm32f4", # rp2040 #"embassy-rp", - #"embassy-rp-examples", + #"examples/rp2040", # std #"embassy-std", - #"embassy-std-examples", + #"examples/std", ] [profile.dev] diff --git a/embassy-nrf-examples/.cargo/config.toml b/embassy-nrf-examples/.cargo/config.toml deleted file mode 100644 index 58ac3debd..000000000 --- a/embassy-nrf-examples/.cargo/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -[unstable] -build-std = ["core"] - -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` -runner = "probe-run --chip nRF52840_xxAA" - -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", - - # Code-size optimizations. - "-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", - "-C", "no-vectorize-loops", -] - -[build] -target = "thumbv7em-none-eabi" diff --git a/embassy-nrf-examples/Cargo.toml b/embassy-nrf-examples/Cargo.toml deleted file mode 100644 index 4cec37522..000000000 --- a/embassy-nrf-examples/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[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-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] } -embassy-nrf = { version = "0.1.0", path = "../embassy-nrf", features = ["defmt", "defmt-trace", "nrf52840"] } - -defmt = "0.2.0" -defmt-rtt = "0.2.0" - -cortex-m = { version = "0.7.1", features = ["inline-asm"] } -cortex-m-rt = "0.6.13" -embedded-hal = { version = "0.2.4" } -panic-probe = { version = "0.2.0", features = ["print-defmt"] } -futures = { version = "0.3.8", default-features = false, features = ["async-await"] } diff --git a/embassy-nrf-examples/build.rs b/embassy-nrf-examples/build.rs deleted file mode 100644 index d534cc3df..000000000 --- a/embassy-nrf-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/embassy-nrf-examples/memory.x b/embassy-nrf-examples/memory.x deleted file mode 100644 index 9b04edec0..000000000 --- a/embassy-nrf-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/embassy-nrf-examples/src/bin/blinky.rs b/embassy-nrf-examples/src/bin/blinky.rs deleted file mode 100644 index 8f12cfda9..000000000 --- a/embassy-nrf-examples/src/bin/blinky.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy::time::{Duration, Timer}; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::Peripherals; -use embedded_hal::digital::v2::OutputPin; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); - - loop { - led.set_high().unwrap(); - Timer::after(Duration::from_millis(300)).await; - led.set_low().unwrap(); - Timer::after(Duration::from_millis(300)).await; - } -} diff --git a/embassy-nrf-examples/src/bin/buffered_uart.rs b/embassy-nrf-examples/src/bin/buffered_uart.rs deleted file mode 100644 index c800e64fc..000000000 --- a/embassy-nrf-examples/src/bin/buffered_uart.rs +++ /dev/null @@ -1,68 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; -use embassy_nrf::gpio::NoPin; -use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals}; -use example_common::*; -use futures::pin_mut; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut config = uarte::Config::default(); - config.parity = uarte::Parity::EXCLUDED; - config.baudrate = uarte::Baudrate::BAUD115200; - - let mut tx_buffer = [0u8; 4096]; - let mut rx_buffer = [0u8; 4096]; - - let irq = interrupt::take!(UARTE0_UART0); - let u = unsafe { - BufferedUarte::new( - p.UARTE0, - p.TIMER0, - p.PPI_CH0, - p.PPI_CH1, - irq, - p.P0_08, - p.P0_06, - NoPin, - NoPin, - config, - &mut rx_buffer, - &mut tx_buffer, - ) - }; - 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 {}", buf); - - // Reverse buf - for i in 0..4 { - buf.swap(i, 7 - i); - } - - info!("writing..."); - unwrap!(u.write_all(&buf).await); - info!("write done"); - } -} diff --git a/embassy-nrf-examples/src/bin/executor_fairness_test.rs b/embassy-nrf-examples/src/bin/executor_fairness_test.rs deleted file mode 100644 index 797be4335..000000000 --- a/embassy-nrf-examples/src/bin/executor_fairness_test.rs +++ /dev/null @@ -1,47 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::task::Poll; -use defmt::panic; -use embassy::executor::Spawner; -use embassy::time::{Duration, Instant, Timer}; -use embassy_nrf::{interrupt, Peripherals}; - -#[embassy::task] -async fn run1() { - loop { - info!("DING DONG"); - Timer::after(Duration::from_ticks(16000)).await; - } -} - -#[embassy::task] -async fn run2() { - loop { - Timer::at(Instant::from_ticks(0)).await; - } -} - -#[embassy::task] -async fn run3() { - futures::future::poll_fn(|cx| { - cx.waker().wake_by_ref(); - Poll::<()>::Pending - }) - .await; -} - -#[embassy::main] -async fn main(spawner: Spawner, _p: Peripherals) { - unwrap!(spawner.spawn(run1())); - unwrap!(spawner.spawn(run2())); - unwrap!(spawner.spawn(run3())); -} diff --git a/embassy-nrf-examples/src/bin/gpiote_channel.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs deleted file mode 100644 index 9800aed98..000000000 --- a/embassy-nrf-examples/src/bin/gpiote_channel.rs +++ /dev/null @@ -1,72 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy_nrf::gpio::{Input, Pull}; -use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; -use embassy_nrf::{interrupt, Peripherals}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - info!("Starting!"); - - let ch1 = InputChannel::new( - p.GPIOTE_CH0, - Input::new(p.P0_11, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let ch2 = InputChannel::new( - p.GPIOTE_CH1, - Input::new(p.P0_12, Pull::Up), - InputChannelPolarity::LoToHi, - ); - let ch3 = InputChannel::new( - p.GPIOTE_CH2, - Input::new(p.P0_24, Pull::Up), - InputChannelPolarity::Toggle, - ); - let ch4 = InputChannel::new( - p.GPIOTE_CH3, - Input::new(p.P0_25, Pull::Up), - InputChannelPolarity::Toggle, - ); - - let button1 = async { - loop { - ch1.wait().await; - info!("Button 1 pressed") - } - }; - - let button2 = async { - loop { - ch2.wait().await; - info!("Button 2 released") - } - }; - - let button3 = async { - loop { - ch3.wait().await; - info!("Button 3 toggled") - } - }; - - let button4 = async { - loop { - ch4.wait().await; - info!("Button 4 toggled") - } - }; - - futures::join!(button1, button2, button3, button4); -} diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs deleted file mode 100644 index 4a7951cd3..000000000 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy::traits::gpio::{WaitForHigh, WaitForLow}; -use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; -use embassy_nrf::gpiote::PortInput; -use embassy_nrf::interrupt; -use embassy_nrf::Peripherals; -use example_common::*; - -#[embassy::task(pool_size = 4)] -async fn button_task(n: usize, mut pin: PortInput<'static, AnyPin>) { - loop { - pin.wait_for_low().await; - info!("Button {:?} pressed!", n); - pin.wait_for_high().await; - info!("Button {:?} released!", n); - } -} - -#[embassy::main] -async fn main(spawner: Spawner, p: Peripherals) { - info!("Starting!"); - - let btn1 = PortInput::new(Input::new(p.P0_11.degrade(), Pull::Up)); - let btn2 = PortInput::new(Input::new(p.P0_12.degrade(), Pull::Up)); - let btn3 = PortInput::new(Input::new(p.P0_24.degrade(), Pull::Up)); - let btn4 = PortInput::new(Input::new(p.P0_25.degrade(), Pull::Up)); - - spawner.spawn(button_task(1, btn1)).unwrap(); - spawner.spawn(button_task(2, btn2)).unwrap(); - spawner.spawn(button_task(3, btn3)).unwrap(); - spawner.spawn(button_task(4, btn4)).unwrap(); -} diff --git a/embassy-nrf-examples/src/bin/multiprio.rs b/embassy-nrf-examples/src/bin/multiprio.rs deleted file mode 100644 index 79fa029b3..000000000 --- a/embassy-nrf-examples/src/bin/multiprio.rs +++ /dev/null @@ -1,162 +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(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use cortex_m_rt::entry; -use defmt::panic; -use embassy::executor::{Executor, InterruptExecutor}; -use embassy::interrupt::InterruptExt; -use embassy::time::{Duration, Instant, Timer}; -use embassy::util::Forever; -use embassy_nrf::{interrupt, peripherals, rtc}; - -#[embassy::task] -async fn run_high() { - loop { - info!(" [high] tick!"); - Timer::after(Duration::from_ticks(27374)).await; - } -} - -#[embassy::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 {} ms", ms); - - Timer::after(Duration::from_ticks(23421)).await; - } -} - -#[embassy::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 {} ms", ms); - - Timer::after(Duration::from_ticks(32983)).await; - } -} - -static RTC: Forever> = Forever::new(); -static ALARM_HIGH: Forever> = Forever::new(); -static EXECUTOR_HIGH: Forever> = Forever::new(); -static ALARM_MED: Forever> = Forever::new(); -static EXECUTOR_MED: Forever> = Forever::new(); -static ALARM_LOW: Forever> = Forever::new(); -static EXECUTOR_LOW: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let p = embassy_nrf::init(Default::default()); - - let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); - rtc.start(); - unsafe { embassy::time::set_clock(rtc) }; - - // High-priority executor: SWI1_EGU1, priority level 6 - let irq = interrupt::take!(SWI1_EGU1); - irq.set_priority(interrupt::Priority::P6); - let alarm = ALARM_HIGH.put(rtc.alarm2()); - let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq)); - executor.set_alarm(alarm); - executor.start(|spawner| { - unwrap!(spawner.spawn(run_high())); - }); - - // Medium-priority executor: SWI0_EGU0, priority level 7 - let irq = interrupt::take!(SWI0_EGU0); - irq.set_priority(interrupt::Priority::P7); - let alarm = ALARM_MED.put(rtc.alarm1()); - let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq)); - executor.set_alarm(alarm); - executor.start(|spawner| { - unwrap!(spawner.spawn(run_med())); - }); - - // Low priority executor: runs in thread mode, using WFE/SEV - let alarm = ALARM_LOW.put(rtc.alarm0()); - let executor = EXECUTOR_LOW.put(Executor::new()); - executor.set_alarm(alarm); - executor.run(|spawner| { - unwrap!(spawner.spawn(run_low())); - }); -} diff --git a/embassy-nrf-examples/src/bin/ppi.rs b/embassy-nrf-examples/src/bin/ppi.rs deleted file mode 100644 index 717604b9e..000000000 --- a/embassy-nrf-examples/src/bin/ppi.rs +++ /dev/null @@ -1,87 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::future::pending; -use defmt::panic; -use embassy::executor::Spawner; -use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; -use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; -use embassy_nrf::ppi::Ppi; -use embassy_nrf::{interrupt, Peripherals}; -use gpiote::{OutputChannel, OutputChannelPolarity}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - info!("Starting!"); - - let button1 = InputChannel::new( - p.GPIOTE_CH0, - Input::new(p.P0_11, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let button2 = InputChannel::new( - p.GPIOTE_CH1, - Input::new(p.P0_12, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let button3 = InputChannel::new( - p.GPIOTE_CH2, - Input::new(p.P0_24, Pull::Up), - InputChannelPolarity::HiToLo, - ); - let button4 = InputChannel::new( - p.GPIOTE_CH3, - Input::new(p.P0_25, Pull::Up), - InputChannelPolarity::HiToLo, - ); - - let led1 = OutputChannel::new( - p.GPIOTE_CH4, - Output::new(p.P0_13, Level::Low, OutputDrive::Standard), - OutputChannelPolarity::Toggle, - ); - - let led2 = OutputChannel::new( - p.GPIOTE_CH5, - Output::new(p.P0_14, Level::Low, OutputDrive::Standard), - OutputChannelPolarity::Toggle, - ); - - let mut ppi = Ppi::new(p.PPI_CH0); - ppi.set_event(button1.event_in()); - ppi.set_task(led1.task_out()); - ppi.enable(); - - let mut ppi = Ppi::new(p.PPI_CH1); - ppi.set_event(button2.event_in()); - ppi.set_task(led1.task_clr()); - ppi.enable(); - - let mut ppi = Ppi::new(p.PPI_CH2); - ppi.set_event(button3.event_in()); - ppi.set_task(led1.task_set()); - ppi.enable(); - - let mut ppi = Ppi::new(p.PPI_CH3); - ppi.set_event(button4.event_in()); - ppi.set_task(led1.task_out()); - ppi.set_fork_task(led2.task_out()); - ppi.enable(); - - info!("PPI setup!"); - info!("Press button 1 to toggle LED 1"); - info!("Press button 2 to turn on LED 1"); - info!("Press button 3 to turn off LED 1"); - info!("Press button 4 to toggle LEDs 1 and 2"); - - // Block forever so the above drivers don't get dropped - pending::<()>().await; -} diff --git a/embassy-nrf-examples/src/bin/pwm.rs b/embassy-nrf-examples/src/bin/pwm.rs deleted file mode 100644 index d2874a29b..000000000 --- a/embassy-nrf-examples/src/bin/pwm.rs +++ /dev/null @@ -1,104 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use defmt::{panic, *}; -use embassy::executor::Spawner; -use embassy::time::{Duration, Timer}; -use embassy_nrf::pwm::{Prescaler, Pwm}; -use embassy_nrf::{interrupt, Peripherals}; - -// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='') -static DUTY: [u16; 1024] = [ - 8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440, - 9526, 9613, 9700, 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675, - 10766, 10857, 10948, 11039, 11131, 11223, 11315, 11407, 11500, 11592, 11685, 11779, 11872, - 11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723, 12818, 12914, 13010, 13106, - 13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266, 14364, - 14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632, - 15730, 15828, 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898, - 16995, 17091, 17188, 17284, 17380, 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145, - 18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896, 18989, 19082, 19174, 19266, 19358, - 19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346, 20434, 20521, - 20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620, - 21701, 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639, - 22714, 22788, 22861, 22934, 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564, - 23631, 23698, 23763, 23828, 23892, 23956, 24019, 24081, 24143, 24204, 24264, 24324, 24383, - 24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933, 24983, 25034, 25083, - 25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655, - 25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089, - 26117, 26144, 26170, 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381, - 26397, 26413, 26427, 26441, 26454, 26466, 26477, 26487, 26496, 26505, 26512, 26519, 26525, - 26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537, 26534, 26530, 26525, 26519, - 26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381, 26364, - 26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061, - 26032, 26002, 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615, - 25575, 25535, 25493, 25451, 25407, 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034, - 24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611, 24555, 24499, 24441, 24383, 24324, - 24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631, 23564, 23497, - 23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564, - 22488, 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538, - 21456, 21373, 21290, 21206, 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434, - 20346, 20258, 20169, 20081, 19991, 19902, 19812, 19722, 19631, 19540, 19449, 19358, 19266, - 19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334, 18239, 18145, 18050, - 17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801, - 16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535, - 15437, 15339, 15242, 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266, - 14169, 14072, 13975, 13878, 13781, 13684, 13587, 13491, 13394, 13298, 13202, 13106, 13010, - 12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154, 12060, 11966, 11872, 11779, - 11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675, 10585, - 10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269, - 9184, 9099, 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952, - 7873, 7794, 7716, 7638, 7561, 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738, - 6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172, 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636, - 5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947, 4888, 4828, 4769, 4711, 4653, - 4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892, 3841, 3791, - 3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047, - 3005, 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418, - 2382, 2347, 2312, 2278, 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896, - 1867, 1838, 1810, 1781, 1754, 1726, 1699, 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472, - 1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252, 1232, 1212, 1192, 1173, 1154, 1135, - 1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903, 888, 874, 860, - 846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637, - 627, 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485, - 479, 473, 467, 461, 455, 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390, - 386, 383, 379, 376, 373, 370, 367, 364, 361, 359, 356, 354, 351, 349, 347, 345, 343, 342, 340, - 338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328, 327, 327, 327, 327, 327, 328, - 328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347, 349, 351, - 354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415, - 419, 424, 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526, - 534, 541, 549, 557, 565, 574, 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699, - 710, 721, 733, 744, 756, 768, 781, 793, 806, 819, 833, 846, 860, 874, 888, 903, 918, 933, 948, - 964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154, 1173, 1192, 1212, 1232, - 1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570, 1595, - 1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048, - 2080, 2112, 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603, - 2641, 2680, 2719, 2758, 2798, 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267, - 3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642, 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047, - 4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653, 4711, 4769, 4828, 4888, 4947, - 5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834, 5901, 5968, - 6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105, - 7180, 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111, -]; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let pwm = Pwm::new(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); - pwm.set_prescaler(Prescaler::Div1); - info!("pwm initialized!"); - - let mut i = 0; - loop { - i += 1; - pwm.set_duty(0, DUTY[i % 1024]); - pwm.set_duty(1, DUTY[(i + 256) % 1024]); - pwm.set_duty(2, DUTY[(i + 512) % 1024]); - pwm.set_duty(3, DUTY[(i + 768) % 1024]); - Timer::after(Duration::from_millis(3)).await; - } -} diff --git a/embassy-nrf-examples/src/bin/qspi.rs b/embassy-nrf-examples/src/bin/qspi.rs deleted file mode 100644 index 6e49887a4..000000000 --- a/embassy-nrf-examples/src/bin/qspi.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::{assert_eq, panic}; -use embassy::executor::Spawner; -use embassy::traits::flash::Flash; -use embassy_nrf::Peripherals; -use embassy_nrf::{interrupt, qspi}; -use example_common::*; - -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]); - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - // Config for the MX25R64 present in the nRF52840 DK - let mut config = qspi::Config::default(); - config.read_opcode = qspi::ReadOpcode::READ4IO; - config.write_opcode = qspi::WriteOpcode::PP4IO; - config.write_page_size = qspi::WritePageSize::_256BYTES; - - let irq = interrupt::take!(QSPI); - let mut q = qspi::Qspi::new( - p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, - ) - .await; - - let mut id = [1; 3]; - q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); - info!("id: {}", id); - - // Read status register - let mut status = [4; 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!") -} diff --git a/embassy-nrf-examples/src/bin/qspi_lowpower.rs b/embassy-nrf-examples/src/bin/qspi_lowpower.rs deleted file mode 100644 index ece3243b6..000000000 --- a/embassy-nrf-examples/src/bin/qspi_lowpower.rs +++ /dev/null @@ -1,85 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use core::mem; -use defmt::panic; -use embassy::executor::Spawner; -use embassy::time::{Duration, Timer}; -use embassy::traits::flash::Flash; -use embassy_nrf::Peripherals; -use embassy_nrf::{interrupt, qspi}; -use example_common::*; - -// Workaround for alignment requirements. -// Nicer API will probably come in the future. -#[repr(C, align(4))] -struct AlignedBuf([u8; 64]); - -#[embassy::main] -async fn main(_spawner: Spawner, mut p: Peripherals) { - let mut irq = interrupt::take!(QSPI); - - loop { - // Config for the MX25R64 present in the nRF52840 DK - let mut config = qspi::Config::default(); - config.read_opcode = qspi::ReadOpcode::READ4IO; - config.write_opcode = qspi::WriteOpcode::PP4IO; - config.write_page_size = qspi::WritePageSize::_256BYTES; - config.deep_power_down = Some(qspi::DeepPowerDownConfig { - enter_time: 3, // tDP = 30uS - exit_time: 3, // tRDP = 35uS - }); - - let mut q = qspi::Qspi::new( - &mut p.QSPI, - &mut irq, - &mut p.P0_19, - &mut p.P0_17, - &mut p.P0_20, - &mut p.P0_21, - &mut p.P0_22, - &mut p.P0_23, - config, - ) - .await; - - let mut id = [1; 3]; - q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); - info!("id: {}", id); - - // Read status register - let mut status = [4; 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; 64]); - - info!("reading..."); - q.read(0, &mut buf.0).await.unwrap(); - info!("read: {=[u8]:x}", buf.0); - - // Drop the QSPI instance. This disables the peripehral and deconfigures the pins. - // This clears the borrow on the singletons, so they can now be used again. - mem::drop(q); - - // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. - // During this sleep, the nRF chip should only use ~3uA - Timer::after(Duration::from_secs(1)).await; - } -} diff --git a/embassy-nrf-examples/src/bin/raw_spawn.rs b/embassy-nrf-examples/src/bin/raw_spawn.rs deleted file mode 100644 index 78de7b100..000000000 --- a/embassy-nrf-examples/src/bin/raw_spawn.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![no_std] -#![no_main] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use core::mem; -use cortex_m_rt::entry; -use defmt::panic; -use embassy::executor::raw::Task; -use embassy::executor::Executor; -use embassy::time::{Duration, Timer}; -use embassy::util::Forever; -use embassy_nrf::peripherals; -use embassy_nrf::{interrupt, rtc}; - -async fn run1() { - loop { - info!("BIG INFREQUENT TICK"); - Timer::after(Duration::from_ticks(64000)).await; - } -} - -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 = embassy_nrf::init(Default::default()); - - 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()); - executor.set_alarm(alarm); - - let run1_task = Task::new(); - let run2_task = Task::new(); - - // Safety: these variables do live forever if main never returns. - let run1_task = unsafe { make_static(&run1_task) }; - let run2_task = unsafe { make_static(&run2_task) }; - - executor.run(|spawner| { - unwrap!(spawner.spawn(run1_task.spawn(|| run1()))); - unwrap!(spawner.spawn(run2_task.spawn(|| run2()))); - }); -} - -unsafe fn make_static(t: &T) -> &'static T { - mem::transmute(t) -} diff --git a/embassy-nrf-examples/src/bin/spim.rs b/embassy-nrf-examples/src/bin/spim.rs deleted file mode 100644 index c42cc6015..000000000 --- a/embassy-nrf-examples/src/bin/spim.rs +++ /dev/null @@ -1,76 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy_nrf::gpio::{Level, Output, OutputDrive}; -use embassy_nrf::Peripherals; -use embassy_nrf::{interrupt, spim}; -use embassy_traits::spi::FullDuplex; -use embedded_hal::digital::v2::*; -use example_common::*; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - info!("running!"); - - let mut config = spim::Config::default(); - config.frequency = spim::Frequency::M16; - - let irq = interrupt::take!(SPIM3); - let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config); - - let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); - - // Example on how to talk to an ENC28J60 chip - - // softreset - cortex_m::asm::delay(10); - ncs.set_low().unwrap(); - cortex_m::asm::delay(5); - let tx = [0xFF]; - unwrap!(spim.read_write(&mut [], &tx).await); - cortex_m::asm::delay(10); - ncs.set_high().unwrap(); - - cortex_m::asm::delay(100000); - - let mut rx = [0; 2]; - - // read ESTAT - cortex_m::asm::delay(5000); - ncs.set_low().unwrap(); - cortex_m::asm::delay(5000); - let tx = [0b000_11101, 0]; - unwrap!(spim.read_write(&mut rx, &tx).await); - cortex_m::asm::delay(5000); - ncs.set_high().unwrap(); - info!("estat: {=[?]}", rx); - - // Switch to bank 3 - cortex_m::asm::delay(10); - ncs.set_low().unwrap(); - cortex_m::asm::delay(5); - let tx = [0b100_11111, 0b11]; - unwrap!(spim.read_write(&mut rx, &tx).await); - cortex_m::asm::delay(10); - ncs.set_high().unwrap(); - - // read EREVID - cortex_m::asm::delay(10); - ncs.set_low().unwrap(); - cortex_m::asm::delay(5); - let tx = [0b000_10010, 0]; - unwrap!(spim.read_write(&mut rx, &tx).await); - cortex_m::asm::delay(10); - ncs.set_high().unwrap(); - - info!("erevid: {=[?]}", rx); -} diff --git a/embassy-nrf-examples/src/bin/timer.rs b/embassy-nrf-examples/src/bin/timer.rs deleted file mode 100644 index 43f6d76ce..000000000 --- a/embassy-nrf-examples/src/bin/timer.rs +++ /dev/null @@ -1,37 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use embassy_nrf::Peripherals; -use example_common::*; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy::time::{Duration, Timer}; - -#[embassy::task] -async fn run1() { - loop { - info!("BIG INFREQUENT TICK"); - Timer::after(Duration::from_ticks(64000)).await; - } -} - -#[embassy::task] -async fn run2() { - loop { - info!("tick"); - Timer::after(Duration::from_ticks(13000)).await; - } -} - -#[embassy::main] -async fn main(spawner: Spawner, _p: Peripherals) { - unwrap!(spawner.spawn(run1())); - unwrap!(spawner.spawn(run2())); -} diff --git a/embassy-nrf-examples/src/bin/twim.rs b/embassy-nrf-examples/src/bin/twim.rs deleted file mode 100644 index 537cea160..000000000 --- a/embassy-nrf-examples/src/bin/twim.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Example on how to read a 24C/24LC i2c eeprom. -//! -//! Connect SDA to P0.03, SCL to P0.04 - -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::{panic, *}; -use embassy::executor::Spawner; -use embassy_nrf::twim::{self, Twim}; -use embassy_nrf::{interrupt, Peripherals}; - -const ADDRESS: u8 = 0x50; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - info!("Initializing TWI..."); - let config = twim::Config::default(); - let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); - let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); - - info!("Reading..."); - - let mut buf = [0u8; 16]; - twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap(); - - info!("Read: {=[u8]:x}", buf); -} diff --git a/embassy-nrf-examples/src/bin/twim_lowpower.rs b/embassy-nrf-examples/src/bin/twim_lowpower.rs deleted file mode 100644 index 1cd66a18e..000000000 --- a/embassy-nrf-examples/src/bin/twim_lowpower.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Example on how to read a 24C/24LC i2c eeprom with low power consumption. -//! The eeprom is read every 1 second, while ensuring lowest possible power while -//! sleeping between reads. -//! -//! Connect SDA to P0.03, SCL to P0.04 - -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use core::mem; - -use defmt::{panic, *}; -use embassy::executor::Spawner; -use embassy::time::{Duration, Timer}; -use embassy_nrf::twim::{self, Twim}; -use embassy_nrf::{interrupt, Peripherals}; - -const ADDRESS: u8 = 0x50; - -#[embassy::main] -async fn main(_spawner: Spawner, mut p: Peripherals) { - info!("Started!"); - let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); - - loop { - info!("Initializing TWI..."); - let config = twim::Config::default(); - - // Create the TWIM instance with borrowed singletons, so they're not consumed. - let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); - - info!("Reading..."); - - let mut buf = [0u8; 16]; - twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap(); - - info!("Read: {=[u8]:x}", buf); - - // Drop the TWIM instance. This disables the peripehral and deconfigures the pins. - // This clears the borrow on the singletons, so they can now be used again. - mem::drop(twi); - - // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. - // During this sleep, the nRF chip should only use ~3uA - Timer::after(Duration::from_secs(1)).await; - } -} diff --git a/embassy-nrf-examples/src/bin/uart.rs b/embassy-nrf-examples/src/bin/uart.rs deleted file mode 100644 index e65e2fe51..000000000 --- a/embassy-nrf-examples/src/bin/uart.rs +++ /dev/null @@ -1,43 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use example_common::*; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy::traits::uart::{Read, Write}; -use embassy_nrf::gpio::NoPin; -use embassy_nrf::{interrupt, uarte, Peripherals}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut config = uarte::Config::default(); - config.parity = uarte::Parity::EXCLUDED; - config.baudrate = uarte::Baudrate::BAUD115200; - - let irq = interrupt::take!(UARTE0_UART0); - let mut uart = - unsafe { uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config) }; - - info!("uarte initialized!"); - - // Message must be in SRAM - let mut buf = [0; 8]; - buf.copy_from_slice(b"Hello!\r\n"); - - unwrap!(uart.write(&buf).await); - info!("wrote hello in uart!"); - - loop { - info!("reading..."); - unwrap!(uart.read(&mut buf).await); - info!("writing..."); - unwrap!(uart.write(&buf).await); - } -} diff --git a/embassy-nrf-examples/src/bin/uart_idle.rs b/embassy-nrf-examples/src/bin/uart_idle.rs deleted file mode 100644 index dc2c73433..000000000 --- a/embassy-nrf-examples/src/bin/uart_idle.rs +++ /dev/null @@ -1,46 +0,0 @@ -#![no_std] -#![no_main] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use embassy_traits::uart::ReadUntilIdle; -use example_common::*; - -use defmt::panic; -use embassy::executor::Spawner; -use embassy::traits::uart::Write; -use embassy_nrf::gpio::NoPin; -use embassy_nrf::{interrupt, uarte, Peripherals}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut config = uarte::Config::default(); - config.parity = uarte::Parity::EXCLUDED; - config.baudrate = uarte::Baudrate::BAUD115200; - - let irq = interrupt::take!(UARTE0_UART0); - let mut uart = unsafe { - uarte::UarteWithIdle::new( - p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config, - ) - }; - - info!("uarte initialized!"); - - // Message must be in SRAM - let mut buf = [0; 8]; - buf.copy_from_slice(b"Hello!\r\n"); - - unwrap!(uart.write(&buf).await); - info!("wrote hello in uart!"); - - loop { - info!("reading..."); - let n = unwrap!(uart.read_until_idle(&mut buf).await); - info!("got {} bytes", n); - } -} diff --git a/embassy-nrf-examples/src/example_common.rs b/embassy-nrf-examples/src/example_common.rs deleted file mode 100644 index 54d633837..000000000 --- a/embassy-nrf-examples/src/example_common.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![macro_use] - -use defmt_rtt as _; // global logger -use panic_probe as _; - -pub use defmt::*; - -use core::sync::atomic::{AtomicUsize, Ordering}; - -defmt::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/embassy-rp-examples/.cargo/config.toml b/embassy-rp-examples/.cargo/config.toml deleted file mode 100644 index 1bbbe97da..000000000 --- a/embassy-rp-examples/.cargo/config.toml +++ /dev/null @@ -1,19 +0,0 @@ -[unstable] -build-std = ["core"] - -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-run-rp --chip RP2040" - -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=-Tlink-rp.x", - "-C", "link-arg=-Tdefmt.x", - - # Code-size optimizations. - "-Z", "trap-unreachable=no", -] - -[build] -target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ diff --git a/embassy-rp-examples/Cargo.toml b/embassy-rp-examples/Cargo.toml deleted file mode 100644 index 2cee99bc5..000000000 --- a/embassy-rp-examples/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -authors = ["Dario Nieuwenhuis "] -edition = "2018" -name = "embassy-rp-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-rp = { version = "0.1.0", path = "../embassy-rp", features = ["defmt", "defmt-trace"] } -rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" } -atomic-polyfill = { version = "0.1.1" } - -defmt = "0.2.0" -defmt-rtt = "0.2.0" - -cortex-m = { version = "0.7.1", features = ["inline-asm"] } -cortex-m-rt = "0.6.13" -embedded-hal = { version = "0.2.4" } -panic-probe = { version = "0.2.0", features = ["print-defmt"] } -futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } diff --git a/embassy-rp-examples/build.rs b/embassy-rp-examples/build.rs deleted file mode 100644 index d534cc3df..000000000 --- a/embassy-rp-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/embassy-rp-examples/memory.x b/embassy-rp-examples/memory.x deleted file mode 100644 index aba861aae..000000000 --- a/embassy-rp-examples/memory.x +++ /dev/null @@ -1,5 +0,0 @@ -MEMORY { - BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 - FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 - RAM : ORIGIN = 0x20000000, LENGTH = 256K -} \ No newline at end of file diff --git a/embassy-rp-examples/src/bin/blinky.rs b/embassy-rp-examples/src/bin/blinky.rs deleted file mode 100644 index e42999912..000000000 --- a/embassy-rp-examples/src/bin/blinky.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![no_std] -#![no_main] -#![feature(asm)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use defmt::*; -use embassy::executor::Spawner; -use embassy_rp::{gpio, Peripherals}; -use embedded_hal::digital::v2::OutputPin; -use gpio::{Level, Output}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let mut led = Output::new(p.PIN_25, Level::Low); - - loop { - info!("led on!"); - led.set_high().unwrap(); - cortex_m::asm::delay(1_000_000); - - info!("led off!"); - led.set_low().unwrap(); - cortex_m::asm::delay(1_000_000); - } -} diff --git a/embassy-rp-examples/src/bin/button.rs b/embassy-rp-examples/src/bin/button.rs deleted file mode 100644 index c4d942ff5..000000000 --- a/embassy-rp-examples/src/bin/button.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![no_std] -#![no_main] -#![feature(asm)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use embassy::executor::Spawner; -use embassy_rp::gpio::{Input, Level, Output, Pull}; -use embassy_rp::Peripherals; -use embedded_hal::digital::v2::{InputPin, OutputPin}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let button = Input::new(p.PIN_28, Pull::Up); - let mut led = Output::new(p.PIN_25, Level::Low); - - loop { - if button.is_high().unwrap() { - led.set_high().unwrap(); - } else { - led.set_low().unwrap(); - } - } -} diff --git a/embassy-rp-examples/src/bin/uart.rs b/embassy-rp-examples/src/bin/uart.rs deleted file mode 100644 index 8b5f2a53b..000000000 --- a/embassy-rp-examples/src/bin/uart.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![no_std] -#![no_main] -#![feature(asm)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use embassy::executor::Spawner; -use embassy_rp::{uart, Peripherals}; - -#[embassy::main] -async fn main(_spawner: Spawner, p: Peripherals) { - let config = uart::Config::default(); - let mut uart = uart::Uart::new(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config); - uart.send("Hello World!\r\n".as_bytes()); - - loop { - uart.send("hello there!\r\n".as_bytes()); - cortex_m::asm::delay(1_000_000); - } -} diff --git a/embassy-rp-examples/src/example_common.rs b/embassy-rp-examples/src/example_common.rs deleted file mode 100644 index f7c4ef57a..000000000 --- a/embassy-rp-examples/src/example_common.rs +++ /dev/null @@ -1,12 +0,0 @@ -use core::sync::atomic::{AtomicUsize, Ordering}; -use defmt_rtt as _; -use panic_probe as _; - -defmt::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/embassy-std-examples/Cargo.toml b/embassy-std-examples/Cargo.toml deleted file mode 100644 index 0998899c8..000000000 --- a/embassy-std-examples/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -authors = ["Dario Nieuwenhuis "] -edition = "2018" -name = "embassy-std-examples" -version = "0.1.0" - -[dependencies] -async-io = "1.3.1" -embassy = { version = "0.1.0", path = "../embassy", features = ["log"] } -embassy-std = { version = "0.1.0", path = "../embassy-std" } -env_logger = "0.8.2" -futures = { version = "0.3.8", default-features = false, features = ["async-await"] } -log = "0.4.11" -nix = "0.19.1" diff --git a/embassy-std-examples/src/bin/serial.rs b/embassy-std-examples/src/bin/serial.rs deleted file mode 100644 index 1b22dc0de..000000000 --- a/embassy-std-examples/src/bin/serial.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../serial_port.rs"] -mod serial_port; - -use async_io::Async; -use embassy::io::AsyncBufReadExt; -use embassy::util::Forever; -use embassy_std::Executor; -use log::*; -use nix::sys::termios; - -use self::serial_port::SerialPort; - -#[embassy::task] -async fn run() { - // Open the serial port. - let baudrate = termios::BaudRate::B115200; - let port = SerialPort::new("/dev/ttyACM0", baudrate).unwrap(); - //let port = Spy::new(port); - - // Use async_io's reactor for async IO. - // This demonstrates how embassy's executor can drive futures from another IO library. - // Essentially, async_io::Async converts from AsRawFd+Read+Write to futures's AsyncRead+AsyncWrite - let port = Async::new(port).unwrap(); - - // This implements futures's AsyncBufRead based on futures's AsyncRead - let port = futures::io::BufReader::new(port); - - // We can then use FromStdIo to convert from futures's AsyncBufRead+AsyncWrite - // to embassy's AsyncBufRead+AsyncWrite - let mut port = embassy::io::FromStdIo::new(port); - - info!("Serial opened!"); - - loop { - let mut buf = [0u8; 256]; - let n = port.read(&mut buf).await.unwrap(); - info!("read {:?}", &buf[..n]); - } -} - -static EXECUTOR: Forever = Forever::new(); - -fn main() { - env_logger::builder() - .filter_level(log::LevelFilter::Debug) - .filter_module("async_io", log::LevelFilter::Info) - .format_timestamp_nanos() - .init(); - - let executor = EXECUTOR.put(Executor::new()); - executor.run(|spawner| { - spawner.spawn(run()).unwrap(); - }); -} diff --git a/embassy-std-examples/src/bin/tick.rs b/embassy-std-examples/src/bin/tick.rs deleted file mode 100644 index 6f30edb34..000000000 --- a/embassy-std-examples/src/bin/tick.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -use embassy::time::{Duration, Timer}; -use embassy::util::Forever; -use embassy_std::Executor; -use log::*; - -#[embassy::task] -async fn run() { - loop { - info!("tick"); - Timer::after(Duration::from_secs(1)).await; - } -} - -static EXECUTOR: Forever = Forever::new(); - -fn main() { - env_logger::builder() - .filter_level(log::LevelFilter::Debug) - .format_timestamp_nanos() - .init(); - - let executor = EXECUTOR.put(Executor::new()); - executor.run(|spawner| { - spawner.spawn(run()).unwrap(); - }); -} diff --git a/embassy-std-examples/src/serial_port.rs b/embassy-std-examples/src/serial_port.rs deleted file mode 100644 index 7ac1b1edb..000000000 --- a/embassy-std-examples/src/serial_port.rs +++ /dev/null @@ -1,71 +0,0 @@ -use nix::fcntl::OFlag; -use nix::sys::termios; -use nix::Error; -use std::io; -use std::os::unix::io::{AsRawFd, RawFd}; - -pub struct SerialPort { - fd: RawFd, -} - -impl SerialPort { - pub fn new<'a, P: ?Sized + nix::NixPath>( - path: &P, - baudrate: termios::BaudRate, - ) -> io::Result { - let fd = nix::fcntl::open( - path, - OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, - nix::sys::stat::Mode::empty(), - ) - .map_err(to_io_error)?; - - let mut cfg = termios::tcgetattr(fd).map_err(to_io_error)?; - cfg.input_flags = termios::InputFlags::empty(); - cfg.output_flags = termios::OutputFlags::empty(); - cfg.control_flags = termios::ControlFlags::empty(); - cfg.local_flags = termios::LocalFlags::empty(); - termios::cfmakeraw(&mut cfg); - cfg.input_flags |= termios::InputFlags::IGNBRK; - cfg.control_flags |= termios::ControlFlags::CREAD; - //cfg.control_flags |= termios::ControlFlags::CRTSCTS; - termios::cfsetospeed(&mut cfg, baudrate).map_err(to_io_error)?; - termios::cfsetispeed(&mut cfg, baudrate).map_err(to_io_error)?; - termios::cfsetspeed(&mut cfg, baudrate).map_err(to_io_error)?; - // Set VMIN = 1 to block until at least one character is received. - cfg.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; - termios::tcsetattr(fd, termios::SetArg::TCSANOW, &cfg).map_err(to_io_error)?; - termios::tcflush(fd, termios::FlushArg::TCIOFLUSH).map_err(to_io_error)?; - - Ok(Self { fd }) - } -} - -impl AsRawFd for SerialPort { - fn as_raw_fd(&self) -> RawFd { - self.fd - } -} - -impl io::Read for SerialPort { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - nix::unistd::read(self.fd, buf).map_err(to_io_error) - } -} - -impl io::Write for SerialPort { - fn write(&mut self, buf: &[u8]) -> io::Result { - nix::unistd::write(self.fd, buf).map_err(to_io_error) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -fn to_io_error(e: Error) -> io::Error { - match e { - Error::Sys(errno) => errno.into(), - e => io::Error::new(io::ErrorKind::InvalidInput, e), - } -} diff --git a/embassy-stm32-examples/.cargo/config.toml b/embassy-stm32-examples/.cargo/config.toml deleted file mode 100644 index 8704a9ba5..000000000 --- a/embassy-stm32-examples/.cargo/config.toml +++ /dev/null @@ -1,21 +0,0 @@ -[unstable] -build-std = ["core"] - -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` -runner = "probe-run --chip STM32F429ZITx" - -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", - - # Code-size optimizations. - "-Z", "trap-unreachable=no", - "-C", "inline-threshold=5", - "-C", "no-vectorize-loops", -] - -[build] -target = "thumbv7em-none-eabi" diff --git a/embassy-stm32-examples/Cargo.toml b/embassy-stm32-examples/Cargo.toml deleted file mode 100644 index 799f0f9b9..000000000 --- a/embassy-stm32-examples/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -authors = ["Dario Nieuwenhuis "] -edition = "2018" -name = "embassy-stm32f4-examples" -version = "0.1.0" -resolver = "2" - -[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-traits = { version = "0.1.0", path = "../embassy-traits", features = ["defmt"] } -embassy-stm32 = { version = "0.1.0", path = "../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f429zi"] } -embassy-extras = {version = "0.1.0", path = "../embassy-extras" } -stm32f4 = { version = "0.13", features = ["stm32f429"] } - -defmt = "0.2.0" -defmt-rtt = "0.2.0" - -cortex-m = "0.7.1" -cortex-m-rt = "0.6.14" -embedded-hal = { version = "0.2.4" } -panic-probe = { version = "0.2.0", features= ["print-defmt"] } -futures = { version = "0.3.8", default-features = false, features = ["async-await"] } -rtt-target = { version = "0.3", features = ["cortex-m"] } -heapless = "0.7" \ No newline at end of file diff --git a/embassy-stm32-examples/build.rs b/embassy-stm32-examples/build.rs deleted file mode 100644 index d534cc3df..000000000 --- a/embassy-stm32-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/embassy-stm32-examples/memory.x b/embassy-stm32-examples/memory.x deleted file mode 100644 index f21e32572..000000000 --- a/embassy-stm32-examples/memory.x +++ /dev/null @@ -1,7 +0,0 @@ -MEMORY -{ - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - /* These values correspond to the STM32F429ZI */ - FLASH : ORIGIN = 0x08000000, LENGTH = 2048K - RAM : ORIGIN = 0x20000000, LENGTH = 192K -} diff --git a/embassy-stm32-examples/src/bin/blinky.rs b/embassy-stm32-examples/src/bin/blinky.rs deleted file mode 100644 index 7590764d8..000000000 --- a/embassy-stm32-examples/src/bin/blinky.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![no_std] -#![no_main] -#![feature(trait_alias)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use embassy_stm32::gpio::{Level, Output}; -use embedded_hal::digital::v2::OutputPin; -use example_common::*; - -use cortex_m_rt::entry; -use stm32f4::stm32f429 as pac; - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let pp = pac::Peripherals::take().unwrap(); - - pp.DBGMCU.cr.modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_standby().set_bit(); - w.dbg_stop().set_bit() - }); - pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); - - pp.RCC.ahb1enr.modify(|_, w| { - w.gpioaen().enabled(); - w.gpioben().enabled(); - w.gpiocen().enabled(); - w.gpioden().enabled(); - w.gpioeen().enabled(); - w.gpiofen().enabled(); - w - }); - - let p = embassy_stm32::init(Default::default()); - - let mut led = Output::new(p.PB7, Level::High); - - loop { - info!("high"); - led.set_high().unwrap(); - cortex_m::asm::delay(10_000_000); - - info!("low"); - led.set_low().unwrap(); - cortex_m::asm::delay(10_000_000); - } -} diff --git a/embassy-stm32-examples/src/bin/button.rs b/embassy-stm32-examples/src/bin/button.rs deleted file mode 100644 index 1ee99f527..000000000 --- a/embassy-stm32-examples/src/bin/button.rs +++ /dev/null @@ -1,59 +0,0 @@ -#![no_std] -#![no_main] -#![feature(trait_alias)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use embassy_stm32::gpio::{Input, Level, Output, Pull}; -use embedded_hal::digital::v2::{InputPin, OutputPin}; -use example_common::*; - -use cortex_m_rt::entry; -use stm32f4::stm32f429 as pac; - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let pp = pac::Peripherals::take().unwrap(); - - pp.DBGMCU.cr.modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_standby().set_bit(); - w.dbg_stop().set_bit() - }); - pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); - - pp.RCC.ahb1enr.modify(|_, w| { - w.gpioaen().enabled(); - w.gpioben().enabled(); - w.gpiocen().enabled(); - w.gpioden().enabled(); - w.gpioeen().enabled(); - w.gpiofen().enabled(); - w - }); - - let p = embassy_stm32::init(Default::default()); - - let button = Input::new(p.PC13, Pull::Down); - let mut led1 = Output::new(p.PB0, Level::High); - let _led2 = Output::new(p.PB7, Level::High); - let mut led3 = Output::new(p.PB14, Level::High); - - loop { - if button.is_high().unwrap() { - info!("high"); - led1.set_high().unwrap(); - led3.set_low().unwrap(); - } else { - info!("low"); - led1.set_low().unwrap(); - led3.set_high().unwrap(); - } - } -} diff --git a/embassy-stm32-examples/src/bin/button_exti.rs b/embassy-stm32-examples/src/bin/button_exti.rs deleted file mode 100644 index 8fc889dad..000000000 --- a/embassy-stm32-examples/src/bin/button_exti.rs +++ /dev/null @@ -1,83 +0,0 @@ -#![no_std] -#![no_main] -#![feature(trait_alias)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use embassy::executor::Executor; -use embassy::time::Clock; -use embassy::util::Forever; -use embassy_stm32::exti::ExtiInput; -use embassy_stm32::gpio::{Input, Pull}; -use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; -use example_common::*; - -use cortex_m_rt::entry; -use stm32f4::stm32f429 as pac; - -#[embassy::task] -async fn main_task() { - let p = embassy_stm32::init(Default::default()); - - let button = Input::new(p.PC13, Pull::Down); - let mut button = ExtiInput::new(button, p.EXTI13); - - info!("Press the USER button..."); - - loop { - button.wait_for_rising_edge().await; - info!("Pressed!"); - button.wait_for_falling_edge().await; - info!("Released!"); - } -} - -struct ZeroClock; - -impl Clock for ZeroClock { - fn now(&self) -> u64 { - 0 - } -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let pp = pac::Peripherals::take().unwrap(); - - pp.DBGMCU.cr.modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_standby().set_bit(); - w.dbg_stop().set_bit() - }); - pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); - - pp.RCC.ahb1enr.modify(|_, w| { - w.gpioaen().enabled(); - w.gpioben().enabled(); - w.gpiocen().enabled(); - w.gpioden().enabled(); - w.gpioeen().enabled(); - w.gpiofen().enabled(); - w - }); - pp.RCC.apb2enr.modify(|_, w| { - w.syscfgen().enabled(); - w - }); - - unsafe { embassy::time::set_clock(&ZeroClock) }; - - let executor = EXECUTOR.put(Executor::new()); - - executor.run(|spawner| { - unwrap!(spawner.spawn(main_task())); - }) -} diff --git a/embassy-stm32-examples/src/bin/spi.rs b/embassy-stm32-examples/src/bin/spi.rs deleted file mode 100644 index af0d57412..000000000 --- a/embassy-stm32-examples/src/bin/spi.rs +++ /dev/null @@ -1,71 +0,0 @@ -#![no_std] -#![no_main] -#![feature(trait_alias)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; - -use embassy_stm32::gpio::{Level, Output}; -use embedded_hal::digital::v2::OutputPin; -use example_common::*; - -use cortex_m_rt::entry; -use embassy_stm32::spi::{Config, Spi}; -use embassy_stm32::time::Hertz; -use embedded_hal::blocking::spi::Transfer; -use stm32f4::stm32f429 as pac; - -#[entry] -fn main() -> ! { - info!("Hello World, dude!"); - - let pp = pac::Peripherals::take().unwrap(); - - pp.DBGMCU.cr.modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_standby().set_bit(); - w.dbg_stop().set_bit() - }); - pp.RCC.ahb1enr.modify(|_, w| w.dma1en().set_bit()); - - pp.RCC.apb1enr.modify(|_, w| { - w.spi3en().enabled(); - w - }); - - pp.RCC.ahb1enr.modify(|_, w| { - w.gpioaen().enabled(); - w.gpioben().enabled(); - w.gpiocen().enabled(); - w.gpioden().enabled(); - w.gpioeen().enabled(); - w.gpiofen().enabled(); - w - }); - - let p = embassy_stm32::init(Default::default()); - - let mut spi = Spi::new( - Hertz(16_000_000), - p.SPI3, - p.PC10, - p.PC12, - p.PC11, - Hertz(1_000_000), - Config::default(), - ); - - let mut cs = Output::new(p.PE0, Level::High); - - loop { - let mut buf = [0x0A; 4]; - unwrap!(cs.set_low()); - unwrap!(spi.transfer(&mut buf)); - unwrap!(cs.set_high()); - info!("xfer {=[u8]:x}", buf); - } -} diff --git a/embassy-stm32-examples/src/bin/usart.rs b/embassy-stm32-examples/src/bin/usart.rs deleted file mode 100644 index f7b66f86b..000000000 --- a/embassy-stm32-examples/src/bin/usart.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![no_std] -#![no_main] -#![feature(trait_alias)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use cortex_m::prelude::_embedded_hal_blocking_serial_Write; -use embassy::executor::Executor; -use embassy::time::Clock; -use embassy::util::Forever; -use embassy_stm32::usart::{Config, Uart}; -use example_common::*; - -use cortex_m_rt::entry; -use stm32f4::stm32f429 as pac; - -#[embassy::task] -async fn main_task() { - let p = embassy_stm32::init(Default::default()); - - let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000); - - usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); - info!("wrote Hello, starting echo"); - - let mut buf = [0u8; 1]; - loop { - usart.read(&mut buf).unwrap(); - usart.bwrite_all(&buf).unwrap(); - } -} - -struct ZeroClock; - -impl Clock for ZeroClock { - fn now(&self) -> u64 { - 0 - } -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let pp = pac::Peripherals::take().unwrap(); - - pp.DBGMCU.cr.modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_standby().set_bit(); - w.dbg_stop().set_bit() - }); - pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); - - pp.RCC.ahb1enr.modify(|_, w| { - w.gpioaen().enabled(); - w.gpioben().enabled(); - w.gpiocen().enabled(); - w.gpioden().enabled(); - w.gpioeen().enabled(); - w.gpiofen().enabled(); - w - }); - pp.RCC.apb2enr.modify(|_, w| { - w.syscfgen().enabled(); - w - }); - pp.RCC.apb1enr.modify(|_, w| { - w.usart3en().enabled(); - w - }); - - unsafe { embassy::time::set_clock(&ZeroClock) }; - - let executor = EXECUTOR.put(Executor::new()); - - executor.run(|spawner| { - unwrap!(spawner.spawn(main_task())); - }) -} diff --git a/embassy-stm32-examples/src/bin/usart_dma.rs b/embassy-stm32-examples/src/bin/usart_dma.rs deleted file mode 100644 index fae05b607..000000000 --- a/embassy-stm32-examples/src/bin/usart_dma.rs +++ /dev/null @@ -1,90 +0,0 @@ -#![no_std] -#![no_main] -#![feature(trait_alias)] -#![feature(min_type_alias_impl_trait)] -#![feature(impl_trait_in_bindings)] -#![feature(type_alias_impl_trait)] -#![allow(incomplete_features)] - -#[path = "../example_common.rs"] -mod example_common; -use core::fmt::Write; -use cortex_m_rt::entry; -use embassy::executor::Executor; -use embassy::time::Clock; -use embassy::util::Forever; -use embassy_stm32::usart::{Config, Uart}; -use example_common::*; -use heapless::String; -use stm32f4::stm32f429 as pac; - -#[embassy::task] -async fn main_task() { - let mut p = embassy_stm32::init(Default::default()); - - let config = Config::default(); - let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000); - - for n in 0u32.. { - let mut s: String<128> = String::new(); - core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); - - usart - .write_dma(&mut p.DMA1_CH3, s.as_bytes()) - .await - .unwrap(); - info!("wrote DMA"); - } -} - -struct ZeroClock; - -impl Clock for ZeroClock { - fn now(&self) -> u64 { - 0 - } -} - -static EXECUTOR: Forever = Forever::new(); - -#[entry] -fn main() -> ! { - info!("Hello World!"); - - let pp = pac::Peripherals::take().unwrap(); - - pp.DBGMCU.cr.modify(|_, w| { - w.dbg_sleep().set_bit(); - w.dbg_standby().set_bit(); - w.dbg_stop().set_bit() - }); - pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); - - pp.RCC.ahb1enr.modify(|_, w| { - w.gpioaen().enabled(); - w.gpioben().enabled(); - w.gpiocen().enabled(); - w.gpioden().enabled(); - w.gpioeen().enabled(); - w.gpiofen().enabled(); - w.dma1en().enabled(); - w.dma2en().enabled(); - w - }); - pp.RCC.apb2enr.modify(|_, w| { - w.syscfgen().enabled(); - w - }); - pp.RCC.apb1enr.modify(|_, w| { - w.usart3en().enabled(); - w - }); - - unsafe { embassy::time::set_clock(&ZeroClock) }; - - let executor = EXECUTOR.put(Executor::new()); - - executor.run(|spawner| { - unwrap!(spawner.spawn(main_task())); - }) -} diff --git a/embassy-stm32-examples/src/example_common.rs b/embassy-stm32-examples/src/example_common.rs deleted file mode 100644 index 54d633837..000000000 --- a/embassy-stm32-examples/src/example_common.rs +++ /dev/null @@ -1,17 +0,0 @@ -#![macro_use] - -use defmt_rtt as _; // global logger -use panic_probe as _; - -pub use defmt::*; - -use core::sync::atomic::{AtomicUsize, Ordering}; - -defmt::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/nrf/.cargo/config.toml b/examples/nrf/.cargo/config.toml new file mode 100644 index 000000000..58ac3debd --- /dev/null +++ b/examples/nrf/.cargo/config.toml @@ -0,0 +1,21 @@ +[unstable] +build-std = ["core"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips` +runner = "probe-run --chip nRF52840_xxAA" + +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", + + # Code-size optimizations. + "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", +] + +[build] +target = "thumbv7em-none-eabi" diff --git a/examples/nrf/Cargo.toml b/examples/nrf/Cargo.toml new file mode 100644 index 000000000..fa1dab360 --- /dev/null +++ b/examples/nrf/Cargo.toml @@ -0,0 +1,31 @@ +[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-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } +embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "defmt-trace", "nrf52840"] } + +defmt = "0.2.0" +defmt-rtt = "0.2.0" + +cortex-m = { version = "0.7.1", features = ["inline-asm"] } +cortex-m-rt = "0.6.13" +embedded-hal = { version = "0.2.4" } +panic-probe = { version = "0.2.0", features = ["print-defmt"] } +futures = { version = "0.3.8", default-features = false, features = ["async-await"] } diff --git a/examples/nrf/build.rs b/examples/nrf/build.rs new file mode 100644 index 000000000..d534cc3df --- /dev/null +++ b/examples/nrf/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/examples/nrf/memory.x b/examples/nrf/memory.x new file mode 100644 index 000000000..9b04edec0 --- /dev/null +++ b/examples/nrf/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/examples/nrf/src/bin/blinky.rs b/examples/nrf/src/bin/blinky.rs new file mode 100644 index 000000000..8f12cfda9 --- /dev/null +++ b/examples/nrf/src/bin/blinky.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::Peripherals; +use embedded_hal::digital::v2::OutputPin; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); + + loop { + led.set_high().unwrap(); + Timer::after(Duration::from_millis(300)).await; + led.set_low().unwrap(); + Timer::after(Duration::from_millis(300)).await; + } +} diff --git a/examples/nrf/src/bin/buffered_uart.rs b/examples/nrf/src/bin/buffered_uart.rs new file mode 100644 index 000000000..c800e64fc --- /dev/null +++ b/examples/nrf/src/bin/buffered_uart.rs @@ -0,0 +1,68 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy::io::{AsyncBufReadExt, AsyncWriteExt}; +use embassy_nrf::gpio::NoPin; +use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals}; +use example_common::*; +use futures::pin_mut; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; + + let mut tx_buffer = [0u8; 4096]; + let mut rx_buffer = [0u8; 4096]; + + let irq = interrupt::take!(UARTE0_UART0); + let u = unsafe { + BufferedUarte::new( + p.UARTE0, + p.TIMER0, + p.PPI_CH0, + p.PPI_CH1, + irq, + p.P0_08, + p.P0_06, + NoPin, + NoPin, + config, + &mut rx_buffer, + &mut tx_buffer, + ) + }; + 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 {}", buf); + + // Reverse buf + for i in 0..4 { + buf.swap(i, 7 - i); + } + + info!("writing..."); + unwrap!(u.write_all(&buf).await); + info!("write done"); + } +} diff --git a/examples/nrf/src/bin/executor_fairness_test.rs b/examples/nrf/src/bin/executor_fairness_test.rs new file mode 100644 index 000000000..797be4335 --- /dev/null +++ b/examples/nrf/src/bin/executor_fairness_test.rs @@ -0,0 +1,47 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::task::Poll; +use defmt::panic; +use embassy::executor::Spawner; +use embassy::time::{Duration, Instant, Timer}; +use embassy_nrf::{interrupt, Peripherals}; + +#[embassy::task] +async fn run1() { + loop { + info!("DING DONG"); + Timer::after(Duration::from_ticks(16000)).await; + } +} + +#[embassy::task] +async fn run2() { + loop { + Timer::at(Instant::from_ticks(0)).await; + } +} + +#[embassy::task] +async fn run3() { + futures::future::poll_fn(|cx| { + cx.waker().wake_by_ref(); + Poll::<()>::Pending + }) + .await; +} + +#[embassy::main] +async fn main(spawner: Spawner, _p: Peripherals) { + unwrap!(spawner.spawn(run1())); + unwrap!(spawner.spawn(run2())); + unwrap!(spawner.spawn(run3())); +} diff --git a/examples/nrf/src/bin/gpiote_channel.rs b/examples/nrf/src/bin/gpiote_channel.rs new file mode 100644 index 000000000..9800aed98 --- /dev/null +++ b/examples/nrf/src/bin/gpiote_channel.rs @@ -0,0 +1,72 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; +use embassy_nrf::{interrupt, Peripherals}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Starting!"); + + let ch1 = InputChannel::new( + p.GPIOTE_CH0, + Input::new(p.P0_11, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let ch2 = InputChannel::new( + p.GPIOTE_CH1, + Input::new(p.P0_12, Pull::Up), + InputChannelPolarity::LoToHi, + ); + let ch3 = InputChannel::new( + p.GPIOTE_CH2, + Input::new(p.P0_24, Pull::Up), + InputChannelPolarity::Toggle, + ); + let ch4 = InputChannel::new( + p.GPIOTE_CH3, + Input::new(p.P0_25, Pull::Up), + InputChannelPolarity::Toggle, + ); + + let button1 = async { + loop { + ch1.wait().await; + info!("Button 1 pressed") + } + }; + + let button2 = async { + loop { + ch2.wait().await; + info!("Button 2 released") + } + }; + + let button3 = async { + loop { + ch3.wait().await; + info!("Button 3 toggled") + } + }; + + let button4 = async { + loop { + ch4.wait().await; + info!("Button 4 toggled") + } + }; + + futures::join!(button1, button2, button3, button4); +} diff --git a/examples/nrf/src/bin/gpiote_port.rs b/examples/nrf/src/bin/gpiote_port.rs new file mode 100644 index 000000000..4a7951cd3 --- /dev/null +++ b/examples/nrf/src/bin/gpiote_port.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy::traits::gpio::{WaitForHigh, WaitForLow}; +use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; +use embassy_nrf::gpiote::PortInput; +use embassy_nrf::interrupt; +use embassy_nrf::Peripherals; +use example_common::*; + +#[embassy::task(pool_size = 4)] +async fn button_task(n: usize, mut pin: PortInput<'static, AnyPin>) { + loop { + pin.wait_for_low().await; + info!("Button {:?} pressed!", n); + pin.wait_for_high().await; + info!("Button {:?} released!", n); + } +} + +#[embassy::main] +async fn main(spawner: Spawner, p: Peripherals) { + info!("Starting!"); + + let btn1 = PortInput::new(Input::new(p.P0_11.degrade(), Pull::Up)); + let btn2 = PortInput::new(Input::new(p.P0_12.degrade(), Pull::Up)); + let btn3 = PortInput::new(Input::new(p.P0_24.degrade(), Pull::Up)); + let btn4 = PortInput::new(Input::new(p.P0_25.degrade(), Pull::Up)); + + spawner.spawn(button_task(1, btn1)).unwrap(); + spawner.spawn(button_task(2, btn2)).unwrap(); + spawner.spawn(button_task(3, btn3)).unwrap(); + spawner.spawn(button_task(4, btn4)).unwrap(); +} diff --git a/examples/nrf/src/bin/multiprio.rs b/examples/nrf/src/bin/multiprio.rs new file mode 100644 index 000000000..79fa029b3 --- /dev/null +++ b/examples/nrf/src/bin/multiprio.rs @@ -0,0 +1,162 @@ +//! 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(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use cortex_m_rt::entry; +use defmt::panic; +use embassy::executor::{Executor, InterruptExecutor}; +use embassy::interrupt::InterruptExt; +use embassy::time::{Duration, Instant, Timer}; +use embassy::util::Forever; +use embassy_nrf::{interrupt, peripherals, rtc}; + +#[embassy::task] +async fn run_high() { + loop { + info!(" [high] tick!"); + Timer::after(Duration::from_ticks(27374)).await; + } +} + +#[embassy::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 {} ms", ms); + + Timer::after(Duration::from_ticks(23421)).await; + } +} + +#[embassy::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 {} ms", ms); + + Timer::after(Duration::from_ticks(32983)).await; + } +} + +static RTC: Forever> = Forever::new(); +static ALARM_HIGH: Forever> = Forever::new(); +static EXECUTOR_HIGH: Forever> = Forever::new(); +static ALARM_MED: Forever> = Forever::new(); +static EXECUTOR_MED: Forever> = Forever::new(); +static ALARM_LOW: Forever> = Forever::new(); +static EXECUTOR_LOW: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_nrf::init(Default::default()); + + let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1))); + rtc.start(); + unsafe { embassy::time::set_clock(rtc) }; + + // High-priority executor: SWI1_EGU1, priority level 6 + let irq = interrupt::take!(SWI1_EGU1); + irq.set_priority(interrupt::Priority::P6); + let alarm = ALARM_HIGH.put(rtc.alarm2()); + let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq)); + executor.set_alarm(alarm); + executor.start(|spawner| { + unwrap!(spawner.spawn(run_high())); + }); + + // Medium-priority executor: SWI0_EGU0, priority level 7 + let irq = interrupt::take!(SWI0_EGU0); + irq.set_priority(interrupt::Priority::P7); + let alarm = ALARM_MED.put(rtc.alarm1()); + let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq)); + executor.set_alarm(alarm); + executor.start(|spawner| { + unwrap!(spawner.spawn(run_med())); + }); + + // Low priority executor: runs in thread mode, using WFE/SEV + let alarm = ALARM_LOW.put(rtc.alarm0()); + let executor = EXECUTOR_LOW.put(Executor::new()); + executor.set_alarm(alarm); + executor.run(|spawner| { + unwrap!(spawner.spawn(run_low())); + }); +} diff --git a/examples/nrf/src/bin/ppi.rs b/examples/nrf/src/bin/ppi.rs new file mode 100644 index 000000000..717604b9e --- /dev/null +++ b/examples/nrf/src/bin/ppi.rs @@ -0,0 +1,87 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::future::pending; +use defmt::panic; +use embassy::executor::Spawner; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; +use embassy_nrf::ppi::Ppi; +use embassy_nrf::{interrupt, Peripherals}; +use gpiote::{OutputChannel, OutputChannelPolarity}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Starting!"); + + let button1 = InputChannel::new( + p.GPIOTE_CH0, + Input::new(p.P0_11, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let button2 = InputChannel::new( + p.GPIOTE_CH1, + Input::new(p.P0_12, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let button3 = InputChannel::new( + p.GPIOTE_CH2, + Input::new(p.P0_24, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let button4 = InputChannel::new( + p.GPIOTE_CH3, + Input::new(p.P0_25, Pull::Up), + InputChannelPolarity::HiToLo, + ); + + let led1 = OutputChannel::new( + p.GPIOTE_CH4, + Output::new(p.P0_13, Level::Low, OutputDrive::Standard), + OutputChannelPolarity::Toggle, + ); + + let led2 = OutputChannel::new( + p.GPIOTE_CH5, + Output::new(p.P0_14, Level::Low, OutputDrive::Standard), + OutputChannelPolarity::Toggle, + ); + + let mut ppi = Ppi::new(p.PPI_CH0); + ppi.set_event(button1.event_in()); + ppi.set_task(led1.task_out()); + ppi.enable(); + + let mut ppi = Ppi::new(p.PPI_CH1); + ppi.set_event(button2.event_in()); + ppi.set_task(led1.task_clr()); + ppi.enable(); + + let mut ppi = Ppi::new(p.PPI_CH2); + ppi.set_event(button3.event_in()); + ppi.set_task(led1.task_set()); + ppi.enable(); + + let mut ppi = Ppi::new(p.PPI_CH3); + ppi.set_event(button4.event_in()); + ppi.set_task(led1.task_out()); + ppi.set_fork_task(led2.task_out()); + ppi.enable(); + + info!("PPI setup!"); + info!("Press button 1 to toggle LED 1"); + info!("Press button 2 to turn on LED 1"); + info!("Press button 3 to turn off LED 1"); + info!("Press button 4 to toggle LEDs 1 and 2"); + + // Block forever so the above drivers don't get dropped + pending::<()>().await; +} diff --git a/examples/nrf/src/bin/pwm.rs b/examples/nrf/src/bin/pwm.rs new file mode 100644 index 000000000..d2874a29b --- /dev/null +++ b/examples/nrf/src/bin/pwm.rs @@ -0,0 +1,104 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use defmt::{panic, *}; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_nrf::pwm::{Prescaler, Pwm}; +use embassy_nrf::{interrupt, Peripherals}; + +// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='') +static DUTY: [u16; 1024] = [ + 8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440, + 9526, 9613, 9700, 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675, + 10766, 10857, 10948, 11039, 11131, 11223, 11315, 11407, 11500, 11592, 11685, 11779, 11872, + 11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723, 12818, 12914, 13010, 13106, + 13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266, 14364, + 14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632, + 15730, 15828, 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898, + 16995, 17091, 17188, 17284, 17380, 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145, + 18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896, 18989, 19082, 19174, 19266, 19358, + 19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346, 20434, 20521, + 20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620, + 21701, 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639, + 22714, 22788, 22861, 22934, 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564, + 23631, 23698, 23763, 23828, 23892, 23956, 24019, 24081, 24143, 24204, 24264, 24324, 24383, + 24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933, 24983, 25034, 25083, + 25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655, + 25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089, + 26117, 26144, 26170, 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381, + 26397, 26413, 26427, 26441, 26454, 26466, 26477, 26487, 26496, 26505, 26512, 26519, 26525, + 26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537, 26534, 26530, 26525, 26519, + 26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381, 26364, + 26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061, + 26032, 26002, 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615, + 25575, 25535, 25493, 25451, 25407, 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034, + 24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611, 24555, 24499, 24441, 24383, 24324, + 24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631, 23564, 23497, + 23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564, + 22488, 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538, + 21456, 21373, 21290, 21206, 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434, + 20346, 20258, 20169, 20081, 19991, 19902, 19812, 19722, 19631, 19540, 19449, 19358, 19266, + 19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334, 18239, 18145, 18050, + 17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801, + 16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535, + 15437, 15339, 15242, 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266, + 14169, 14072, 13975, 13878, 13781, 13684, 13587, 13491, 13394, 13298, 13202, 13106, 13010, + 12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154, 12060, 11966, 11872, 11779, + 11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675, 10585, + 10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269, + 9184, 9099, 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952, + 7873, 7794, 7716, 7638, 7561, 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738, + 6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172, 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636, + 5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947, 4888, 4828, 4769, 4711, 4653, + 4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892, 3841, 3791, + 3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047, + 3005, 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418, + 2382, 2347, 2312, 2278, 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896, + 1867, 1838, 1810, 1781, 1754, 1726, 1699, 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472, + 1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252, 1232, 1212, 1192, 1173, 1154, 1135, + 1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903, 888, 874, 860, + 846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637, + 627, 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485, + 479, 473, 467, 461, 455, 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390, + 386, 383, 379, 376, 373, 370, 367, 364, 361, 359, 356, 354, 351, 349, 347, 345, 343, 342, 340, + 338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328, 327, 327, 327, 327, 327, 328, + 328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347, 349, 351, + 354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415, + 419, 424, 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526, + 534, 541, 549, 557, 565, 574, 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699, + 710, 721, 733, 744, 756, 768, 781, 793, 806, 819, 833, 846, 860, 874, 888, 903, 918, 933, 948, + 964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154, 1173, 1192, 1212, 1232, + 1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570, 1595, + 1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048, + 2080, 2112, 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603, + 2641, 2680, 2719, 2758, 2798, 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267, + 3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642, 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047, + 4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653, 4711, 4769, 4828, 4888, 4947, + 5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834, 5901, 5968, + 6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105, + 7180, 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111, +]; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let pwm = Pwm::new(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); + pwm.set_prescaler(Prescaler::Div1); + info!("pwm initialized!"); + + let mut i = 0; + loop { + i += 1; + pwm.set_duty(0, DUTY[i % 1024]); + pwm.set_duty(1, DUTY[(i + 256) % 1024]); + pwm.set_duty(2, DUTY[(i + 512) % 1024]); + pwm.set_duty(3, DUTY[(i + 768) % 1024]); + Timer::after(Duration::from_millis(3)).await; + } +} diff --git a/examples/nrf/src/bin/qspi.rs b/examples/nrf/src/bin/qspi.rs new file mode 100644 index 000000000..6e49887a4 --- /dev/null +++ b/examples/nrf/src/bin/qspi.rs @@ -0,0 +1,84 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::{assert_eq, panic}; +use embassy::executor::Spawner; +use embassy::traits::flash::Flash; +use embassy_nrf::Peripherals; +use embassy_nrf::{interrupt, qspi}; +use example_common::*; + +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]); + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + // Config for the MX25R64 present in the nRF52840 DK + let mut config = qspi::Config::default(); + config.read_opcode = qspi::ReadOpcode::READ4IO; + config.write_opcode = qspi::WriteOpcode::PP4IO; + config.write_page_size = qspi::WritePageSize::_256BYTES; + + let irq = interrupt::take!(QSPI); + let mut q = qspi::Qspi::new( + p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config, + ) + .await; + + let mut id = [1; 3]; + q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); + info!("id: {}", id); + + // Read status register + let mut status = [4; 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!") +} diff --git a/examples/nrf/src/bin/qspi_lowpower.rs b/examples/nrf/src/bin/qspi_lowpower.rs new file mode 100644 index 000000000..ece3243b6 --- /dev/null +++ b/examples/nrf/src/bin/qspi_lowpower.rs @@ -0,0 +1,85 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use core::mem; +use defmt::panic; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy::traits::flash::Flash; +use embassy_nrf::Peripherals; +use embassy_nrf::{interrupt, qspi}; +use example_common::*; + +// Workaround for alignment requirements. +// Nicer API will probably come in the future. +#[repr(C, align(4))] +struct AlignedBuf([u8; 64]); + +#[embassy::main] +async fn main(_spawner: Spawner, mut p: Peripherals) { + let mut irq = interrupt::take!(QSPI); + + loop { + // Config for the MX25R64 present in the nRF52840 DK + let mut config = qspi::Config::default(); + config.read_opcode = qspi::ReadOpcode::READ4IO; + config.write_opcode = qspi::WriteOpcode::PP4IO; + config.write_page_size = qspi::WritePageSize::_256BYTES; + config.deep_power_down = Some(qspi::DeepPowerDownConfig { + enter_time: 3, // tDP = 30uS + exit_time: 3, // tRDP = 35uS + }); + + let mut q = qspi::Qspi::new( + &mut p.QSPI, + &mut irq, + &mut p.P0_19, + &mut p.P0_17, + &mut p.P0_20, + &mut p.P0_21, + &mut p.P0_22, + &mut p.P0_23, + config, + ) + .await; + + let mut id = [1; 3]; + q.custom_instruction(0x9F, &[], &mut id).await.unwrap(); + info!("id: {}", id); + + // Read status register + let mut status = [4; 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; 64]); + + info!("reading..."); + q.read(0, &mut buf.0).await.unwrap(); + info!("read: {=[u8]:x}", buf.0); + + // Drop the QSPI instance. This disables the peripehral and deconfigures the pins. + // This clears the borrow on the singletons, so they can now be used again. + mem::drop(q); + + // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. + // During this sleep, the nRF chip should only use ~3uA + Timer::after(Duration::from_secs(1)).await; + } +} diff --git a/examples/nrf/src/bin/raw_spawn.rs b/examples/nrf/src/bin/raw_spawn.rs new file mode 100644 index 000000000..78de7b100 --- /dev/null +++ b/examples/nrf/src/bin/raw_spawn.rs @@ -0,0 +1,65 @@ +#![no_std] +#![no_main] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use core::mem; +use cortex_m_rt::entry; +use defmt::panic; +use embassy::executor::raw::Task; +use embassy::executor::Executor; +use embassy::time::{Duration, Timer}; +use embassy::util::Forever; +use embassy_nrf::peripherals; +use embassy_nrf::{interrupt, rtc}; + +async fn run1() { + loop { + info!("BIG INFREQUENT TICK"); + Timer::after(Duration::from_ticks(64000)).await; + } +} + +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 = embassy_nrf::init(Default::default()); + + 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()); + executor.set_alarm(alarm); + + let run1_task = Task::new(); + let run2_task = Task::new(); + + // Safety: these variables do live forever if main never returns. + let run1_task = unsafe { make_static(&run1_task) }; + let run2_task = unsafe { make_static(&run2_task) }; + + executor.run(|spawner| { + unwrap!(spawner.spawn(run1_task.spawn(|| run1()))); + unwrap!(spawner.spawn(run2_task.spawn(|| run2()))); + }); +} + +unsafe fn make_static(t: &T) -> &'static T { + mem::transmute(t) +} diff --git a/examples/nrf/src/bin/spim.rs b/examples/nrf/src/bin/spim.rs new file mode 100644 index 000000000..c42cc6015 --- /dev/null +++ b/examples/nrf/src/bin/spim.rs @@ -0,0 +1,76 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy_nrf::gpio::{Level, Output, OutputDrive}; +use embassy_nrf::Peripherals; +use embassy_nrf::{interrupt, spim}; +use embassy_traits::spi::FullDuplex; +use embedded_hal::digital::v2::*; +use example_common::*; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("running!"); + + let mut config = spim::Config::default(); + config.frequency = spim::Frequency::M16; + + let irq = interrupt::take!(SPIM3); + let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config); + + let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard); + + // Example on how to talk to an ENC28J60 chip + + // softreset + cortex_m::asm::delay(10); + ncs.set_low().unwrap(); + cortex_m::asm::delay(5); + let tx = [0xFF]; + unwrap!(spim.read_write(&mut [], &tx).await); + cortex_m::asm::delay(10); + ncs.set_high().unwrap(); + + cortex_m::asm::delay(100000); + + let mut rx = [0; 2]; + + // read ESTAT + cortex_m::asm::delay(5000); + ncs.set_low().unwrap(); + cortex_m::asm::delay(5000); + let tx = [0b000_11101, 0]; + unwrap!(spim.read_write(&mut rx, &tx).await); + cortex_m::asm::delay(5000); + ncs.set_high().unwrap(); + info!("estat: {=[?]}", rx); + + // Switch to bank 3 + cortex_m::asm::delay(10); + ncs.set_low().unwrap(); + cortex_m::asm::delay(5); + let tx = [0b100_11111, 0b11]; + unwrap!(spim.read_write(&mut rx, &tx).await); + cortex_m::asm::delay(10); + ncs.set_high().unwrap(); + + // read EREVID + cortex_m::asm::delay(10); + ncs.set_low().unwrap(); + cortex_m::asm::delay(5); + let tx = [0b000_10010, 0]; + unwrap!(spim.read_write(&mut rx, &tx).await); + cortex_m::asm::delay(10); + ncs.set_high().unwrap(); + + info!("erevid: {=[?]}", rx); +} diff --git a/examples/nrf/src/bin/timer.rs b/examples/nrf/src/bin/timer.rs new file mode 100644 index 000000000..43f6d76ce --- /dev/null +++ b/examples/nrf/src/bin/timer.rs @@ -0,0 +1,37 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy_nrf::Peripherals; +use example_common::*; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; + +#[embassy::task] +async fn run1() { + loop { + info!("BIG INFREQUENT TICK"); + Timer::after(Duration::from_ticks(64000)).await; + } +} + +#[embassy::task] +async fn run2() { + loop { + info!("tick"); + Timer::after(Duration::from_ticks(13000)).await; + } +} + +#[embassy::main] +async fn main(spawner: Spawner, _p: Peripherals) { + unwrap!(spawner.spawn(run1())); + unwrap!(spawner.spawn(run2())); +} diff --git a/examples/nrf/src/bin/twim.rs b/examples/nrf/src/bin/twim.rs new file mode 100644 index 000000000..537cea160 --- /dev/null +++ b/examples/nrf/src/bin/twim.rs @@ -0,0 +1,35 @@ +//! Example on how to read a 24C/24LC i2c eeprom. +//! +//! Connect SDA to P0.03, SCL to P0.04 + +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::{panic, *}; +use embassy::executor::Spawner; +use embassy_nrf::twim::{self, Twim}; +use embassy_nrf::{interrupt, Peripherals}; + +const ADDRESS: u8 = 0x50; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Initializing TWI..."); + let config = twim::Config::default(); + let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); + let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config); + + info!("Reading..."); + + let mut buf = [0u8; 16]; + twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap(); + + info!("Read: {=[u8]:x}", buf); +} diff --git a/examples/nrf/src/bin/twim_lowpower.rs b/examples/nrf/src/bin/twim_lowpower.rs new file mode 100644 index 000000000..1cd66a18e --- /dev/null +++ b/examples/nrf/src/bin/twim_lowpower.rs @@ -0,0 +1,54 @@ +//! Example on how to read a 24C/24LC i2c eeprom with low power consumption. +//! The eeprom is read every 1 second, while ensuring lowest possible power while +//! sleeping between reads. +//! +//! Connect SDA to P0.03, SCL to P0.04 + +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use core::mem; + +use defmt::{panic, *}; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_nrf::twim::{self, Twim}; +use embassy_nrf::{interrupt, Peripherals}; + +const ADDRESS: u8 = 0x50; + +#[embassy::main] +async fn main(_spawner: Spawner, mut p: Peripherals) { + info!("Started!"); + let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0); + + loop { + info!("Initializing TWI..."); + let config = twim::Config::default(); + + // Create the TWIM instance with borrowed singletons, so they're not consumed. + let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config); + + info!("Reading..."); + + let mut buf = [0u8; 16]; + twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap(); + + info!("Read: {=[u8]:x}", buf); + + // Drop the TWIM instance. This disables the peripehral and deconfigures the pins. + // This clears the borrow on the singletons, so they can now be used again. + mem::drop(twi); + + // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do. + // During this sleep, the nRF chip should only use ~3uA + Timer::after(Duration::from_secs(1)).await; + } +} diff --git a/examples/nrf/src/bin/uart.rs b/examples/nrf/src/bin/uart.rs new file mode 100644 index 000000000..e65e2fe51 --- /dev/null +++ b/examples/nrf/src/bin/uart.rs @@ -0,0 +1,43 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use example_common::*; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy::traits::uart::{Read, Write}; +use embassy_nrf::gpio::NoPin; +use embassy_nrf::{interrupt, uarte, Peripherals}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; + + let irq = interrupt::take!(UARTE0_UART0); + let mut uart = + unsafe { uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config) }; + + info!("uarte initialized!"); + + // Message must be in SRAM + let mut buf = [0; 8]; + buf.copy_from_slice(b"Hello!\r\n"); + + unwrap!(uart.write(&buf).await); + info!("wrote hello in uart!"); + + loop { + info!("reading..."); + unwrap!(uart.read(&mut buf).await); + info!("writing..."); + unwrap!(uart.write(&buf).await); + } +} diff --git a/examples/nrf/src/bin/uart_idle.rs b/examples/nrf/src/bin/uart_idle.rs new file mode 100644 index 000000000..dc2c73433 --- /dev/null +++ b/examples/nrf/src/bin/uart_idle.rs @@ -0,0 +1,46 @@ +#![no_std] +#![no_main] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy_traits::uart::ReadUntilIdle; +use example_common::*; + +use defmt::panic; +use embassy::executor::Spawner; +use embassy::traits::uart::Write; +use embassy_nrf::gpio::NoPin; +use embassy_nrf::{interrupt, uarte, Peripherals}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut config = uarte::Config::default(); + config.parity = uarte::Parity::EXCLUDED; + config.baudrate = uarte::Baudrate::BAUD115200; + + let irq = interrupt::take!(UARTE0_UART0); + let mut uart = unsafe { + uarte::UarteWithIdle::new( + p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config, + ) + }; + + info!("uarte initialized!"); + + // Message must be in SRAM + let mut buf = [0; 8]; + buf.copy_from_slice(b"Hello!\r\n"); + + unwrap!(uart.write(&buf).await); + info!("wrote hello in uart!"); + + loop { + info!("reading..."); + let n = unwrap!(uart.read_until_idle(&mut buf).await); + info!("got {} bytes", n); + } +} diff --git a/examples/nrf/src/example_common.rs b/examples/nrf/src/example_common.rs new file mode 100644 index 000000000..54d633837 --- /dev/null +++ b/examples/nrf/src/example_common.rs @@ -0,0 +1,17 @@ +#![macro_use] + +use defmt_rtt as _; // global logger +use panic_probe as _; + +pub use defmt::*; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +defmt::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/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml new file mode 100644 index 000000000..1bbbe97da --- /dev/null +++ b/examples/rp/.cargo/config.toml @@ -0,0 +1,19 @@ +[unstable] +build-std = ["core"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +runner = "probe-run-rp --chip RP2040" + +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=-Tlink-rp.x", + "-C", "link-arg=-Tdefmt.x", + + # Code-size optimizations. + "-Z", "trap-unreachable=no", +] + +[build] +target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml new file mode 100644 index 000000000..71b48129f --- /dev/null +++ b/examples/rp/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-rp-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-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "defmt-trace"] } +rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" } +atomic-polyfill = { version = "0.1.1" } + +defmt = "0.2.0" +defmt-rtt = "0.2.0" + +cortex-m = { version = "0.7.1", features = ["inline-asm"] } +cortex-m-rt = "0.6.13" +embedded-hal = { version = "0.2.4" } +panic-probe = { version = "0.2.0", features = ["print-defmt"] } +futures = { version = "0.3.8", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } diff --git a/examples/rp/build.rs b/examples/rp/build.rs new file mode 100644 index 000000000..d534cc3df --- /dev/null +++ b/examples/rp/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/examples/rp/memory.x b/examples/rp/memory.x new file mode 100644 index 000000000..aba861aae --- /dev/null +++ b/examples/rp/memory.x @@ -0,0 +1,5 @@ +MEMORY { + BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 + FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 + RAM : ORIGIN = 0x20000000, LENGTH = 256K +} \ No newline at end of file diff --git a/examples/rp/src/bin/blinky.rs b/examples/rp/src/bin/blinky.rs new file mode 100644 index 000000000..e42999912 --- /dev/null +++ b/examples/rp/src/bin/blinky.rs @@ -0,0 +1,31 @@ +#![no_std] +#![no_main] +#![feature(asm)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use defmt::*; +use embassy::executor::Spawner; +use embassy_rp::{gpio, Peripherals}; +use embedded_hal::digital::v2::OutputPin; +use gpio::{Level, Output}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + info!("led on!"); + led.set_high().unwrap(); + cortex_m::asm::delay(1_000_000); + + info!("led off!"); + led.set_low().unwrap(); + cortex_m::asm::delay(1_000_000); + } +} diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs new file mode 100644 index 000000000..c4d942ff5 --- /dev/null +++ b/examples/rp/src/bin/button.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] +#![feature(asm)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy::executor::Spawner; +use embassy_rp::gpio::{Input, Level, Output, Pull}; +use embassy_rp::Peripherals; +use embedded_hal::digital::v2::{InputPin, OutputPin}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let button = Input::new(p.PIN_28, Pull::Up); + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + if button.is_high().unwrap() { + led.set_high().unwrap(); + } else { + led.set_low().unwrap(); + } + } +} diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs new file mode 100644 index 000000000..8b5f2a53b --- /dev/null +++ b/examples/rp/src/bin/uart.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] +#![feature(asm)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy::executor::Spawner; +use embassy_rp::{uart, Peripherals}; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + let config = uart::Config::default(); + let mut uart = uart::Uart::new(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config); + uart.send("Hello World!\r\n".as_bytes()); + + loop { + uart.send("hello there!\r\n".as_bytes()); + cortex_m::asm::delay(1_000_000); + } +} diff --git a/examples/rp/src/example_common.rs b/examples/rp/src/example_common.rs new file mode 100644 index 000000000..f7c4ef57a --- /dev/null +++ b/examples/rp/src/example_common.rs @@ -0,0 +1,12 @@ +use core::sync::atomic::{AtomicUsize, Ordering}; +use defmt_rtt as _; +use panic_probe as _; + +defmt::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/std/Cargo.toml b/examples/std/Cargo.toml new file mode 100644 index 000000000..04e89269d --- /dev/null +++ b/examples/std/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-std-examples" +version = "0.1.0" + +[dependencies] +embassy = { version = "0.1.0", path = "../../embassy", features = ["log"] } +embassy-std = { version = "0.1.0", path = "../../embassy-std" } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] } +smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="ec59aba5e10cf91df0c9253d9c2aca4dd143d2ff", default-features = false } + +async-io = "1.3.1" +env_logger = "0.8.2" +futures = { version = "0.3.8", default-features = false, features = ["async-await"] } +log = "0.4.11" +nix = "0.21.0" +libc = "0.2.81" +clap = { version = "3.0.0-beta.2", features = ["derive"] } +rand_core = { version = "0.6.0", features = ["std"] } +heapless = { version = "0.5.6", default-features = false } diff --git a/examples/std/src/bin/net.rs b/examples/std/src/bin/net.rs new file mode 100644 index 000000000..5a726e5d2 --- /dev/null +++ b/examples/std/src/bin/net.rs @@ -0,0 +1,103 @@ +#![feature(type_alias_impl_trait)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![allow(incomplete_features)] + +use clap::{AppSettings, Clap}; +use embassy::executor::Spawner; +use embassy::io::AsyncWriteExt; +use embassy::util::Forever; +use embassy_net::*; +use embassy_std::Executor; +use heapless::Vec; +use log::*; + +#[path = "../tuntap.rs"] +mod tuntap; + +use crate::tuntap::TunTapDevice; + +static DEVICE: Forever = Forever::new(); +static CONFIG: Forever = Forever::new(); + +#[derive(Clap)] +#[clap(version = "1.0")] +#[clap(setting = AppSettings::ColoredHelp)] +struct Opts { + /// TAP device name + #[clap(long, default_value = "tap0")] + tap: String, +} + +#[embassy::task] +async fn net_task() { + embassy_net::run().await +} + +#[embassy::task] +async fn main_task(spawner: Spawner) { + let opts: Opts = Opts::parse(); + + // Init network device + let device = TunTapDevice::new(&opts.tap).unwrap(); + + // Static IP configuration + let config = StaticConfigurator::new(Config { + address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), + dns_servers: Vec::new(), + gateway: Some(Ipv4Address::new(192, 168, 69, 1)), + }); + + // DHCP configruation + let config = DhcpConfigurator::new(); + + // Init network stack + embassy_net::init(DEVICE.put(device), CONFIG.put(config)); + + // Launch network task + spawner.spawn(net_task()).unwrap(); + + // Then we can use it! + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut socket = TcpSocket::new(&mut rx_buffer, &mut tx_buffer); + + socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); + + let remote_endpoint = (Ipv4Address::new(192, 168, 69, 74), 8000); + info!("connecting to {:?}...", remote_endpoint); + let r = socket.connect(remote_endpoint).await; + if let Err(e) = r { + warn!("connect error: {:?}", e); + return; + } + info!("connected!"); + loop { + let r = socket.write_all(b"Hello!\n").await; + if let Err(e) = r { + warn!("write error: {:?}", e); + return; + } + } +} + +#[no_mangle] +fn _embassy_rand(buf: &mut [u8]) { + use rand_core::{OsRng, RngCore}; + OsRng.fill_bytes(buf); +} + +static EXECUTOR: Forever = Forever::new(); + +fn main() { + env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .filter_module("async_io", log::LevelFilter::Info) + .format_timestamp_nanos() + .init(); + + let executor = EXECUTOR.put(Executor::new()); + executor.run(|spawner| { + spawner.spawn(main_task(spawner)).unwrap(); + }); +} diff --git a/examples/std/src/bin/serial.rs b/examples/std/src/bin/serial.rs new file mode 100644 index 000000000..1b22dc0de --- /dev/null +++ b/examples/std/src/bin/serial.rs @@ -0,0 +1,59 @@ +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../serial_port.rs"] +mod serial_port; + +use async_io::Async; +use embassy::io::AsyncBufReadExt; +use embassy::util::Forever; +use embassy_std::Executor; +use log::*; +use nix::sys::termios; + +use self::serial_port::SerialPort; + +#[embassy::task] +async fn run() { + // Open the serial port. + let baudrate = termios::BaudRate::B115200; + let port = SerialPort::new("/dev/ttyACM0", baudrate).unwrap(); + //let port = Spy::new(port); + + // Use async_io's reactor for async IO. + // This demonstrates how embassy's executor can drive futures from another IO library. + // Essentially, async_io::Async converts from AsRawFd+Read+Write to futures's AsyncRead+AsyncWrite + let port = Async::new(port).unwrap(); + + // This implements futures's AsyncBufRead based on futures's AsyncRead + let port = futures::io::BufReader::new(port); + + // We can then use FromStdIo to convert from futures's AsyncBufRead+AsyncWrite + // to embassy's AsyncBufRead+AsyncWrite + let mut port = embassy::io::FromStdIo::new(port); + + info!("Serial opened!"); + + loop { + let mut buf = [0u8; 256]; + let n = port.read(&mut buf).await.unwrap(); + info!("read {:?}", &buf[..n]); + } +} + +static EXECUTOR: Forever = Forever::new(); + +fn main() { + env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .filter_module("async_io", log::LevelFilter::Info) + .format_timestamp_nanos() + .init(); + + let executor = EXECUTOR.put(Executor::new()); + executor.run(|spawner| { + spawner.spawn(run()).unwrap(); + }); +} diff --git a/examples/std/src/bin/tick.rs b/examples/std/src/bin/tick.rs new file mode 100644 index 000000000..6f30edb34 --- /dev/null +++ b/examples/std/src/bin/tick.rs @@ -0,0 +1,31 @@ +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +use embassy::time::{Duration, Timer}; +use embassy::util::Forever; +use embassy_std::Executor; +use log::*; + +#[embassy::task] +async fn run() { + loop { + info!("tick"); + Timer::after(Duration::from_secs(1)).await; + } +} + +static EXECUTOR: Forever = Forever::new(); + +fn main() { + env_logger::builder() + .filter_level(log::LevelFilter::Debug) + .format_timestamp_nanos() + .init(); + + let executor = EXECUTOR.put(Executor::new()); + executor.run(|spawner| { + spawner.spawn(run()).unwrap(); + }); +} diff --git a/examples/std/src/serial_port.rs b/examples/std/src/serial_port.rs new file mode 100644 index 000000000..7ac1b1edb --- /dev/null +++ b/examples/std/src/serial_port.rs @@ -0,0 +1,71 @@ +use nix::fcntl::OFlag; +use nix::sys::termios; +use nix::Error; +use std::io; +use std::os::unix::io::{AsRawFd, RawFd}; + +pub struct SerialPort { + fd: RawFd, +} + +impl SerialPort { + pub fn new<'a, P: ?Sized + nix::NixPath>( + path: &P, + baudrate: termios::BaudRate, + ) -> io::Result { + let fd = nix::fcntl::open( + path, + OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK, + nix::sys::stat::Mode::empty(), + ) + .map_err(to_io_error)?; + + let mut cfg = termios::tcgetattr(fd).map_err(to_io_error)?; + cfg.input_flags = termios::InputFlags::empty(); + cfg.output_flags = termios::OutputFlags::empty(); + cfg.control_flags = termios::ControlFlags::empty(); + cfg.local_flags = termios::LocalFlags::empty(); + termios::cfmakeraw(&mut cfg); + cfg.input_flags |= termios::InputFlags::IGNBRK; + cfg.control_flags |= termios::ControlFlags::CREAD; + //cfg.control_flags |= termios::ControlFlags::CRTSCTS; + termios::cfsetospeed(&mut cfg, baudrate).map_err(to_io_error)?; + termios::cfsetispeed(&mut cfg, baudrate).map_err(to_io_error)?; + termios::cfsetspeed(&mut cfg, baudrate).map_err(to_io_error)?; + // Set VMIN = 1 to block until at least one character is received. + cfg.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1; + termios::tcsetattr(fd, termios::SetArg::TCSANOW, &cfg).map_err(to_io_error)?; + termios::tcflush(fd, termios::FlushArg::TCIOFLUSH).map_err(to_io_error)?; + + Ok(Self { fd }) + } +} + +impl AsRawFd for SerialPort { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +impl io::Read for SerialPort { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + nix::unistd::read(self.fd, buf).map_err(to_io_error) + } +} + +impl io::Write for SerialPort { + fn write(&mut self, buf: &[u8]) -> io::Result { + nix::unistd::write(self.fd, buf).map_err(to_io_error) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +fn to_io_error(e: Error) -> io::Error { + match e { + Error::Sys(errno) => errno.into(), + e => io::Error::new(io::ErrorKind::InvalidInput, e), + } +} diff --git a/examples/std/src/tuntap.rs b/examples/std/src/tuntap.rs new file mode 100644 index 000000000..dd453deb3 --- /dev/null +++ b/examples/std/src/tuntap.rs @@ -0,0 +1,225 @@ +use async_io::Async; +use libc; +use log::*; +use smoltcp::wire::EthernetFrame; +use std::io; +use std::io::{Read, Write}; +use std::os::unix::io::{AsRawFd, RawFd}; + +pub const SIOCGIFMTU: libc::c_ulong = 0x8921; +pub const SIOCGIFINDEX: libc::c_ulong = 0x8933; +pub const ETH_P_ALL: libc::c_short = 0x0003; +pub const TUNSETIFF: libc::c_ulong = 0x400454CA; +pub const IFF_TUN: libc::c_int = 0x0001; +pub const IFF_TAP: libc::c_int = 0x0002; +pub const IFF_NO_PI: libc::c_int = 0x1000; + +#[repr(C)] +#[derive(Debug)] +struct ifreq { + ifr_name: [libc::c_char; libc::IF_NAMESIZE], + ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */ +} + +fn ifreq_for(name: &str) -> ifreq { + let mut ifreq = ifreq { + ifr_name: [0; libc::IF_NAMESIZE], + ifr_data: 0, + }; + for (i, byte) in name.as_bytes().iter().enumerate() { + ifreq.ifr_name[i] = *byte as libc::c_char + } + ifreq +} + +fn ifreq_ioctl( + lower: libc::c_int, + ifreq: &mut ifreq, + cmd: libc::c_ulong, +) -> io::Result { + unsafe { + let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq); + if res == -1 { + return Err(io::Error::last_os_error()); + } + } + + Ok(ifreq.ifr_data) +} + +#[derive(Debug)] +pub struct TunTap { + fd: libc::c_int, + ifreq: ifreq, + mtu: usize, +} + +impl AsRawFd for TunTap { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +impl TunTap { + pub fn new(name: &str) -> io::Result { + unsafe { + let fd = libc::open( + "/dev/net/tun\0".as_ptr() as *const libc::c_char, + libc::O_RDWR | libc::O_NONBLOCK, + ); + if fd == -1 { + return Err(io::Error::last_os_error()); + } + + let mut ifreq = ifreq_for(name); + ifreq.ifr_data = IFF_TAP | IFF_NO_PI; + ifreq_ioctl(fd, &mut ifreq, TUNSETIFF)?; + + let socket = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP); + if socket == -1 { + return Err(io::Error::last_os_error()); + } + + let ip_mtu = ifreq_ioctl(socket, &mut ifreq, SIOCGIFMTU); + libc::close(socket); + let ip_mtu = ip_mtu? as usize; + + // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.) + // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it. + let mtu = ip_mtu + EthernetFrame::<&[u8]>::header_len(); + + Ok(TunTap { fd, mtu, ifreq }) + } + } +} + +impl Drop for TunTap { + fn drop(&mut self) { + unsafe { + libc::close(self.fd); + } + } +} + +impl io::Read for TunTap { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) }; + if len == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(len as usize) + } + } +} + +impl io::Write for TunTap { + fn write(&mut self, buf: &[u8]) -> io::Result { + let len = unsafe { libc::write(self.fd, buf.as_ptr() as *mut libc::c_void, buf.len()) }; + if len == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(len as usize) + } + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub struct TunTapDevice { + device: Async, + waker: Option, +} + +impl TunTapDevice { + pub fn new(name: &str) -> io::Result { + Ok(Self { + device: Async::new(TunTap::new(name)?)?, + waker: None, + }) + } +} + +use core::task::Waker; +use embassy_net::{DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf}; +use std::task::Context; + +impl crate::Device for TunTapDevice { + fn is_transmit_ready(&mut self) -> bool { + true + } + + fn transmit(&mut self, pkt: PacketBuf) { + // todo handle WouldBlock + match self.device.get_mut().write(&pkt) { + Ok(_) => {} + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + info!("transmit WouldBlock"); + } + Err(e) => panic!("transmit error: {:?}", e), + } + } + + fn receive(&mut self) -> Option { + let mut pkt = PacketBox::new(Packet::new()).unwrap(); + loop { + match self.device.get_mut().read(&mut pkt[..]) { + Ok(n) => { + return Some(pkt.slice(0..n)); + } + Err(e) if e.kind() == io::ErrorKind::WouldBlock => { + let ready = if let Some(w) = self.waker.as_ref() { + let mut cx = Context::from_waker(w); + let ready = self.device.poll_readable(&mut cx).is_ready(); + ready + } else { + false + }; + if !ready { + return None; + } + } + Err(e) => panic!("read error: {:?}", e), + } + } + } + + fn register_waker(&mut self, w: &Waker) { + match self.waker { + // Optimization: If both the old and new Wakers wake the same task, we can simply + // keep the old waker, skipping the clone. (In most executor implementations, + // cloning a waker is somewhat expensive, comparable to cloning an Arc). + Some(ref w2) if (w2.will_wake(w)) => {} + _ => { + // clone the new waker and store it + if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) { + // We had a waker registered for another task. Wake it, so the other task can + // reregister itself if it's still interested. + // + // If two tasks are waiting on the same thing concurrently, this will cause them + // to wake each other in a loop fighting over this WakerRegistration. This wastes + // CPU but things will still work. + // + // If the user wants to have two tasks waiting on the same thing they should use + // a more appropriate primitive that can store multiple wakers. + old_waker.wake() + } + } + } + } + + fn capabilities(&mut self) -> DeviceCapabilities { + let mut caps = DeviceCapabilities::default(); + caps.max_transmission_unit = self.device.get_ref().mtu; + caps + } + + fn link_state(&mut self) -> LinkState { + LinkState::Up + } + + fn ethernet_address(&mut self) -> [u8; 6] { + [0x02, 0x03, 0x04, 0x05, 0x06, 0x07] + } +} diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml new file mode 100644 index 000000000..8704a9ba5 --- /dev/null +++ b/examples/stm32f4/.cargo/config.toml @@ -0,0 +1,21 @@ +[unstable] +build-std = ["core"] + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips` +runner = "probe-run --chip STM32F429ZITx" + +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", + + # Code-size optimizations. + "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", +] + +[build] +target = "thumbv7em-none-eabi" diff --git a/examples/stm32f4/Cargo.toml b/examples/stm32f4/Cargo.toml new file mode 100644 index 000000000..c5c8d9ae6 --- /dev/null +++ b/examples/stm32f4/Cargo.toml @@ -0,0 +1,35 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-stm32f4-examples" +version = "0.1.0" +resolver = "2" + +[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-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f429zi"] } +embassy-extras = {version = "0.1.0", path = "../../embassy-extras" } +stm32f4 = { version = "0.13", features = ["stm32f429"] } + +defmt = "0.2.0" +defmt-rtt = "0.2.0" + +cortex-m = "0.7.1" +cortex-m-rt = "0.6.14" +embedded-hal = { version = "0.2.4" } +panic-probe = { version = "0.2.0", features= ["print-defmt"] } +futures = { version = "0.3.8", default-features = false, features = ["async-await"] } +rtt-target = { version = "0.3", features = ["cortex-m"] } +heapless = "0.7" \ No newline at end of file diff --git a/examples/stm32f4/build.rs b/examples/stm32f4/build.rs new file mode 100644 index 000000000..d534cc3df --- /dev/null +++ b/examples/stm32f4/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/examples/stm32f4/memory.x b/examples/stm32f4/memory.x new file mode 100644 index 000000000..f21e32572 --- /dev/null +++ b/examples/stm32f4/memory.x @@ -0,0 +1,7 @@ +MEMORY +{ + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + /* These values correspond to the STM32F429ZI */ + FLASH : ORIGIN = 0x08000000, LENGTH = 2048K + RAM : ORIGIN = 0x20000000, LENGTH = 192K +} diff --git a/examples/stm32f4/src/bin/blinky.rs b/examples/stm32f4/src/bin/blinky.rs new file mode 100644 index 000000000..7590764d8 --- /dev/null +++ b/examples/stm32f4/src/bin/blinky.rs @@ -0,0 +1,54 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy_stm32::gpio::{Level, Output}; +use embedded_hal::digital::v2::OutputPin; +use example_common::*; + +use cortex_m_rt::entry; +use stm32f4::stm32f429 as pac; + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w + }); + + let p = embassy_stm32::init(Default::default()); + + let mut led = Output::new(p.PB7, Level::High); + + loop { + info!("high"); + led.set_high().unwrap(); + cortex_m::asm::delay(10_000_000); + + info!("low"); + led.set_low().unwrap(); + cortex_m::asm::delay(10_000_000); + } +} diff --git a/examples/stm32f4/src/bin/button.rs b/examples/stm32f4/src/bin/button.rs new file mode 100644 index 000000000..1ee99f527 --- /dev/null +++ b/examples/stm32f4/src/bin/button.rs @@ -0,0 +1,59 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy_stm32::gpio::{Input, Level, Output, Pull}; +use embedded_hal::digital::v2::{InputPin, OutputPin}; +use example_common::*; + +use cortex_m_rt::entry; +use stm32f4::stm32f429 as pac; + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w + }); + + let p = embassy_stm32::init(Default::default()); + + let button = Input::new(p.PC13, Pull::Down); + let mut led1 = Output::new(p.PB0, Level::High); + let _led2 = Output::new(p.PB7, Level::High); + let mut led3 = Output::new(p.PB14, Level::High); + + loop { + if button.is_high().unwrap() { + info!("high"); + led1.set_high().unwrap(); + led3.set_low().unwrap(); + } else { + info!("low"); + led1.set_low().unwrap(); + led3.set_high().unwrap(); + } + } +} diff --git a/examples/stm32f4/src/bin/button_exti.rs b/examples/stm32f4/src/bin/button_exti.rs new file mode 100644 index 000000000..8fc889dad --- /dev/null +++ b/examples/stm32f4/src/bin/button_exti.rs @@ -0,0 +1,83 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::{Input, Pull}; +use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge}; +use example_common::*; + +use cortex_m_rt::entry; +use stm32f4::stm32f429 as pac; + +#[embassy::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let button = Input::new(p.PC13, Pull::Down); + let mut button = ExtiInput::new(button, p.EXTI13); + + info!("Press the USER button..."); + + loop { + button.wait_for_rising_edge().await; + info!("Pressed!"); + button.wait_for_falling_edge().await; + info!("Released!"); + } +} + +struct ZeroClock; + +impl Clock for ZeroClock { + fn now(&self) -> u64 { + 0 + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w + }); + pp.RCC.apb2enr.modify(|_, w| { + w.syscfgen().enabled(); + w + }); + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32f4/src/bin/spi.rs b/examples/stm32f4/src/bin/spi.rs new file mode 100644 index 000000000..af0d57412 --- /dev/null +++ b/examples/stm32f4/src/bin/spi.rs @@ -0,0 +1,71 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; + +use embassy_stm32::gpio::{Level, Output}; +use embedded_hal::digital::v2::OutputPin; +use example_common::*; + +use cortex_m_rt::entry; +use embassy_stm32::spi::{Config, Spi}; +use embassy_stm32::time::Hertz; +use embedded_hal::blocking::spi::Transfer; +use stm32f4::stm32f429 as pac; + +#[entry] +fn main() -> ! { + info!("Hello World, dude!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().set_bit()); + + pp.RCC.apb1enr.modify(|_, w| { + w.spi3en().enabled(); + w + }); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w + }); + + let p = embassy_stm32::init(Default::default()); + + let mut spi = Spi::new( + Hertz(16_000_000), + p.SPI3, + p.PC10, + p.PC12, + p.PC11, + Hertz(1_000_000), + Config::default(), + ); + + let mut cs = Output::new(p.PE0, Level::High); + + loop { + let mut buf = [0x0A; 4]; + unwrap!(cs.set_low()); + unwrap!(spi.transfer(&mut buf)); + unwrap!(cs.set_high()); + info!("xfer {=[u8]:x}", buf); + } +} diff --git a/examples/stm32f4/src/bin/usart.rs b/examples/stm32f4/src/bin/usart.rs new file mode 100644 index 000000000..f7b66f86b --- /dev/null +++ b/examples/stm32f4/src/bin/usart.rs @@ -0,0 +1,86 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use cortex_m::prelude::_embedded_hal_blocking_serial_Write; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::usart::{Config, Uart}; +use example_common::*; + +use cortex_m_rt::entry; +use stm32f4::stm32f429 as pac; + +#[embassy::task] +async fn main_task() { + let p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000); + + usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap(); + info!("wrote Hello, starting echo"); + + let mut buf = [0u8; 1]; + loop { + usart.read(&mut buf).unwrap(); + usart.bwrite_all(&buf).unwrap(); + } +} + +struct ZeroClock; + +impl Clock for ZeroClock { + fn now(&self) -> u64 { + 0 + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w + }); + pp.RCC.apb2enr.modify(|_, w| { + w.syscfgen().enabled(); + w + }); + pp.RCC.apb1enr.modify(|_, w| { + w.usart3en().enabled(); + w + }); + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32f4/src/bin/usart_dma.rs b/examples/stm32f4/src/bin/usart_dma.rs new file mode 100644 index 000000000..fae05b607 --- /dev/null +++ b/examples/stm32f4/src/bin/usart_dma.rs @@ -0,0 +1,90 @@ +#![no_std] +#![no_main] +#![feature(trait_alias)] +#![feature(min_type_alias_impl_trait)] +#![feature(impl_trait_in_bindings)] +#![feature(type_alias_impl_trait)] +#![allow(incomplete_features)] + +#[path = "../example_common.rs"] +mod example_common; +use core::fmt::Write; +use cortex_m_rt::entry; +use embassy::executor::Executor; +use embassy::time::Clock; +use embassy::util::Forever; +use embassy_stm32::usart::{Config, Uart}; +use example_common::*; +use heapless::String; +use stm32f4::stm32f429 as pac; + +#[embassy::task] +async fn main_task() { + let mut p = embassy_stm32::init(Default::default()); + + let config = Config::default(); + let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000); + + for n in 0u32.. { + let mut s: String<128> = String::new(); + core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap(); + + usart + .write_dma(&mut p.DMA1_CH3, s.as_bytes()) + .await + .unwrap(); + info!("wrote DMA"); + } +} + +struct ZeroClock; + +impl Clock for ZeroClock { + fn now(&self) -> u64 { + 0 + } +} + +static EXECUTOR: Forever = Forever::new(); + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let pp = pac::Peripherals::take().unwrap(); + + pp.DBGMCU.cr.modify(|_, w| { + w.dbg_sleep().set_bit(); + w.dbg_standby().set_bit(); + w.dbg_stop().set_bit() + }); + pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled()); + + pp.RCC.ahb1enr.modify(|_, w| { + w.gpioaen().enabled(); + w.gpioben().enabled(); + w.gpiocen().enabled(); + w.gpioden().enabled(); + w.gpioeen().enabled(); + w.gpiofen().enabled(); + w.dma1en().enabled(); + w.dma2en().enabled(); + w + }); + pp.RCC.apb2enr.modify(|_, w| { + w.syscfgen().enabled(); + w + }); + pp.RCC.apb1enr.modify(|_, w| { + w.usart3en().enabled(); + w + }); + + unsafe { embassy::time::set_clock(&ZeroClock) }; + + let executor = EXECUTOR.put(Executor::new()); + + executor.run(|spawner| { + unwrap!(spawner.spawn(main_task())); + }) +} diff --git a/examples/stm32f4/src/example_common.rs b/examples/stm32f4/src/example_common.rs new file mode 100644 index 000000000..54d633837 --- /dev/null +++ b/examples/stm32f4/src/example_common.rs @@ -0,0 +1,17 @@ +#![macro_use] + +use defmt_rtt as _; // global logger +use panic_probe as _; + +pub use defmt::*; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +defmt::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 + } +} -- cgit