Move examples to a subdirectory

This commit is contained in:
Dario Nieuwenhuis
2021-06-02 01:30:07 +02:00
parent a0c5f7137f
commit dff03ecfc7
51 changed files with 374 additions and 36 deletions

View File

@ -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"

31
examples/nrf/Cargo.toml Normal file
View File

@ -0,0 +1,31 @@
[package]
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
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"] }

31
examples/nrf/build.rs Normal file
View File

@ -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");
}

7
examples/nrf/memory.x Normal file
View File

@ -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
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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()));
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new();
static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new();
static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR_LOW: Forever<Executor> = 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()));
});
}

View File

@ -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;
}

104
examples/nrf/src/bin/pwm.rs Normal file
View File

@ -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;
}
}

View File

@ -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!")
}

View File

@ -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;
}
}

View File

@ -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<rtc::RTC<peripherals::RTC1>> = Forever::new();
static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
static EXECUTOR: Forever<Executor> = 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: &T) -> &'static T {
mem::transmute(t)
}

View File

@ -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);
}

View File

@ -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()));
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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+

32
examples/rp/Cargo.toml Normal file
View File

@ -0,0 +1,32 @@
[package]
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
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"] }

31
examples/rp/build.rs Normal file
View File

@ -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");
}

5
examples/rp/memory.x Normal file
View File

@ -0,0 +1,5 @@
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

21
examples/std/Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
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 }

103
examples/std/src/bin/net.rs Normal file
View File

@ -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<TunTapDevice> = Forever::new();
static CONFIG: Forever<DhcpConfigurator> = 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<Executor> = 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();
});
}

View File

@ -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<Executor> = 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();
});
}

View File

@ -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<Executor> = 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();
});
}

View File

@ -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<Self> {
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<usize> {
nix::unistd::read(self.fd, buf).map_err(to_io_error)
}
}
impl io::Write for SerialPort {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
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),
}
}

225
examples/std/src/tuntap.rs Normal file
View File

@ -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<libc::c_int> {
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<TunTap> {
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<usize> {
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<usize> {
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<TunTap>,
waker: Option<Waker>,
}
impl TunTapDevice {
pub fn new(name: &str) -> io::Result<TunTapDevice> {
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<PacketBuf> {
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]
}
}

View File

@ -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"

View File

@ -0,0 +1,35 @@
[package]
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
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"

31
examples/stm32f4/build.rs Normal file
View File

@ -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");
}

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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<Executor> = 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()));
})
}

View File

@ -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);
}
}

View File

@ -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<Executor> = 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()));
})
}

View File

@ -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<Executor> = 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()));
})
}

View File

@ -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
}
}