aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2021-06-02 01:30:07 +0200
committerDario Nieuwenhuis <[email protected]>2021-06-02 01:32:19 +0200
commitdff03ecfc74d6af716637888338ebfa99ab7a027 (patch)
treec06bf2b0a2e6657c3427c956dbd27a4e45211aaa /examples
parenta0c5f7137fe0c45b8db0aad2a116aea91e6a93f7 (diff)
Move examples to a subdirectory
Diffstat (limited to 'examples')
-rw-r--r--examples/nrf/.cargo/config.toml21
-rw-r--r--examples/nrf/Cargo.toml31
-rw-r--r--examples/nrf/build.rs31
-rw-r--r--examples/nrf/memory.x7
-rw-r--r--examples/nrf/src/bin/blinky.rs28
-rw-r--r--examples/nrf/src/bin/buffered_uart.rs68
-rw-r--r--examples/nrf/src/bin/executor_fairness_test.rs47
-rw-r--r--examples/nrf/src/bin/gpiote_channel.rs72
-rw-r--r--examples/nrf/src/bin/gpiote_port.rs43
-rw-r--r--examples/nrf/src/bin/multiprio.rs162
-rw-r--r--examples/nrf/src/bin/ppi.rs87
-rw-r--r--examples/nrf/src/bin/pwm.rs104
-rw-r--r--examples/nrf/src/bin/qspi.rs84
-rw-r--r--examples/nrf/src/bin/qspi_lowpower.rs85
-rw-r--r--examples/nrf/src/bin/raw_spawn.rs65
-rw-r--r--examples/nrf/src/bin/spim.rs76
-rw-r--r--examples/nrf/src/bin/timer.rs37
-rw-r--r--examples/nrf/src/bin/twim.rs35
-rw-r--r--examples/nrf/src/bin/twim_lowpower.rs54
-rw-r--r--examples/nrf/src/bin/uart.rs43
-rw-r--r--examples/nrf/src/bin/uart_idle.rs46
-rw-r--r--examples/nrf/src/example_common.rs17
-rw-r--r--examples/rp/.cargo/config.toml19
-rw-r--r--examples/rp/Cargo.toml32
-rw-r--r--examples/rp/build.rs31
-rw-r--r--examples/rp/memory.x5
-rw-r--r--examples/rp/src/bin/blinky.rs31
-rw-r--r--examples/rp/src/bin/button.rs29
-rw-r--r--examples/rp/src/bin/uart.rs25
-rw-r--r--examples/rp/src/example_common.rs12
-rw-r--r--examples/std/Cargo.toml21
-rw-r--r--examples/std/src/bin/net.rs103
-rw-r--r--examples/std/src/bin/serial.rs59
-rw-r--r--examples/std/src/bin/tick.rs31
-rw-r--r--examples/std/src/serial_port.rs71
-rw-r--r--examples/std/src/tuntap.rs225
-rw-r--r--examples/stm32f4/.cargo/config.toml21
-rw-r--r--examples/stm32f4/Cargo.toml35
-rw-r--r--examples/stm32f4/build.rs31
-rw-r--r--examples/stm32f4/memory.x7
-rw-r--r--examples/stm32f4/src/bin/blinky.rs54
-rw-r--r--examples/stm32f4/src/bin/button.rs59
-rw-r--r--examples/stm32f4/src/bin/button_exti.rs83
-rw-r--r--examples/stm32f4/src/bin/spi.rs71
-rw-r--r--examples/stm32f4/src/bin/usart.rs86
-rw-r--r--examples/stm32f4/src/bin/usart_dma.rs90
-rw-r--r--examples/stm32f4/src/example_common.rs17
47 files changed, 2491 insertions, 0 deletions
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 @@
1[unstable]
2build-std = ["core"]
3
4[target.'cfg(all(target_arch = "arm", target_os = "none"))']
5# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
6runner = "probe-run --chip nRF52840_xxAA"
7
8rustflags = [
9 # LLD (shipped with the Rust toolchain) is used as the default linker
10 "-C", "link-arg=--nmagic",
11 "-C", "link-arg=-Tlink.x",
12 "-C", "link-arg=-Tdefmt.x",
13
14 # Code-size optimizations.
15 "-Z", "trap-unreachable=no",
16 "-C", "inline-threshold=5",
17 "-C", "no-vectorize-loops",
18]
19
20[build]
21target = "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 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-nrf-examples"
5version = "0.1.0"
6
7[features]
8default = [
9 "defmt-default",
10]
11defmt-default = []
12defmt-trace = []
13defmt-debug = []
14defmt-info = []
15defmt-warn = []
16defmt-error = []
17
18
19[dependencies]
20embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] }
21embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] }
22embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "defmt-trace", "nrf52840"] }
23
24defmt = "0.2.0"
25defmt-rtt = "0.2.0"
26
27cortex-m = { version = "0.7.1", features = ["inline-asm"] }
28cortex-m-rt = "0.6.13"
29embedded-hal = { version = "0.2.4" }
30panic-probe = { version = "0.2.0", features = ["print-defmt"] }
31futures = { 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 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31}
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 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
5 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
6 RAM : ORIGIN = 0x20000000, LENGTH = 256K
7}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use defmt::panic;
12use embassy::executor::Spawner;
13use embassy::time::{Duration, Timer};
14use embassy_nrf::gpio::{Level, Output, OutputDrive};
15use embassy_nrf::Peripherals;
16use embedded_hal::digital::v2::OutputPin;
17
18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) {
20 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
21
22 loop {
23 led.set_high().unwrap();
24 Timer::after(Duration::from_millis(300)).await;
25 led.set_low().unwrap();
26 Timer::after(Duration::from_millis(300)).await;
27 }
28}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use defmt::panic;
12use embassy::executor::Spawner;
13use embassy::io::{AsyncBufReadExt, AsyncWriteExt};
14use embassy_nrf::gpio::NoPin;
15use embassy_nrf::{buffered_uarte::BufferedUarte, interrupt, uarte, Peripherals};
16use example_common::*;
17use futures::pin_mut;
18
19#[embassy::main]
20async fn main(_spawner: Spawner, p: Peripherals) {
21 let mut config = uarte::Config::default();
22 config.parity = uarte::Parity::EXCLUDED;
23 config.baudrate = uarte::Baudrate::BAUD115200;
24
25 let mut tx_buffer = [0u8; 4096];
26 let mut rx_buffer = [0u8; 4096];
27
28 let irq = interrupt::take!(UARTE0_UART0);
29 let u = unsafe {
30 BufferedUarte::new(
31 p.UARTE0,
32 p.TIMER0,
33 p.PPI_CH0,
34 p.PPI_CH1,
35 irq,
36 p.P0_08,
37 p.P0_06,
38 NoPin,
39 NoPin,
40 config,
41 &mut rx_buffer,
42 &mut tx_buffer,
43 )
44 };
45 pin_mut!(u);
46
47 info!("uarte initialized!");
48
49 unwrap!(u.write_all(b"Hello!\r\n").await);
50 info!("wrote hello in uart!");
51
52 // Simple demo, reading 8-char chunks and echoing them back reversed.
53 loop {
54 info!("reading...");
55 let mut buf = [0u8; 8];
56 unwrap!(u.read_exact(&mut buf).await);
57 info!("read done, got {}", buf);
58
59 // Reverse buf
60 for i in 0..4 {
61 buf.swap(i, 7 - i);
62 }
63
64 info!("writing...");
65 unwrap!(u.write_all(&buf).await);
66 info!("write done");
67 }
68}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use example_common::*;
11
12use core::task::Poll;
13use defmt::panic;
14use embassy::executor::Spawner;
15use embassy::time::{Duration, Instant, Timer};
16use embassy_nrf::{interrupt, Peripherals};
17
18#[embassy::task]
19async fn run1() {
20 loop {
21 info!("DING DONG");
22 Timer::after(Duration::from_ticks(16000)).await;
23 }
24}
25
26#[embassy::task]
27async fn run2() {
28 loop {
29 Timer::at(Instant::from_ticks(0)).await;
30 }
31}
32
33#[embassy::task]
34async fn run3() {
35 futures::future::poll_fn(|cx| {
36 cx.waker().wake_by_ref();
37 Poll::<()>::Pending
38 })
39 .await;
40}
41
42#[embassy::main]
43async fn main(spawner: Spawner, _p: Peripherals) {
44 unwrap!(spawner.spawn(run1()));
45 unwrap!(spawner.spawn(run2()));
46 unwrap!(spawner.spawn(run3()));
47}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use example_common::*;
11
12use defmt::panic;
13use embassy::executor::Spawner;
14use embassy_nrf::gpio::{Input, Pull};
15use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
16use embassy_nrf::{interrupt, Peripherals};
17
18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) {
20 info!("Starting!");
21
22 let ch1 = InputChannel::new(
23 p.GPIOTE_CH0,
24 Input::new(p.P0_11, Pull::Up),
25 InputChannelPolarity::HiToLo,
26 );
27 let ch2 = InputChannel::new(
28 p.GPIOTE_CH1,
29 Input::new(p.P0_12, Pull::Up),
30 InputChannelPolarity::LoToHi,
31 );
32 let ch3 = InputChannel::new(
33 p.GPIOTE_CH2,
34 Input::new(p.P0_24, Pull::Up),
35 InputChannelPolarity::Toggle,
36 );
37 let ch4 = InputChannel::new(
38 p.GPIOTE_CH3,
39 Input::new(p.P0_25, Pull::Up),
40 InputChannelPolarity::Toggle,
41 );
42
43 let button1 = async {
44 loop {
45 ch1.wait().await;
46 info!("Button 1 pressed")
47 }
48 };
49
50 let button2 = async {
51 loop {
52 ch2.wait().await;
53 info!("Button 2 released")
54 }
55 };
56
57 let button3 = async {
58 loop {
59 ch3.wait().await;
60 info!("Button 3 toggled")
61 }
62 };
63
64 let button4 = async {
65 loop {
66 ch4.wait().await;
67 info!("Button 4 toggled")
68 }
69 };
70
71 futures::join!(button1, button2, button3, button4);
72}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use defmt::panic;
12use embassy::executor::Spawner;
13use embassy::traits::gpio::{WaitForHigh, WaitForLow};
14use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull};
15use embassy_nrf::gpiote::PortInput;
16use embassy_nrf::interrupt;
17use embassy_nrf::Peripherals;
18use example_common::*;
19
20#[embassy::task(pool_size = 4)]
21async fn button_task(n: usize, mut pin: PortInput<'static, AnyPin>) {
22 loop {
23 pin.wait_for_low().await;
24 info!("Button {:?} pressed!", n);
25 pin.wait_for_high().await;
26 info!("Button {:?} released!", n);
27 }
28}
29
30#[embassy::main]
31async fn main(spawner: Spawner, p: Peripherals) {
32 info!("Starting!");
33
34 let btn1 = PortInput::new(Input::new(p.P0_11.degrade(), Pull::Up));
35 let btn2 = PortInput::new(Input::new(p.P0_12.degrade(), Pull::Up));
36 let btn3 = PortInput::new(Input::new(p.P0_24.degrade(), Pull::Up));
37 let btn4 = PortInput::new(Input::new(p.P0_25.degrade(), Pull::Up));
38
39 spawner.spawn(button_task(1, btn1)).unwrap();
40 spawner.spawn(button_task(2, btn2)).unwrap();
41 spawner.spawn(button_task(3, btn3)).unwrap();
42 spawner.spawn(button_task(4, btn4)).unwrap();
43}
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 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58#![feature(min_type_alias_impl_trait)]
59#![feature(impl_trait_in_bindings)]
60#![feature(type_alias_impl_trait)]
61#![allow(incomplete_features)]
62
63#[path = "../example_common.rs"]
64mod example_common;
65use example_common::*;
66
67use cortex_m_rt::entry;
68use defmt::panic;
69use embassy::executor::{Executor, InterruptExecutor};
70use embassy::interrupt::InterruptExt;
71use embassy::time::{Duration, Instant, Timer};
72use embassy::util::Forever;
73use embassy_nrf::{interrupt, peripherals, rtc};
74
75#[embassy::task]
76async fn run_high() {
77 loop {
78 info!(" [high] tick!");
79 Timer::after(Duration::from_ticks(27374)).await;
80 }
81}
82
83#[embassy::task]
84async fn run_med() {
85 loop {
86 let start = Instant::now();
87 info!(" [med] Starting long computation");
88
89 // Spin-wait to simulate a long CPU computation
90 cortex_m::asm::delay(32_000_000); // ~1 second
91
92 let end = Instant::now();
93 let ms = end.duration_since(start).as_ticks() / 33;
94 info!(" [med] done in {} ms", ms);
95
96 Timer::after(Duration::from_ticks(23421)).await;
97 }
98}
99
100#[embassy::task]
101async fn run_low() {
102 loop {
103 let start = Instant::now();
104 info!("[low] Starting long computation");
105
106 // Spin-wait to simulate a long CPU computation
107 cortex_m::asm::delay(64_000_000); // ~2 seconds
108
109 let end = Instant::now();
110 let ms = end.duration_since(start).as_ticks() / 33;
111 info!("[low] done in {} ms", ms);
112
113 Timer::after(Duration::from_ticks(32983)).await;
114 }
115}
116
117static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
118static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
119static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new();
120static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
121static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new();
122static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
123static EXECUTOR_LOW: Forever<Executor> = Forever::new();
124
125#[entry]
126fn main() -> ! {
127 info!("Hello World!");
128
129 let p = embassy_nrf::init(Default::default());
130
131 let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
132 rtc.start();
133 unsafe { embassy::time::set_clock(rtc) };
134
135 // High-priority executor: SWI1_EGU1, priority level 6
136 let irq = interrupt::take!(SWI1_EGU1);
137 irq.set_priority(interrupt::Priority::P6);
138 let alarm = ALARM_HIGH.put(rtc.alarm2());
139 let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
140 executor.set_alarm(alarm);
141 executor.start(|spawner| {
142 unwrap!(spawner.spawn(run_high()));
143 });
144
145 // Medium-priority executor: SWI0_EGU0, priority level 7
146 let irq = interrupt::take!(SWI0_EGU0);
147 irq.set_priority(interrupt::Priority::P7);
148 let alarm = ALARM_MED.put(rtc.alarm1());
149 let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
150 executor.set_alarm(alarm);
151 executor.start(|spawner| {
152 unwrap!(spawner.spawn(run_med()));
153 });
154
155 // Low priority executor: runs in thread mode, using WFE/SEV
156 let alarm = ALARM_LOW.put(rtc.alarm0());
157 let executor = EXECUTOR_LOW.put(Executor::new());
158 executor.set_alarm(alarm);
159 executor.run(|spawner| {
160 unwrap!(spawner.spawn(run_low()));
161 });
162}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use example_common::*;
11
12use core::future::pending;
13use defmt::panic;
14use embassy::executor::Spawner;
15use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
16use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
17use embassy_nrf::ppi::Ppi;
18use embassy_nrf::{interrupt, Peripherals};
19use gpiote::{OutputChannel, OutputChannelPolarity};
20
21#[embassy::main]
22async fn main(_spawner: Spawner, p: Peripherals) {
23 info!("Starting!");
24
25 let button1 = InputChannel::new(
26 p.GPIOTE_CH0,
27 Input::new(p.P0_11, Pull::Up),
28 InputChannelPolarity::HiToLo,
29 );
30 let button2 = InputChannel::new(
31 p.GPIOTE_CH1,
32 Input::new(p.P0_12, Pull::Up),
33 InputChannelPolarity::HiToLo,
34 );
35 let button3 = InputChannel::new(
36 p.GPIOTE_CH2,
37 Input::new(p.P0_24, Pull::Up),
38 InputChannelPolarity::HiToLo,
39 );
40 let button4 = InputChannel::new(
41 p.GPIOTE_CH3,
42 Input::new(p.P0_25, Pull::Up),
43 InputChannelPolarity::HiToLo,
44 );
45
46 let led1 = OutputChannel::new(
47 p.GPIOTE_CH4,
48 Output::new(p.P0_13, Level::Low, OutputDrive::Standard),
49 OutputChannelPolarity::Toggle,
50 );
51
52 let led2 = OutputChannel::new(
53 p.GPIOTE_CH5,
54 Output::new(p.P0_14, Level::Low, OutputDrive::Standard),
55 OutputChannelPolarity::Toggle,
56 );
57
58 let mut ppi = Ppi::new(p.PPI_CH0);
59 ppi.set_event(button1.event_in());
60 ppi.set_task(led1.task_out());
61 ppi.enable();
62
63 let mut ppi = Ppi::new(p.PPI_CH1);
64 ppi.set_event(button2.event_in());
65 ppi.set_task(led1.task_clr());
66 ppi.enable();
67
68 let mut ppi = Ppi::new(p.PPI_CH2);
69 ppi.set_event(button3.event_in());
70 ppi.set_task(led1.task_set());
71 ppi.enable();
72
73 let mut ppi = Ppi::new(p.PPI_CH3);
74 ppi.set_event(button4.event_in());
75 ppi.set_task(led1.task_out());
76 ppi.set_fork_task(led2.task_out());
77 ppi.enable();
78
79 info!("PPI setup!");
80 info!("Press button 1 to toggle LED 1");
81 info!("Press button 2 to turn on LED 1");
82 info!("Press button 3 to turn off LED 1");
83 info!("Press button 4 to toggle LEDs 1 and 2");
84
85 // Block forever so the above drivers don't get dropped
86 pending::<()>().await;
87}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use defmt::{panic, *};
11use embassy::executor::Spawner;
12use embassy::time::{Duration, Timer};
13use embassy_nrf::pwm::{Prescaler, Pwm};
14use embassy_nrf::{interrupt, Peripherals};
15
16// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='')
17static DUTY: [u16; 1024] = [
18 8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440,
19 9526, 9613, 9700, 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675,
20 10766, 10857, 10948, 11039, 11131, 11223, 11315, 11407, 11500, 11592, 11685, 11779, 11872,
21 11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723, 12818, 12914, 13010, 13106,
22 13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266, 14364,
23 14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632,
24 15730, 15828, 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898,
25 16995, 17091, 17188, 17284, 17380, 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145,
26 18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896, 18989, 19082, 19174, 19266, 19358,
27 19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346, 20434, 20521,
28 20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620,
29 21701, 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639,
30 22714, 22788, 22861, 22934, 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564,
31 23631, 23698, 23763, 23828, 23892, 23956, 24019, 24081, 24143, 24204, 24264, 24324, 24383,
32 24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933, 24983, 25034, 25083,
33 25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655,
34 25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089,
35 26117, 26144, 26170, 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381,
36 26397, 26413, 26427, 26441, 26454, 26466, 26477, 26487, 26496, 26505, 26512, 26519, 26525,
37 26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537, 26534, 26530, 26525, 26519,
38 26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381, 26364,
39 26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061,
40 26032, 26002, 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615,
41 25575, 25535, 25493, 25451, 25407, 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034,
42 24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611, 24555, 24499, 24441, 24383, 24324,
43 24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631, 23564, 23497,
44 23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564,
45 22488, 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538,
46 21456, 21373, 21290, 21206, 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434,
47 20346, 20258, 20169, 20081, 19991, 19902, 19812, 19722, 19631, 19540, 19449, 19358, 19266,
48 19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334, 18239, 18145, 18050,
49 17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801,
50 16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535,
51 15437, 15339, 15242, 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266,
52 14169, 14072, 13975, 13878, 13781, 13684, 13587, 13491, 13394, 13298, 13202, 13106, 13010,
53 12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154, 12060, 11966, 11872, 11779,
54 11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675, 10585,
55 10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269,
56 9184, 9099, 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952,
57 7873, 7794, 7716, 7638, 7561, 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738,
58 6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172, 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636,
59 5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947, 4888, 4828, 4769, 4711, 4653,
60 4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892, 3841, 3791,
61 3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047,
62 3005, 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418,
63 2382, 2347, 2312, 2278, 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896,
64 1867, 1838, 1810, 1781, 1754, 1726, 1699, 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472,
65 1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252, 1232, 1212, 1192, 1173, 1154, 1135,
66 1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903, 888, 874, 860,
67 846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637,
68 627, 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485,
69 479, 473, 467, 461, 455, 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390,
70 386, 383, 379, 376, 373, 370, 367, 364, 361, 359, 356, 354, 351, 349, 347, 345, 343, 342, 340,
71 338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328, 327, 327, 327, 327, 327, 328,
72 328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347, 349, 351,
73 354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415,
74 419, 424, 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526,
75 534, 541, 549, 557, 565, 574, 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699,
76 710, 721, 733, 744, 756, 768, 781, 793, 806, 819, 833, 846, 860, 874, 888, 903, 918, 933, 948,
77 964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154, 1173, 1192, 1212, 1232,
78 1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570, 1595,
79 1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048,
80 2080, 2112, 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603,
81 2641, 2680, 2719, 2758, 2798, 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267,
82 3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642, 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047,
83 4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653, 4711, 4769, 4828, 4888, 4947,
84 5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834, 5901, 5968,
85 6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105,
86 7180, 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111,
87];
88
89#[embassy::main]
90async fn main(_spawner: Spawner, p: Peripherals) {
91 let pwm = Pwm::new(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15);
92 pwm.set_prescaler(Prescaler::Div1);
93 info!("pwm initialized!");
94
95 let mut i = 0;
96 loop {
97 i += 1;
98 pwm.set_duty(0, DUTY[i % 1024]);
99 pwm.set_duty(1, DUTY[(i + 256) % 1024]);
100 pwm.set_duty(2, DUTY[(i + 512) % 1024]);
101 pwm.set_duty(3, DUTY[(i + 768) % 1024]);
102 Timer::after(Duration::from_millis(3)).await;
103 }
104}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use defmt::{assert_eq, panic};
12use embassy::executor::Spawner;
13use embassy::traits::flash::Flash;
14use embassy_nrf::Peripherals;
15use embassy_nrf::{interrupt, qspi};
16use example_common::*;
17
18const PAGE_SIZE: usize = 4096;
19
20// Workaround for alignment requirements.
21// Nicer API will probably come in the future.
22#[repr(C, align(4))]
23struct AlignedBuf([u8; 4096]);
24
25#[embassy::main]
26async fn main(_spawner: Spawner, p: Peripherals) {
27 // Config for the MX25R64 present in the nRF52840 DK
28 let mut config = qspi::Config::default();
29 config.read_opcode = qspi::ReadOpcode::READ4IO;
30 config.write_opcode = qspi::WriteOpcode::PP4IO;
31 config.write_page_size = qspi::WritePageSize::_256BYTES;
32
33 let irq = interrupt::take!(QSPI);
34 let mut q = qspi::Qspi::new(
35 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
36 )
37 .await;
38
39 let mut id = [1; 3];
40 q.custom_instruction(0x9F, &[], &mut id).await.unwrap();
41 info!("id: {}", id);
42
43 // Read status register
44 let mut status = [4; 1];
45 q.custom_instruction(0x05, &[], &mut status).await.unwrap();
46
47 info!("status: {:?}", status[0]);
48
49 if status[0] & 0x40 == 0 {
50 status[0] |= 0x40;
51
52 q.custom_instruction(0x01, &status, &mut []).await.unwrap();
53
54 info!("enabled quad in status");
55 }
56
57 let mut buf = AlignedBuf([0u8; PAGE_SIZE]);
58
59 let pattern = |a: u32| (a ^ (a >> 8) ^ (a >> 16) ^ (a >> 24)) as u8;
60
61 for i in 0..8 {
62 info!("page {:?}: erasing... ", i);
63 q.erase(i * PAGE_SIZE).await.unwrap();
64
65 for j in 0..PAGE_SIZE {
66 buf.0[j] = pattern((j + i * PAGE_SIZE) as u32);
67 }
68
69 info!("programming...");
70 q.write(i * PAGE_SIZE, &buf.0).await.unwrap();
71 }
72
73 for i in 0..8 {
74 info!("page {:?}: reading... ", i);
75 q.read(i * PAGE_SIZE, &mut buf.0).await.unwrap();
76
77 info!("verifying...");
78 for j in 0..PAGE_SIZE {
79 assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32));
80 }
81 }
82
83 info!("done!")
84}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use core::mem;
12use defmt::panic;
13use embassy::executor::Spawner;
14use embassy::time::{Duration, Timer};
15use embassy::traits::flash::Flash;
16use embassy_nrf::Peripherals;
17use embassy_nrf::{interrupt, qspi};
18use example_common::*;
19
20// Workaround for alignment requirements.
21// Nicer API will probably come in the future.
22#[repr(C, align(4))]
23struct AlignedBuf([u8; 64]);
24
25#[embassy::main]
26async fn main(_spawner: Spawner, mut p: Peripherals) {
27 let mut irq = interrupt::take!(QSPI);
28
29 loop {
30 // Config for the MX25R64 present in the nRF52840 DK
31 let mut config = qspi::Config::default();
32 config.read_opcode = qspi::ReadOpcode::READ4IO;
33 config.write_opcode = qspi::WriteOpcode::PP4IO;
34 config.write_page_size = qspi::WritePageSize::_256BYTES;
35 config.deep_power_down = Some(qspi::DeepPowerDownConfig {
36 enter_time: 3, // tDP = 30uS
37 exit_time: 3, // tRDP = 35uS
38 });
39
40 let mut q = qspi::Qspi::new(
41 &mut p.QSPI,
42 &mut irq,
43 &mut p.P0_19,
44 &mut p.P0_17,
45 &mut p.P0_20,
46 &mut p.P0_21,
47 &mut p.P0_22,
48 &mut p.P0_23,
49 config,
50 )
51 .await;
52
53 let mut id = [1; 3];
54 q.custom_instruction(0x9F, &[], &mut id).await.unwrap();
55 info!("id: {}", id);
56
57 // Read status register
58 let mut status = [4; 1];
59 q.custom_instruction(0x05, &[], &mut status).await.unwrap();
60
61 info!("status: {:?}", status[0]);
62
63 if status[0] & 0x40 == 0 {
64 status[0] |= 0x40;
65
66 q.custom_instruction(0x01, &status, &mut []).await.unwrap();
67
68 info!("enabled quad in status");
69 }
70
71 let mut buf = AlignedBuf([0u8; 64]);
72
73 info!("reading...");
74 q.read(0, &mut buf.0).await.unwrap();
75 info!("read: {=[u8]:x}", buf.0);
76
77 // Drop the QSPI instance. This disables the peripehral and deconfigures the pins.
78 // This clears the borrow on the singletons, so they can now be used again.
79 mem::drop(q);
80
81 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
82 // During this sleep, the nRF chip should only use ~3uA
83 Timer::after(Duration::from_secs(1)).await;
84 }
85}
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 @@
1#![no_std]
2#![no_main]
3
4#[path = "../example_common.rs"]
5mod example_common;
6use example_common::*;
7
8use core::mem;
9use cortex_m_rt::entry;
10use defmt::panic;
11use embassy::executor::raw::Task;
12use embassy::executor::Executor;
13use embassy::time::{Duration, Timer};
14use embassy::util::Forever;
15use embassy_nrf::peripherals;
16use embassy_nrf::{interrupt, rtc};
17
18async fn run1() {
19 loop {
20 info!("BIG INFREQUENT TICK");
21 Timer::after(Duration::from_ticks(64000)).await;
22 }
23}
24
25async fn run2() {
26 loop {
27 info!("tick");
28 Timer::after(Duration::from_ticks(13000)).await;
29 }
30}
31
32static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
33static ALARM: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
34static EXECUTOR: Forever<Executor> = Forever::new();
35
36#[entry]
37fn main() -> ! {
38 info!("Hello World!");
39
40 let p = embassy_nrf::init(Default::default());
41
42 let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
43 rtc.start();
44 unsafe { embassy::time::set_clock(rtc) };
45
46 let alarm = ALARM.put(rtc.alarm0());
47 let executor = EXECUTOR.put(Executor::new());
48 executor.set_alarm(alarm);
49
50 let run1_task = Task::new();
51 let run2_task = Task::new();
52
53 // Safety: these variables do live forever if main never returns.
54 let run1_task = unsafe { make_static(&run1_task) };
55 let run2_task = unsafe { make_static(&run2_task) };
56
57 executor.run(|spawner| {
58 unwrap!(spawner.spawn(run1_task.spawn(|| run1())));
59 unwrap!(spawner.spawn(run2_task.spawn(|| run2())));
60 });
61}
62
63unsafe fn make_static<T>(t: &T) -> &'static T {
64 mem::transmute(t)
65}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use defmt::panic;
12use embassy::executor::Spawner;
13use embassy_nrf::gpio::{Level, Output, OutputDrive};
14use embassy_nrf::Peripherals;
15use embassy_nrf::{interrupt, spim};
16use embassy_traits::spi::FullDuplex;
17use embedded_hal::digital::v2::*;
18use example_common::*;
19
20#[embassy::main]
21async fn main(_spawner: Spawner, p: Peripherals) {
22 info!("running!");
23
24 let mut config = spim::Config::default();
25 config.frequency = spim::Frequency::M16;
26
27 let irq = interrupt::take!(SPIM3);
28 let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
29
30 let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
31
32 // Example on how to talk to an ENC28J60 chip
33
34 // softreset
35 cortex_m::asm::delay(10);
36 ncs.set_low().unwrap();
37 cortex_m::asm::delay(5);
38 let tx = [0xFF];
39 unwrap!(spim.read_write(&mut [], &tx).await);
40 cortex_m::asm::delay(10);
41 ncs.set_high().unwrap();
42
43 cortex_m::asm::delay(100000);
44
45 let mut rx = [0; 2];
46
47 // read ESTAT
48 cortex_m::asm::delay(5000);
49 ncs.set_low().unwrap();
50 cortex_m::asm::delay(5000);
51 let tx = [0b000_11101, 0];
52 unwrap!(spim.read_write(&mut rx, &tx).await);
53 cortex_m::asm::delay(5000);
54 ncs.set_high().unwrap();
55 info!("estat: {=[?]}", rx);
56
57 // Switch to bank 3
58 cortex_m::asm::delay(10);
59 ncs.set_low().unwrap();
60 cortex_m::asm::delay(5);
61 let tx = [0b100_11111, 0b11];
62 unwrap!(spim.read_write(&mut rx, &tx).await);
63 cortex_m::asm::delay(10);
64 ncs.set_high().unwrap();
65
66 // read EREVID
67 cortex_m::asm::delay(10);
68 ncs.set_low().unwrap();
69 cortex_m::asm::delay(5);
70 let tx = [0b000_10010, 0];
71 unwrap!(spim.read_write(&mut rx, &tx).await);
72 cortex_m::asm::delay(10);
73 ncs.set_high().unwrap();
74
75 info!("erevid: {=[?]}", rx);
76}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use embassy_nrf::Peripherals;
11use example_common::*;
12
13use defmt::panic;
14use embassy::executor::Spawner;
15use embassy::time::{Duration, Timer};
16
17#[embassy::task]
18async fn run1() {
19 loop {
20 info!("BIG INFREQUENT TICK");
21 Timer::after(Duration::from_ticks(64000)).await;
22 }
23}
24
25#[embassy::task]
26async fn run2() {
27 loop {
28 info!("tick");
29 Timer::after(Duration::from_ticks(13000)).await;
30 }
31}
32
33#[embassy::main]
34async fn main(spawner: Spawner, _p: Peripherals) {
35 unwrap!(spawner.spawn(run1()));
36 unwrap!(spawner.spawn(run2()));
37}
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 @@
1//! Example on how to read a 24C/24LC i2c eeprom.
2//!
3//! Connect SDA to P0.03, SCL to P0.04
4
5#![no_std]
6#![no_main]
7#![feature(min_type_alias_impl_trait)]
8#![feature(impl_trait_in_bindings)]
9#![feature(type_alias_impl_trait)]
10#![allow(incomplete_features)]
11
12#[path = "../example_common.rs"]
13mod example_common;
14
15use defmt::{panic, *};
16use embassy::executor::Spawner;
17use embassy_nrf::twim::{self, Twim};
18use embassy_nrf::{interrupt, Peripherals};
19
20const ADDRESS: u8 = 0x50;
21
22#[embassy::main]
23async fn main(_spawner: Spawner, p: Peripherals) {
24 info!("Initializing TWI...");
25 let config = twim::Config::default();
26 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
27 let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
28
29 info!("Reading...");
30
31 let mut buf = [0u8; 16];
32 twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap();
33
34 info!("Read: {=[u8]:x}", buf);
35}
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 @@
1//! Example on how to read a 24C/24LC i2c eeprom with low power consumption.
2//! The eeprom is read every 1 second, while ensuring lowest possible power while
3//! sleeping between reads.
4//!
5//! Connect SDA to P0.03, SCL to P0.04
6
7#![no_std]
8#![no_main]
9#![feature(min_type_alias_impl_trait)]
10#![feature(impl_trait_in_bindings)]
11#![feature(type_alias_impl_trait)]
12#![allow(incomplete_features)]
13
14#[path = "../example_common.rs"]
15mod example_common;
16
17use core::mem;
18
19use defmt::{panic, *};
20use embassy::executor::Spawner;
21use embassy::time::{Duration, Timer};
22use embassy_nrf::twim::{self, Twim};
23use embassy_nrf::{interrupt, Peripherals};
24
25const ADDRESS: u8 = 0x50;
26
27#[embassy::main]
28async fn main(_spawner: Spawner, mut p: Peripherals) {
29 info!("Started!");
30 let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
31
32 loop {
33 info!("Initializing TWI...");
34 let config = twim::Config::default();
35
36 // Create the TWIM instance with borrowed singletons, so they're not consumed.
37 let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
38
39 info!("Reading...");
40
41 let mut buf = [0u8; 16];
42 twi.write_then_read(ADDRESS, &mut [0x00], &mut buf).unwrap();
43
44 info!("Read: {=[u8]:x}", buf);
45
46 // Drop the TWIM instance. This disables the peripehral and deconfigures the pins.
47 // This clears the borrow on the singletons, so they can now be used again.
48 mem::drop(twi);
49
50 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
51 // During this sleep, the nRF chip should only use ~3uA
52 Timer::after(Duration::from_secs(1)).await;
53 }
54}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use example_common::*;
11
12use defmt::panic;
13use embassy::executor::Spawner;
14use embassy::traits::uart::{Read, Write};
15use embassy_nrf::gpio::NoPin;
16use embassy_nrf::{interrupt, uarte, Peripherals};
17
18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) {
20 let mut config = uarte::Config::default();
21 config.parity = uarte::Parity::EXCLUDED;
22 config.baudrate = uarte::Baudrate::BAUD115200;
23
24 let irq = interrupt::take!(UARTE0_UART0);
25 let mut uart =
26 unsafe { uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, NoPin, NoPin, config) };
27
28 info!("uarte initialized!");
29
30 // Message must be in SRAM
31 let mut buf = [0; 8];
32 buf.copy_from_slice(b"Hello!\r\n");
33
34 unwrap!(uart.write(&buf).await);
35 info!("wrote hello in uart!");
36
37 loop {
38 info!("reading...");
39 unwrap!(uart.read(&mut buf).await);
40 info!("writing...");
41 unwrap!(uart.write(&buf).await);
42 }
43}
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 @@
1#![no_std]
2#![no_main]
3#![feature(min_type_alias_impl_trait)]
4#![feature(impl_trait_in_bindings)]
5#![feature(type_alias_impl_trait)]
6#![allow(incomplete_features)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10use embassy_traits::uart::ReadUntilIdle;
11use example_common::*;
12
13use defmt::panic;
14use embassy::executor::Spawner;
15use embassy::traits::uart::Write;
16use embassy_nrf::gpio::NoPin;
17use embassy_nrf::{interrupt, uarte, Peripherals};
18
19#[embassy::main]
20async fn main(_spawner: Spawner, p: Peripherals) {
21 let mut config = uarte::Config::default();
22 config.parity = uarte::Parity::EXCLUDED;
23 config.baudrate = uarte::Baudrate::BAUD115200;
24
25 let irq = interrupt::take!(UARTE0_UART0);
26 let mut uart = unsafe {
27 uarte::UarteWithIdle::new(
28 p.UARTE0, p.TIMER0, p.PPI_CH0, p.PPI_CH1, irq, p.P0_08, p.P0_06, NoPin, NoPin, config,
29 )
30 };
31
32 info!("uarte initialized!");
33
34 // Message must be in SRAM
35 let mut buf = [0; 8];
36 buf.copy_from_slice(b"Hello!\r\n");
37
38 unwrap!(uart.write(&buf).await);
39 info!("wrote hello in uart!");
40
41 loop {
42 info!("reading...");
43 let n = unwrap!(uart.read_until_idle(&mut buf).await);
44 info!("got {} bytes", n);
45 }
46}
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 @@
1#![macro_use]
2
3use defmt_rtt as _; // global logger
4use panic_probe as _;
5
6pub use defmt::*;
7
8use core::sync::atomic::{AtomicUsize, Ordering};
9
10defmt::timestamp! {"{=u64}", {
11 static COUNT: AtomicUsize = AtomicUsize::new(0);
12 // NOTE(no-CAS) `timestamps` runs with interrupts disabled
13 let n = COUNT.load(Ordering::Relaxed);
14 COUNT.store(n + 1, Ordering::Relaxed);
15 n as u64
16 }
17}
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 @@
1[unstable]
2build-std = ["core"]
3
4[target.'cfg(all(target_arch = "arm", target_os = "none"))']
5runner = "probe-run-rp --chip RP2040"
6
7rustflags = [
8 # LLD (shipped with the Rust toolchain) is used as the default linker
9 "-C", "link-arg=--nmagic",
10 "-C", "link-arg=-Tlink.x",
11 "-C", "link-arg=-Tlink-rp.x",
12 "-C", "link-arg=-Tdefmt.x",
13
14 # Code-size optimizations.
15 "-Z", "trap-unreachable=no",
16]
17
18[build]
19target = "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 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-rp-examples"
5version = "0.1.0"
6
7[features]
8default = [
9 "defmt-default",
10]
11defmt-default = []
12defmt-trace = []
13defmt-debug = []
14defmt-info = []
15defmt-warn = []
16defmt-error = []
17
18
19[dependencies]
20embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] }
21embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "defmt-trace"] }
22rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" }
23atomic-polyfill = { version = "0.1.1" }
24
25defmt = "0.2.0"
26defmt-rtt = "0.2.0"
27
28cortex-m = { version = "0.7.1", features = ["inline-asm"] }
29cortex-m-rt = "0.6.13"
30embedded-hal = { version = "0.2.4" }
31panic-probe = { version = "0.2.0", features = ["print-defmt"] }
32futures = { 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 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31}
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 @@
1MEMORY {
2 BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3 FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
4 RAM : ORIGIN = 0x20000000, LENGTH = 256K
5} \ 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 @@
1#![no_std]
2#![no_main]
3#![feature(asm)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11
12use defmt::*;
13use embassy::executor::Spawner;
14use embassy_rp::{gpio, Peripherals};
15use embedded_hal::digital::v2::OutputPin;
16use gpio::{Level, Output};
17
18#[embassy::main]
19async fn main(_spawner: Spawner, p: Peripherals) {
20 let mut led = Output::new(p.PIN_25, Level::Low);
21
22 loop {
23 info!("led on!");
24 led.set_high().unwrap();
25 cortex_m::asm::delay(1_000_000);
26
27 info!("led off!");
28 led.set_low().unwrap();
29 cortex_m::asm::delay(1_000_000);
30 }
31}
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 @@
1#![no_std]
2#![no_main]
3#![feature(asm)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11
12use embassy::executor::Spawner;
13use embassy_rp::gpio::{Input, Level, Output, Pull};
14use embassy_rp::Peripherals;
15use embedded_hal::digital::v2::{InputPin, OutputPin};
16
17#[embassy::main]
18async fn main(_spawner: Spawner, p: Peripherals) {
19 let button = Input::new(p.PIN_28, Pull::Up);
20 let mut led = Output::new(p.PIN_25, Level::Low);
21
22 loop {
23 if button.is_high().unwrap() {
24 led.set_high().unwrap();
25 } else {
26 led.set_low().unwrap();
27 }
28 }
29}
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 @@
1#![no_std]
2#![no_main]
3#![feature(asm)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11
12use embassy::executor::Spawner;
13use embassy_rp::{uart, Peripherals};
14
15#[embassy::main]
16async fn main(_spawner: Spawner, p: Peripherals) {
17 let config = uart::Config::default();
18 let mut uart = uart::Uart::new(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config);
19 uart.send("Hello World!\r\n".as_bytes());
20
21 loop {
22 uart.send("hello there!\r\n".as_bytes());
23 cortex_m::asm::delay(1_000_000);
24 }
25}
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 @@
1use core::sync::atomic::{AtomicUsize, Ordering};
2use defmt_rtt as _;
3use panic_probe as _;
4
5defmt::timestamp! {"{=u64}", {
6 static COUNT: AtomicUsize = AtomicUsize::new(0);
7 // NOTE(no-CAS) `timestamps` runs with interrupts disabled
8 let n = COUNT.load(Ordering::Relaxed);
9 COUNT.store(n + 1, Ordering::Relaxed);
10 n as u64
11}
12}
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 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-std-examples"
5version = "0.1.0"
6
7[dependencies]
8embassy = { version = "0.1.0", path = "../../embassy", features = ["log"] }
9embassy-std = { version = "0.1.0", path = "../../embassy-std" }
10embassy-net = { version = "0.1.0", path = "../../embassy-net", features=["std", "log", "medium-ethernet", "tcp", "dhcpv4"] }
11smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev="ec59aba5e10cf91df0c9253d9c2aca4dd143d2ff", default-features = false }
12
13async-io = "1.3.1"
14env_logger = "0.8.2"
15futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
16log = "0.4.11"
17nix = "0.21.0"
18libc = "0.2.81"
19clap = { version = "3.0.0-beta.2", features = ["derive"] }
20rand_core = { version = "0.6.0", features = ["std"] }
21heapless = { 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 @@
1#![feature(type_alias_impl_trait)]
2#![feature(min_type_alias_impl_trait)]
3#![feature(impl_trait_in_bindings)]
4#![allow(incomplete_features)]
5
6use clap::{AppSettings, Clap};
7use embassy::executor::Spawner;
8use embassy::io::AsyncWriteExt;
9use embassy::util::Forever;
10use embassy_net::*;
11use embassy_std::Executor;
12use heapless::Vec;
13use log::*;
14
15#[path = "../tuntap.rs"]
16mod tuntap;
17
18use crate::tuntap::TunTapDevice;
19
20static DEVICE: Forever<TunTapDevice> = Forever::new();
21static CONFIG: Forever<DhcpConfigurator> = Forever::new();
22
23#[derive(Clap)]
24#[clap(version = "1.0")]
25#[clap(setting = AppSettings::ColoredHelp)]
26struct Opts {
27 /// TAP device name
28 #[clap(long, default_value = "tap0")]
29 tap: String,
30}
31
32#[embassy::task]
33async fn net_task() {
34 embassy_net::run().await
35}
36
37#[embassy::task]
38async fn main_task(spawner: Spawner) {
39 let opts: Opts = Opts::parse();
40
41 // Init network device
42 let device = TunTapDevice::new(&opts.tap).unwrap();
43
44 // Static IP configuration
45 let config = StaticConfigurator::new(Config {
46 address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
47 dns_servers: Vec::new(),
48 gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
49 });
50
51 // DHCP configruation
52 let config = DhcpConfigurator::new();
53
54 // Init network stack
55 embassy_net::init(DEVICE.put(device), CONFIG.put(config));
56
57 // Launch network task
58 spawner.spawn(net_task()).unwrap();
59
60 // Then we can use it!
61 let mut rx_buffer = [0; 4096];
62 let mut tx_buffer = [0; 4096];
63 let mut socket = TcpSocket::new(&mut rx_buffer, &mut tx_buffer);
64
65 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
66
67 let remote_endpoint = (Ipv4Address::new(192, 168, 69, 74), 8000);
68 info!("connecting to {:?}...", remote_endpoint);
69 let r = socket.connect(remote_endpoint).await;
70 if let Err(e) = r {
71 warn!("connect error: {:?}", e);
72 return;
73 }
74 info!("connected!");
75 loop {
76 let r = socket.write_all(b"Hello!\n").await;
77 if let Err(e) = r {
78 warn!("write error: {:?}", e);
79 return;
80 }
81 }
82}
83
84#[no_mangle]
85fn _embassy_rand(buf: &mut [u8]) {
86 use rand_core::{OsRng, RngCore};
87 OsRng.fill_bytes(buf);
88}
89
90static EXECUTOR: Forever<Executor> = Forever::new();
91
92fn main() {
93 env_logger::builder()
94 .filter_level(log::LevelFilter::Debug)
95 .filter_module("async_io", log::LevelFilter::Info)
96 .format_timestamp_nanos()
97 .init();
98
99 let executor = EXECUTOR.put(Executor::new());
100 executor.run(|spawner| {
101 spawner.spawn(main_task(spawner)).unwrap();
102 });
103}
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 @@
1#![feature(min_type_alias_impl_trait)]
2#![feature(impl_trait_in_bindings)]
3#![feature(type_alias_impl_trait)]
4#![allow(incomplete_features)]
5
6#[path = "../serial_port.rs"]
7mod serial_port;
8
9use async_io::Async;
10use embassy::io::AsyncBufReadExt;
11use embassy::util::Forever;
12use embassy_std::Executor;
13use log::*;
14use nix::sys::termios;
15
16use self::serial_port::SerialPort;
17
18#[embassy::task]
19async fn run() {
20 // Open the serial port.
21 let baudrate = termios::BaudRate::B115200;
22 let port = SerialPort::new("/dev/ttyACM0", baudrate).unwrap();
23 //let port = Spy::new(port);
24
25 // Use async_io's reactor for async IO.
26 // This demonstrates how embassy's executor can drive futures from another IO library.
27 // Essentially, async_io::Async converts from AsRawFd+Read+Write to futures's AsyncRead+AsyncWrite
28 let port = Async::new(port).unwrap();
29
30 // This implements futures's AsyncBufRead based on futures's AsyncRead
31 let port = futures::io::BufReader::new(port);
32
33 // We can then use FromStdIo to convert from futures's AsyncBufRead+AsyncWrite
34 // to embassy's AsyncBufRead+AsyncWrite
35 let mut port = embassy::io::FromStdIo::new(port);
36
37 info!("Serial opened!");
38
39 loop {
40 let mut buf = [0u8; 256];
41 let n = port.read(&mut buf).await.unwrap();
42 info!("read {:?}", &buf[..n]);
43 }
44}
45
46static EXECUTOR: Forever<Executor> = Forever::new();
47
48fn main() {
49 env_logger::builder()
50 .filter_level(log::LevelFilter::Debug)
51 .filter_module("async_io", log::LevelFilter::Info)
52 .format_timestamp_nanos()
53 .init();
54
55 let executor = EXECUTOR.put(Executor::new());
56 executor.run(|spawner| {
57 spawner.spawn(run()).unwrap();
58 });
59}
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 @@
1#![feature(min_type_alias_impl_trait)]
2#![feature(impl_trait_in_bindings)]
3#![feature(type_alias_impl_trait)]
4#![allow(incomplete_features)]
5
6use embassy::time::{Duration, Timer};
7use embassy::util::Forever;
8use embassy_std::Executor;
9use log::*;
10
11#[embassy::task]
12async fn run() {
13 loop {
14 info!("tick");
15 Timer::after(Duration::from_secs(1)).await;
16 }
17}
18
19static EXECUTOR: Forever<Executor> = Forever::new();
20
21fn main() {
22 env_logger::builder()
23 .filter_level(log::LevelFilter::Debug)
24 .format_timestamp_nanos()
25 .init();
26
27 let executor = EXECUTOR.put(Executor::new());
28 executor.run(|spawner| {
29 spawner.spawn(run()).unwrap();
30 });
31}
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 @@
1use nix::fcntl::OFlag;
2use nix::sys::termios;
3use nix::Error;
4use std::io;
5use std::os::unix::io::{AsRawFd, RawFd};
6
7pub struct SerialPort {
8 fd: RawFd,
9}
10
11impl SerialPort {
12 pub fn new<'a, P: ?Sized + nix::NixPath>(
13 path: &P,
14 baudrate: termios::BaudRate,
15 ) -> io::Result<Self> {
16 let fd = nix::fcntl::open(
17 path,
18 OFlag::O_RDWR | OFlag::O_NOCTTY | OFlag::O_NONBLOCK,
19 nix::sys::stat::Mode::empty(),
20 )
21 .map_err(to_io_error)?;
22
23 let mut cfg = termios::tcgetattr(fd).map_err(to_io_error)?;
24 cfg.input_flags = termios::InputFlags::empty();
25 cfg.output_flags = termios::OutputFlags::empty();
26 cfg.control_flags = termios::ControlFlags::empty();
27 cfg.local_flags = termios::LocalFlags::empty();
28 termios::cfmakeraw(&mut cfg);
29 cfg.input_flags |= termios::InputFlags::IGNBRK;
30 cfg.control_flags |= termios::ControlFlags::CREAD;
31 //cfg.control_flags |= termios::ControlFlags::CRTSCTS;
32 termios::cfsetospeed(&mut cfg, baudrate).map_err(to_io_error)?;
33 termios::cfsetispeed(&mut cfg, baudrate).map_err(to_io_error)?;
34 termios::cfsetspeed(&mut cfg, baudrate).map_err(to_io_error)?;
35 // Set VMIN = 1 to block until at least one character is received.
36 cfg.control_chars[termios::SpecialCharacterIndices::VMIN as usize] = 1;
37 termios::tcsetattr(fd, termios::SetArg::TCSANOW, &cfg).map_err(to_io_error)?;
38 termios::tcflush(fd, termios::FlushArg::TCIOFLUSH).map_err(to_io_error)?;
39
40 Ok(Self { fd })
41 }
42}
43
44impl AsRawFd for SerialPort {
45 fn as_raw_fd(&self) -> RawFd {
46 self.fd
47 }
48}
49
50impl io::Read for SerialPort {
51 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
52 nix::unistd::read(self.fd, buf).map_err(to_io_error)
53 }
54}
55
56impl io::Write for SerialPort {
57 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
58 nix::unistd::write(self.fd, buf).map_err(to_io_error)
59 }
60
61 fn flush(&mut self) -> io::Result<()> {
62 Ok(())
63 }
64}
65
66fn to_io_error(e: Error) -> io::Error {
67 match e {
68 Error::Sys(errno) => errno.into(),
69 e => io::Error::new(io::ErrorKind::InvalidInput, e),
70 }
71}
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 @@
1use async_io::Async;
2use libc;
3use log::*;
4use smoltcp::wire::EthernetFrame;
5use std::io;
6use std::io::{Read, Write};
7use std::os::unix::io::{AsRawFd, RawFd};
8
9pub const SIOCGIFMTU: libc::c_ulong = 0x8921;
10pub const SIOCGIFINDEX: libc::c_ulong = 0x8933;
11pub const ETH_P_ALL: libc::c_short = 0x0003;
12pub const TUNSETIFF: libc::c_ulong = 0x400454CA;
13pub const IFF_TUN: libc::c_int = 0x0001;
14pub const IFF_TAP: libc::c_int = 0x0002;
15pub const IFF_NO_PI: libc::c_int = 0x1000;
16
17#[repr(C)]
18#[derive(Debug)]
19struct ifreq {
20 ifr_name: [libc::c_char; libc::IF_NAMESIZE],
21 ifr_data: libc::c_int, /* ifr_ifindex or ifr_mtu */
22}
23
24fn ifreq_for(name: &str) -> ifreq {
25 let mut ifreq = ifreq {
26 ifr_name: [0; libc::IF_NAMESIZE],
27 ifr_data: 0,
28 };
29 for (i, byte) in name.as_bytes().iter().enumerate() {
30 ifreq.ifr_name[i] = *byte as libc::c_char
31 }
32 ifreq
33}
34
35fn ifreq_ioctl(
36 lower: libc::c_int,
37 ifreq: &mut ifreq,
38 cmd: libc::c_ulong,
39) -> io::Result<libc::c_int> {
40 unsafe {
41 let res = libc::ioctl(lower, cmd as _, ifreq as *mut ifreq);
42 if res == -1 {
43 return Err(io::Error::last_os_error());
44 }
45 }
46
47 Ok(ifreq.ifr_data)
48}
49
50#[derive(Debug)]
51pub struct TunTap {
52 fd: libc::c_int,
53 ifreq: ifreq,
54 mtu: usize,
55}
56
57impl AsRawFd for TunTap {
58 fn as_raw_fd(&self) -> RawFd {
59 self.fd
60 }
61}
62
63impl TunTap {
64 pub fn new(name: &str) -> io::Result<TunTap> {
65 unsafe {
66 let fd = libc::open(
67 "/dev/net/tun\0".as_ptr() as *const libc::c_char,
68 libc::O_RDWR | libc::O_NONBLOCK,
69 );
70 if fd == -1 {
71 return Err(io::Error::last_os_error());
72 }
73
74 let mut ifreq = ifreq_for(name);
75 ifreq.ifr_data = IFF_TAP | IFF_NO_PI;
76 ifreq_ioctl(fd, &mut ifreq, TUNSETIFF)?;
77
78 let socket = libc::socket(libc::AF_INET, libc::SOCK_DGRAM, libc::IPPROTO_IP);
79 if socket == -1 {
80 return Err(io::Error::last_os_error());
81 }
82
83 let ip_mtu = ifreq_ioctl(socket, &mut ifreq, SIOCGIFMTU);
84 libc::close(socket);
85 let ip_mtu = ip_mtu? as usize;
86
87 // SIOCGIFMTU returns the IP MTU (typically 1500 bytes.)
88 // smoltcp counts the entire Ethernet packet in the MTU, so add the Ethernet header size to it.
89 let mtu = ip_mtu + EthernetFrame::<&[u8]>::header_len();
90
91 Ok(TunTap { fd, mtu, ifreq })
92 }
93 }
94}
95
96impl Drop for TunTap {
97 fn drop(&mut self) {
98 unsafe {
99 libc::close(self.fd);
100 }
101 }
102}
103
104impl io::Read for TunTap {
105 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
106 let len = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut libc::c_void, buf.len()) };
107 if len == -1 {
108 Err(io::Error::last_os_error())
109 } else {
110 Ok(len as usize)
111 }
112 }
113}
114
115impl io::Write for TunTap {
116 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
117 let len = unsafe { libc::write(self.fd, buf.as_ptr() as *mut libc::c_void, buf.len()) };
118 if len == -1 {
119 Err(io::Error::last_os_error())
120 } else {
121 Ok(len as usize)
122 }
123 }
124
125 fn flush(&mut self) -> io::Result<()> {
126 Ok(())
127 }
128}
129
130pub struct TunTapDevice {
131 device: Async<TunTap>,
132 waker: Option<Waker>,
133}
134
135impl TunTapDevice {
136 pub fn new(name: &str) -> io::Result<TunTapDevice> {
137 Ok(Self {
138 device: Async::new(TunTap::new(name)?)?,
139 waker: None,
140 })
141 }
142}
143
144use core::task::Waker;
145use embassy_net::{DeviceCapabilities, LinkState, Packet, PacketBox, PacketBoxExt, PacketBuf};
146use std::task::Context;
147
148impl crate::Device for TunTapDevice {
149 fn is_transmit_ready(&mut self) -> bool {
150 true
151 }
152
153 fn transmit(&mut self, pkt: PacketBuf) {
154 // todo handle WouldBlock
155 match self.device.get_mut().write(&pkt) {
156 Ok(_) => {}
157 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
158 info!("transmit WouldBlock");
159 }
160 Err(e) => panic!("transmit error: {:?}", e),
161 }
162 }
163
164 fn receive(&mut self) -> Option<PacketBuf> {
165 let mut pkt = PacketBox::new(Packet::new()).unwrap();
166 loop {
167 match self.device.get_mut().read(&mut pkt[..]) {
168 Ok(n) => {
169 return Some(pkt.slice(0..n));
170 }
171 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
172 let ready = if let Some(w) = self.waker.as_ref() {
173 let mut cx = Context::from_waker(w);
174 let ready = self.device.poll_readable(&mut cx).is_ready();
175 ready
176 } else {
177 false
178 };
179 if !ready {
180 return None;
181 }
182 }
183 Err(e) => panic!("read error: {:?}", e),
184 }
185 }
186 }
187
188 fn register_waker(&mut self, w: &Waker) {
189 match self.waker {
190 // Optimization: If both the old and new Wakers wake the same task, we can simply
191 // keep the old waker, skipping the clone. (In most executor implementations,
192 // cloning a waker is somewhat expensive, comparable to cloning an Arc).
193 Some(ref w2) if (w2.will_wake(w)) => {}
194 _ => {
195 // clone the new waker and store it
196 if let Some(old_waker) = core::mem::replace(&mut self.waker, Some(w.clone())) {
197 // We had a waker registered for another task. Wake it, so the other task can
198 // reregister itself if it's still interested.
199 //
200 // If two tasks are waiting on the same thing concurrently, this will cause them
201 // to wake each other in a loop fighting over this WakerRegistration. This wastes
202 // CPU but things will still work.
203 //
204 // If the user wants to have two tasks waiting on the same thing they should use
205 // a more appropriate primitive that can store multiple wakers.
206 old_waker.wake()
207 }
208 }
209 }
210 }
211
212 fn capabilities(&mut self) -> DeviceCapabilities {
213 let mut caps = DeviceCapabilities::default();
214 caps.max_transmission_unit = self.device.get_ref().mtu;
215 caps
216 }
217
218 fn link_state(&mut self) -> LinkState {
219 LinkState::Up
220 }
221
222 fn ethernet_address(&mut self) -> [u8; 6] {
223 [0x02, 0x03, 0x04, 0x05, 0x06, 0x07]
224 }
225}
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 @@
1[unstable]
2build-std = ["core"]
3
4[target.'cfg(all(target_arch = "arm", target_os = "none"))']
5# replace STM32F429ZITx with your chip as listed in `probe-run --list-chips`
6runner = "probe-run --chip STM32F429ZITx"
7
8rustflags = [
9 # LLD (shipped with the Rust toolchain) is used as the default linker
10 "-C", "link-arg=--nmagic",
11 "-C", "link-arg=-Tlink.x",
12 "-C", "link-arg=-Tdefmt.x",
13
14 # Code-size optimizations.
15 "-Z", "trap-unreachable=no",
16 "-C", "inline-threshold=5",
17 "-C", "no-vectorize-loops",
18]
19
20[build]
21target = "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 @@
1[package]
2authors = ["Dario Nieuwenhuis <[email protected]>"]
3edition = "2018"
4name = "embassy-stm32f4-examples"
5version = "0.1.0"
6resolver = "2"
7
8[features]
9default = [
10 "defmt-default",
11]
12defmt-default = []
13defmt-trace = []
14defmt-debug = []
15defmt-info = []
16defmt-warn = []
17defmt-error = []
18
19[dependencies]
20embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] }
21embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] }
22embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f429zi"] }
23embassy-extras = {version = "0.1.0", path = "../../embassy-extras" }
24stm32f4 = { version = "0.13", features = ["stm32f429"] }
25
26defmt = "0.2.0"
27defmt-rtt = "0.2.0"
28
29cortex-m = "0.7.1"
30cortex-m-rt = "0.6.14"
31embedded-hal = { version = "0.2.4" }
32panic-probe = { version = "0.2.0", features= ["print-defmt"] }
33futures = { version = "0.3.8", default-features = false, features = ["async-await"] }
34rtt-target = { version = "0.3", features = ["cortex-m"] }
35heapless = "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 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31}
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 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the STM32F429ZI */
5 FLASH : ORIGIN = 0x08000000, LENGTH = 2048K
6 RAM : ORIGIN = 0x20000000, LENGTH = 192K
7}
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 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11use embassy_stm32::gpio::{Level, Output};
12use embedded_hal::digital::v2::OutputPin;
13use example_common::*;
14
15use cortex_m_rt::entry;
16use stm32f4::stm32f429 as pac;
17
18#[entry]
19fn main() -> ! {
20 info!("Hello World!");
21
22 let pp = pac::Peripherals::take().unwrap();
23
24 pp.DBGMCU.cr.modify(|_, w| {
25 w.dbg_sleep().set_bit();
26 w.dbg_standby().set_bit();
27 w.dbg_stop().set_bit()
28 });
29 pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled());
30
31 pp.RCC.ahb1enr.modify(|_, w| {
32 w.gpioaen().enabled();
33 w.gpioben().enabled();
34 w.gpiocen().enabled();
35 w.gpioden().enabled();
36 w.gpioeen().enabled();
37 w.gpiofen().enabled();
38 w
39 });
40
41 let p = embassy_stm32::init(Default::default());
42
43 let mut led = Output::new(p.PB7, Level::High);
44
45 loop {
46 info!("high");
47 led.set_high().unwrap();
48 cortex_m::asm::delay(10_000_000);
49
50 info!("low");
51 led.set_low().unwrap();
52 cortex_m::asm::delay(10_000_000);
53 }
54}
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 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11use embassy_stm32::gpio::{Input, Level, Output, Pull};
12use embedded_hal::digital::v2::{InputPin, OutputPin};
13use example_common::*;
14
15use cortex_m_rt::entry;
16use stm32f4::stm32f429 as pac;
17
18#[entry]
19fn main() -> ! {
20 info!("Hello World!");
21
22 let pp = pac::Peripherals::take().unwrap();
23
24 pp.DBGMCU.cr.modify(|_, w| {
25 w.dbg_sleep().set_bit();
26 w.dbg_standby().set_bit();
27 w.dbg_stop().set_bit()
28 });
29 pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled());
30
31 pp.RCC.ahb1enr.modify(|_, w| {
32 w.gpioaen().enabled();
33 w.gpioben().enabled();
34 w.gpiocen().enabled();
35 w.gpioden().enabled();
36 w.gpioeen().enabled();
37 w.gpiofen().enabled();
38 w
39 });
40
41 let p = embassy_stm32::init(Default::default());
42
43 let button = Input::new(p.PC13, Pull::Down);
44 let mut led1 = Output::new(p.PB0, Level::High);
45 let _led2 = Output::new(p.PB7, Level::High);
46 let mut led3 = Output::new(p.PB14, Level::High);
47
48 loop {
49 if button.is_high().unwrap() {
50 info!("high");
51 led1.set_high().unwrap();
52 led3.set_low().unwrap();
53 } else {
54 info!("low");
55 led1.set_low().unwrap();
56 led3.set_high().unwrap();
57 }
58 }
59}
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 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11use embassy::executor::Executor;
12use embassy::time::Clock;
13use embassy::util::Forever;
14use embassy_stm32::exti::ExtiInput;
15use embassy_stm32::gpio::{Input, Pull};
16use embassy_traits::gpio::{WaitForFallingEdge, WaitForRisingEdge};
17use example_common::*;
18
19use cortex_m_rt::entry;
20use stm32f4::stm32f429 as pac;
21
22#[embassy::task]
23async fn main_task() {
24 let p = embassy_stm32::init(Default::default());
25
26 let button = Input::new(p.PC13, Pull::Down);
27 let mut button = ExtiInput::new(button, p.EXTI13);
28
29 info!("Press the USER button...");
30
31 loop {
32 button.wait_for_rising_edge().await;
33 info!("Pressed!");
34 button.wait_for_falling_edge().await;
35 info!("Released!");
36 }
37}
38
39struct ZeroClock;
40
41impl Clock for ZeroClock {
42 fn now(&self) -> u64 {
43 0
44 }
45}
46
47static EXECUTOR: Forever<Executor> = Forever::new();
48
49#[entry]
50fn main() -> ! {
51 info!("Hello World!");
52
53 let pp = pac::Peripherals::take().unwrap();
54
55 pp.DBGMCU.cr.modify(|_, w| {
56 w.dbg_sleep().set_bit();
57 w.dbg_standby().set_bit();
58 w.dbg_stop().set_bit()
59 });
60 pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled());
61
62 pp.RCC.ahb1enr.modify(|_, w| {
63 w.gpioaen().enabled();
64 w.gpioben().enabled();
65 w.gpiocen().enabled();
66 w.gpioden().enabled();
67 w.gpioeen().enabled();
68 w.gpiofen().enabled();
69 w
70 });
71 pp.RCC.apb2enr.modify(|_, w| {
72 w.syscfgen().enabled();
73 w
74 });
75
76 unsafe { embassy::time::set_clock(&ZeroClock) };
77
78 let executor = EXECUTOR.put(Executor::new());
79
80 executor.run(|spawner| {
81 unwrap!(spawner.spawn(main_task()));
82 })
83}
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 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11
12use embassy_stm32::gpio::{Level, Output};
13use embedded_hal::digital::v2::OutputPin;
14use example_common::*;
15
16use cortex_m_rt::entry;
17use embassy_stm32::spi::{Config, Spi};
18use embassy_stm32::time::Hertz;
19use embedded_hal::blocking::spi::Transfer;
20use stm32f4::stm32f429 as pac;
21
22#[entry]
23fn main() -> ! {
24 info!("Hello World, dude!");
25
26 let pp = pac::Peripherals::take().unwrap();
27
28 pp.DBGMCU.cr.modify(|_, w| {
29 w.dbg_sleep().set_bit();
30 w.dbg_standby().set_bit();
31 w.dbg_stop().set_bit()
32 });
33 pp.RCC.ahb1enr.modify(|_, w| w.dma1en().set_bit());
34
35 pp.RCC.apb1enr.modify(|_, w| {
36 w.spi3en().enabled();
37 w
38 });
39
40 pp.RCC.ahb1enr.modify(|_, w| {
41 w.gpioaen().enabled();
42 w.gpioben().enabled();
43 w.gpiocen().enabled();
44 w.gpioden().enabled();
45 w.gpioeen().enabled();
46 w.gpiofen().enabled();
47 w
48 });
49
50 let p = embassy_stm32::init(Default::default());
51
52 let mut spi = Spi::new(
53 Hertz(16_000_000),
54 p.SPI3,
55 p.PC10,
56 p.PC12,
57 p.PC11,
58 Hertz(1_000_000),
59 Config::default(),
60 );
61
62 let mut cs = Output::new(p.PE0, Level::High);
63
64 loop {
65 let mut buf = [0x0A; 4];
66 unwrap!(cs.set_low());
67 unwrap!(spi.transfer(&mut buf));
68 unwrap!(cs.set_high());
69 info!("xfer {=[u8]:x}", buf);
70 }
71}
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 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11use cortex_m::prelude::_embedded_hal_blocking_serial_Write;
12use embassy::executor::Executor;
13use embassy::time::Clock;
14use embassy::util::Forever;
15use embassy_stm32::usart::{Config, Uart};
16use example_common::*;
17
18use cortex_m_rt::entry;
19use stm32f4::stm32f429 as pac;
20
21#[embassy::task]
22async fn main_task() {
23 let p = embassy_stm32::init(Default::default());
24
25 let config = Config::default();
26 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000);
27
28 usart.bwrite_all(b"Hello Embassy World!\r\n").unwrap();
29 info!("wrote Hello, starting echo");
30
31 let mut buf = [0u8; 1];
32 loop {
33 usart.read(&mut buf).unwrap();
34 usart.bwrite_all(&buf).unwrap();
35 }
36}
37
38struct ZeroClock;
39
40impl Clock for ZeroClock {
41 fn now(&self) -> u64 {
42 0
43 }
44}
45
46static EXECUTOR: Forever<Executor> = Forever::new();
47
48#[entry]
49fn main() -> ! {
50 info!("Hello World!");
51
52 let pp = pac::Peripherals::take().unwrap();
53
54 pp.DBGMCU.cr.modify(|_, w| {
55 w.dbg_sleep().set_bit();
56 w.dbg_standby().set_bit();
57 w.dbg_stop().set_bit()
58 });
59 pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled());
60
61 pp.RCC.ahb1enr.modify(|_, w| {
62 w.gpioaen().enabled();
63 w.gpioben().enabled();
64 w.gpiocen().enabled();
65 w.gpioden().enabled();
66 w.gpioeen().enabled();
67 w.gpiofen().enabled();
68 w
69 });
70 pp.RCC.apb2enr.modify(|_, w| {
71 w.syscfgen().enabled();
72 w
73 });
74 pp.RCC.apb1enr.modify(|_, w| {
75 w.usart3en().enabled();
76 w
77 });
78
79 unsafe { embassy::time::set_clock(&ZeroClock) };
80
81 let executor = EXECUTOR.put(Executor::new());
82
83 executor.run(|spawner| {
84 unwrap!(spawner.spawn(main_task()));
85 })
86}
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 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7#![allow(incomplete_features)]
8
9#[path = "../example_common.rs"]
10mod example_common;
11use core::fmt::Write;
12use cortex_m_rt::entry;
13use embassy::executor::Executor;
14use embassy::time::Clock;
15use embassy::util::Forever;
16use embassy_stm32::usart::{Config, Uart};
17use example_common::*;
18use heapless::String;
19use stm32f4::stm32f429 as pac;
20
21#[embassy::task]
22async fn main_task() {
23 let mut p = embassy_stm32::init(Default::default());
24
25 let config = Config::default();
26 let mut usart = Uart::new(p.USART3, p.PD9, p.PD8, config, 16_000_000);
27
28 for n in 0u32.. {
29 let mut s: String<128> = String::new();
30 core::write!(&mut s, "Hello DMA World {}!\r\n", n).unwrap();
31
32 usart
33 .write_dma(&mut p.DMA1_CH3, s.as_bytes())
34 .await
35 .unwrap();
36 info!("wrote DMA");
37 }
38}
39
40struct ZeroClock;
41
42impl Clock for ZeroClock {
43 fn now(&self) -> u64 {
44 0
45 }
46}
47
48static EXECUTOR: Forever<Executor> = Forever::new();
49
50#[entry]
51fn main() -> ! {
52 info!("Hello World!");
53
54 let pp = pac::Peripherals::take().unwrap();
55
56 pp.DBGMCU.cr.modify(|_, w| {
57 w.dbg_sleep().set_bit();
58 w.dbg_standby().set_bit();
59 w.dbg_stop().set_bit()
60 });
61 pp.RCC.ahb1enr.modify(|_, w| w.dma1en().enabled());
62
63 pp.RCC.ahb1enr.modify(|_, w| {
64 w.gpioaen().enabled();
65 w.gpioben().enabled();
66 w.gpiocen().enabled();
67 w.gpioden().enabled();
68 w.gpioeen().enabled();
69 w.gpiofen().enabled();
70 w.dma1en().enabled();
71 w.dma2en().enabled();
72 w
73 });
74 pp.RCC.apb2enr.modify(|_, w| {
75 w.syscfgen().enabled();
76 w
77 });
78 pp.RCC.apb1enr.modify(|_, w| {
79 w.usart3en().enabled();
80 w
81 });
82
83 unsafe { embassy::time::set_clock(&ZeroClock) };
84
85 let executor = EXECUTOR.put(Executor::new());
86
87 executor.run(|spawner| {
88 unwrap!(spawner.spawn(main_task()));
89 })
90}
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 @@
1#![macro_use]
2
3use defmt_rtt as _; // global logger
4use panic_probe as _;
5
6pub use defmt::*;
7
8use core::sync::atomic::{AtomicUsize, Ordering};
9
10defmt::timestamp! {"{=u64}", {
11 static COUNT: AtomicUsize = AtomicUsize::new(0);
12 // NOTE(no-CAS) `timestamps` runs with interrupts disabled
13 let n = COUNT.load(Ordering::Relaxed);
14 COUNT.store(n + 1, Ordering::Relaxed);
15 n as u64
16 }
17}