aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf52840/src/bin
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-01-10 11:06:22 +0000
committerGitHub <[email protected]>2023-01-10 11:06:22 +0000
commitdbf749370897290e16ef6ed2917d075c40358991 (patch)
tree0ad516d336522f531514ac300e9c0adac1371250 /examples/nrf52840/src/bin
parent3fbedd7c0953cab5f14433da6b9b1e2ff5d76939 (diff)
parent2baebabf4dd2abecfd08ca078ecf59060d5ad585 (diff)
Merge #1149
1149: Add samples for nrf5340 r=lulf a=Tiwalun Samples for the nrf5340, copied from the existing nrf samples. Not sure if copying them is the best way of adding support, or using features in the existing samples would be better? The code is mostly the same, with some different peripherals and pin mappings for the DK. Co-authored-by: Dominik Boehi <[email protected]>
Diffstat (limited to 'examples/nrf52840/src/bin')
-rw-r--r--examples/nrf52840/src/bin/awaitable_timer.rs26
-rw-r--r--examples/nrf52840/src/bin/blinky.rs21
-rw-r--r--examples/nrf52840/src/bin/buffered_uart.rs57
-rw-r--r--examples/nrf52840/src/bin/channel.rs43
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs50
-rw-r--r--examples/nrf52840/src/bin/executor_fairness_test.rs43
-rw-r--r--examples/nrf52840/src/bin/gpiote_channel.rs66
-rw-r--r--examples/nrf52840/src/bin/gpiote_port.rs34
-rw-r--r--examples/nrf52840/src/bin/i2s_effect.rs117
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs115
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs151
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_report.rs78
-rw-r--r--examples/nrf52840/src/bin/lora_p2p_sense.rs125
-rw-r--r--examples/nrf52840/src/bin/manually_create_executor.rs49
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs140
-rw-r--r--examples/nrf52840/src/bin/mutex.rs42
-rw-r--r--examples/nrf52840/src/bin/nvmc.rs43
-rw-r--r--examples/nrf52840/src/bin/pdm.rs33
-rw-r--r--examples/nrf52840/src/bin/ppi.rs73
-rw-r--r--examples/nrf52840/src/bin/pubsub.rs107
-rw-r--r--examples/nrf52840/src/bin/pwm.rs89
-rw-r--r--examples/nrf52840/src/bin/pwm_double_sequence.rs41
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence.rs36
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ppi.rs67
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs75
-rw-r--r--examples/nrf52840/src/bin/pwm_servo.rs47
-rw-r--r--examples/nrf52840/src/bin/qdec.rs24
-rw-r--r--examples/nrf52840/src/bin/qspi.rs76
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs78
-rw-r--r--examples/nrf52840/src/bin/raw_spawn.rs52
-rw-r--r--examples/nrf52840/src/bin/rng.rs30
-rw-r--r--examples/nrf52840/src/bin/saadc.rs25
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs68
-rw-r--r--examples/nrf52840/src/bin/self_spawn.rs22
-rw-r--r--examples/nrf52840/src/bin/self_spawn_current_executor.rs22
-rw-r--r--examples/nrf52840/src/bin/spim.rs68
-rw-r--r--examples/nrf52840/src/bin/spis.rs27
-rw-r--r--examples/nrf52840/src/bin/temp.rs23
-rw-r--r--examples/nrf52840/src/bin/timer.rs31
-rw-r--r--examples/nrf52840/src/bin/twim.rs31
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs50
-rw-r--r--examples/nrf52840/src/bin/twis.rs46
-rw-r--r--examples/nrf52840/src/bin/uart.rs35
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs35
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs60
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs169
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs222
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs124
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs110
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs118
-rw-r--r--examples/nrf52840/src/bin/wdt.rs41
51 files changed, 3355 insertions, 0 deletions
diff --git a/examples/nrf52840/src/bin/awaitable_timer.rs b/examples/nrf52840/src/bin/awaitable_timer.rs
new file mode 100644
index 000000000..b32af236c
--- /dev/null
+++ b/examples/nrf52840/src/bin/awaitable_timer.rs
@@ -0,0 +1,26 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::timer::Timer;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 let mut t = Timer::new_awaitable(p.TIMER0, interrupt::take!(TIMER0));
15 // default frequency is 1MHz, so this triggers every second
16 t.cc(0).write(1_000_000);
17 // clear the timer value on cc[0] compare match
18 t.cc(0).short_compare_clear();
19 t.start();
20
21 loop {
22 // wait for compare match
23 t.cc(0).wait().await;
24 info!("hardware timer tick");
25 }
26}
diff --git a/examples/nrf52840/src/bin/blinky.rs b/examples/nrf52840/src/bin/blinky.rs
new file mode 100644
index 000000000..513f6cd82
--- /dev/null
+++ b/examples/nrf52840/src/bin/blinky.rs
@@ -0,0 +1,21 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
14
15 loop {
16 led.set_high();
17 Timer::after(Duration::from_millis(300)).await;
18 led.set_low();
19 Timer::after(Duration::from_millis(300)).await;
20 }
21}
diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs
new file mode 100644
index 000000000..ea566f4b2
--- /dev/null
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
@@ -0,0 +1,57 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::buffered_uarte::{BufferedUarte, State};
8use embassy_nrf::{interrupt, uarte};
9use embedded_io::asynch::{BufRead, Write};
10use futures::pin_mut;
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16 let mut config = uarte::Config::default();
17 config.parity = uarte::Parity::EXCLUDED;
18 config.baudrate = uarte::Baudrate::BAUD115200;
19
20 let mut tx_buffer = [0u8; 4096];
21 let mut rx_buffer = [0u8; 4096];
22
23 let irq = interrupt::take!(UARTE0_UART0);
24 let mut state = State::new();
25 // Please note - important to have hardware flow control (https://github.com/embassy-rs/embassy/issues/536)
26 let u = BufferedUarte::new(
27 &mut state,
28 p.UARTE0,
29 p.TIMER0,
30 p.PPI_CH0,
31 p.PPI_CH1,
32 irq,
33 p.P0_08,
34 p.P0_06,
35 p.P0_07,
36 p.P0_05,
37 config,
38 &mut rx_buffer,
39 &mut tx_buffer,
40 );
41 pin_mut!(u);
42
43 info!("uarte initialized!");
44
45 unwrap!(u.write_all(b"Hello!\r\n").await);
46 info!("wrote hello in uart!");
47
48 loop {
49 info!("reading...");
50 let buf = unwrap!(u.fill_buf().await);
51 info!("read done, got {}", buf);
52
53 // Read bytes have to be explicitly consumed, otherwise fill_buf() will return them again
54 let n = buf.len();
55 u.consume(n);
56 }
57}
diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs
new file mode 100644
index 000000000..d782a79e7
--- /dev/null
+++ b/examples/nrf52840/src/bin/channel.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::unwrap;
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive};
8use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
9use embassy_sync::channel::Channel;
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13enum LedState {
14 On,
15 Off,
16}
17
18static CHANNEL: Channel<ThreadModeRawMutex, LedState, 1> = Channel::new();
19
20#[embassy_executor::task]
21async fn my_task() {
22 loop {
23 CHANNEL.send(LedState::On).await;
24 Timer::after(Duration::from_secs(1)).await;
25 CHANNEL.send(LedState::Off).await;
26 Timer::after(Duration::from_secs(1)).await;
27 }
28}
29
30#[embassy_executor::main]
31async fn main(spawner: Spawner) {
32 let p = embassy_nrf::init(Default::default());
33 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
34
35 unwrap!(spawner.spawn(my_task()));
36
37 loop {
38 match CHANNEL.recv().await {
39 LedState::On => led.set_high(),
40 LedState::Off => led.set_low(),
41 }
42 }
43}
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
new file mode 100644
index 000000000..fcccdaed5
--- /dev/null
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -0,0 +1,50 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::unwrap;
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin};
8use embassy_sync::blocking_mutex::raw::NoopRawMutex;
9use embassy_sync::channel::{Channel, Receiver, Sender};
10use embassy_time::{Duration, Timer};
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14enum LedState {
15 On,
16 Off,
17}
18
19static CHANNEL: StaticCell<Channel<NoopRawMutex, LedState, 1>> = StaticCell::new();
20
21#[embassy_executor::task]
22async fn send_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) {
23 loop {
24 sender.send(LedState::On).await;
25 Timer::after(Duration::from_secs(1)).await;
26 sender.send(LedState::Off).await;
27 Timer::after(Duration::from_secs(1)).await;
28 }
29}
30
31#[embassy_executor::task]
32async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) {
33 let mut led = Output::new(led, Level::Low, OutputDrive::Standard);
34
35 loop {
36 match receiver.recv().await {
37 LedState::On => led.set_high(),
38 LedState::Off => led.set_low(),
39 }
40 }
41}
42
43#[embassy_executor::main]
44async fn main(spawner: Spawner) {
45 let p = embassy_nrf::init(Default::default());
46 let channel = CHANNEL.init(Channel::new());
47
48 unwrap!(spawner.spawn(send_task(channel.sender())));
49 unwrap!(spawner.spawn(recv_task(p.P0_13.degrade(), channel.receiver())));
50}
diff --git a/examples/nrf52840/src/bin/executor_fairness_test.rs b/examples/nrf52840/src/bin/executor_fairness_test.rs
new file mode 100644
index 000000000..2a28f2763
--- /dev/null
+++ b/examples/nrf52840/src/bin/executor_fairness_test.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::future::poll_fn;
6use core::task::Poll;
7
8use defmt::{info, unwrap};
9use embassy_executor::Spawner;
10use embassy_time::{Duration, Instant, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::task]
14async fn run1() {
15 loop {
16 info!("DING DONG");
17 Timer::after(Duration::from_ticks(16000)).await;
18 }
19}
20
21#[embassy_executor::task]
22async fn run2() {
23 loop {
24 Timer::at(Instant::from_ticks(0)).await;
25 }
26}
27
28#[embassy_executor::task]
29async fn run3() {
30 poll_fn(|cx| {
31 cx.waker().wake_by_ref();
32 Poll::<()>::Pending
33 })
34 .await;
35}
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let _p = embassy_nrf::init(Default::default());
40 unwrap!(spawner.spawn(run1()));
41 unwrap!(spawner.spawn(run2()));
42 unwrap!(spawner.spawn(run3()));
43}
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs
new file mode 100644
index 000000000..5bfd02465
--- /dev/null
+++ b/examples/nrf52840/src/bin/gpiote_channel.rs
@@ -0,0 +1,66 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Input, Pull};
8use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Starting!");
15
16 let ch1 = InputChannel::new(
17 p.GPIOTE_CH0,
18 Input::new(p.P0_11, Pull::Up),
19 InputChannelPolarity::HiToLo,
20 );
21 let ch2 = InputChannel::new(
22 p.GPIOTE_CH1,
23 Input::new(p.P0_12, Pull::Up),
24 InputChannelPolarity::LoToHi,
25 );
26 let ch3 = InputChannel::new(
27 p.GPIOTE_CH2,
28 Input::new(p.P0_24, Pull::Up),
29 InputChannelPolarity::Toggle,
30 );
31 let ch4 = InputChannel::new(
32 p.GPIOTE_CH3,
33 Input::new(p.P0_25, Pull::Up),
34 InputChannelPolarity::Toggle,
35 );
36
37 let button1 = async {
38 loop {
39 ch1.wait().await;
40 info!("Button 1 pressed")
41 }
42 };
43
44 let button2 = async {
45 loop {
46 ch2.wait().await;
47 info!("Button 2 released")
48 }
49 };
50
51 let button3 = async {
52 loop {
53 ch3.wait().await;
54 info!("Button 3 toggled")
55 }
56 };
57
58 let button4 = async {
59 loop {
60 ch4.wait().await;
61 info!("Button 4 toggled")
62 }
63 };
64
65 futures::join!(button1, button2, button3, button4);
66}
diff --git a/examples/nrf52840/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs
new file mode 100644
index 000000000..0155d539e
--- /dev/null
+++ b/examples/nrf52840/src/bin/gpiote_port.rs
@@ -0,0 +1,34 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::task(pool_size = 4)]
11async fn button_task(n: usize, mut pin: Input<'static, AnyPin>) {
12 loop {
13 pin.wait_for_low().await;
14 info!("Button {:?} pressed!", n);
15 pin.wait_for_high().await;
16 info!("Button {:?} released!", n);
17 }
18}
19
20#[embassy_executor::main]
21async fn main(spawner: Spawner) {
22 let p = embassy_nrf::init(Default::default());
23 info!("Starting!");
24
25 let btn1 = Input::new(p.P0_11.degrade(), Pull::Up);
26 let btn2 = Input::new(p.P0_12.degrade(), Pull::Up);
27 let btn3 = Input::new(p.P0_24.degrade(), Pull::Up);
28 let btn4 = Input::new(p.P0_25.degrade(), Pull::Up);
29
30 unwrap!(spawner.spawn(button_task(1, btn1)));
31 unwrap!(spawner.spawn(button_task(2, btn2)));
32 unwrap!(spawner.spawn(button_task(3, btn3)));
33 unwrap!(spawner.spawn(button_task(4, btn4)));
34}
diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs
new file mode 100644
index 000000000..3cca005b1
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -0,0 +1,117 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_BUFFERS: usize = 2;
16const NUM_SAMPLES: usize = 4;
17
18#[embassy_executor::main]
19async fn main(_spawner: Spawner) {
20 let p = embassy_nrf::init(Default::default());
21
22 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
23
24 let sample_rate = master_clock.sample_rate();
25 info!("Sample rate: {}", sample_rate);
26
27 let config = Config::default()
28 .sample_width(SampleWidth::_16bit)
29 .channels(Channels::MonoLeft);
30
31 let irq = interrupt::take!(I2S);
32 let buffers_out = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
33 let buffers_in = MultiBuffering::<Sample, NUM_BUFFERS, NUM_SAMPLES>::new();
34 let mut full_duplex_stream = I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).full_duplex(
35 p.P0_29,
36 p.P0_28,
37 buffers_out,
38 buffers_in,
39 );
40
41 let mut modulator = SineOsc::new();
42 modulator.set_frequency(8.0, 1.0 / sample_rate as f32);
43 modulator.set_amplitude(1.0);
44
45 full_duplex_stream.start().await.expect("I2S Start");
46
47 loop {
48 let (buff_out, buff_in) = full_duplex_stream.buffers();
49 for i in 0..NUM_SAMPLES {
50 let modulation = (Sample::SCALE as f32 * bipolar_to_unipolar(modulator.generate())) as Sample;
51 buff_out[i] = buff_in[i] * modulation;
52 }
53
54 if let Err(err) = full_duplex_stream.send_and_receive().await {
55 error!("{}", err);
56 }
57 }
58}
59
60struct SineOsc {
61 amplitude: f32,
62 modulo: f32,
63 phase_inc: f32,
64}
65
66impl SineOsc {
67 const B: f32 = 4.0 / PI;
68 const C: f32 = -4.0 / (PI * PI);
69 const P: f32 = 0.225;
70
71 pub fn new() -> Self {
72 Self {
73 amplitude: 1.0,
74 modulo: 0.0,
75 phase_inc: 0.0,
76 }
77 }
78
79 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
80 self.phase_inc = freq * inv_sample_rate;
81 }
82
83 pub fn set_amplitude(&mut self, amplitude: f32) {
84 self.amplitude = amplitude;
85 }
86
87 pub fn generate(&mut self) -> f32 {
88 let signal = self.parabolic_sin(self.modulo);
89 self.modulo += self.phase_inc;
90 if self.modulo < 0.0 {
91 self.modulo += 1.0;
92 } else if self.modulo > 1.0 {
93 self.modulo -= 1.0;
94 }
95 signal * self.amplitude
96 }
97
98 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
99 let angle = PI - modulo * 2.0 * PI;
100 let y = Self::B * angle + Self::C * angle * abs(angle);
101 Self::P * (y * abs(y) - y) + y
102 }
103}
104
105#[inline]
106fn abs(value: f32) -> f32 {
107 if value < 0.0 {
108 -value
109 } else {
110 value
111 }
112}
113
114#[inline]
115fn bipolar_to_unipolar(value: f32) -> f32 {
116 (value + 1.0) / 2.0
117}
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
new file mode 100644
index 000000000..48eb7d581
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -0,0 +1,115 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{debug, error, info};
6use embassy_executor::Spawner;
7use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
8use embassy_nrf::interrupt;
9use embassy_nrf::pwm::{Prescaler, SimplePwm};
10use {defmt_rtt as _, panic_probe as _};
11
12type Sample = i16;
13
14const NUM_SAMPLES: usize = 500;
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19
20 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
21
22 let sample_rate = master_clock.sample_rate();
23 info!("Sample rate: {}", sample_rate);
24
25 let config = Config::default()
26 .sample_width(SampleWidth::_16bit)
27 .channels(Channels::MonoLeft);
28
29 let irq = interrupt::take!(I2S);
30 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
31 let mut input_stream =
32 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
33
34 // Configure the PWM to use the pins corresponding to the RGB leds
35 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24);
36 pwm.set_prescaler(Prescaler::Div1);
37 pwm.set_max_duty(255);
38
39 let mut rms_online = RmsOnline::<NUM_SAMPLES>::default();
40
41 input_stream.start().await.expect("I2S Start");
42
43 loop {
44 let rms = rms_online.process(input_stream.buffer());
45 let rgb = rgb_from_rms(rms);
46
47 debug!("RMS: {}, RGB: {:?}", rms, rgb);
48 for i in 0..3 {
49 pwm.set_duty(i, rgb[i].into());
50 }
51
52 if let Err(err) = input_stream.receive().await {
53 error!("{}", err);
54 }
55 }
56}
57
58/// RMS from 0.0 until 0.75 will give green with a proportional intensity
59/// RMS from 0.75 until 0.9 will give a blend between orange and red proportionally to the intensity
60/// RMS above 0.9 will give a red with a proportional intensity
61fn rgb_from_rms(rms: f32) -> [u8; 3] {
62 if rms < 0.75 {
63 let intensity = rms / 0.75;
64 [0, (intensity * 165.0) as u8, 0]
65 } else if rms < 0.9 {
66 let intensity = (rms - 0.75) / 0.15;
67 [200, 165 - (165.0 * intensity) as u8, 0]
68 } else {
69 let intensity = (rms - 0.9) / 0.1;
70 [200 + (55.0 * intensity) as u8, 0, 0]
71 }
72}
73
74pub struct RmsOnline<const N: usize> {
75 pub squares: [f32; N],
76 pub head: usize,
77}
78
79impl<const N: usize> Default for RmsOnline<N> {
80 fn default() -> Self {
81 RmsOnline {
82 squares: [0.0; N],
83 head: 0,
84 }
85 }
86}
87
88impl<const N: usize> RmsOnline<N> {
89 pub fn reset(&mut self) {
90 self.squares = [0.0; N];
91 self.head = 0;
92 }
93
94 pub fn process(&mut self, buf: &[Sample]) -> f32 {
95 buf.iter()
96 .for_each(|sample| self.push(*sample as f32 / Sample::SCALE as f32));
97
98 let sum_of_squares = self.squares.iter().fold(0.0, |acc, v| acc + *v);
99 Self::approx_sqrt(sum_of_squares / N as f32)
100 }
101
102 pub fn push(&mut self, signal: f32) {
103 let square = signal * signal;
104 self.squares[self.head] = square;
105 self.head = (self.head + 1) % N;
106 }
107
108 /// Approximated sqrt taken from [micromath]
109 ///
110 /// [micromath]: https://docs.rs/micromath/latest/src/micromath/float/sqrt.rs.html#11-17
111 ///
112 fn approx_sqrt(value: f32) -> f32 {
113 f32::from_bits((value.to_bits() + 0x3f80_0000) >> 1)
114 }
115}
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
new file mode 100644
index 000000000..1b0e8ebc8
--- /dev/null
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -0,0 +1,151 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::f32::consts::PI;
6
7use defmt::{error, info};
8use embassy_executor::Spawner;
9use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S};
10use embassy_nrf::interrupt;
11use {defmt_rtt as _, panic_probe as _};
12
13type Sample = i16;
14
15const NUM_SAMPLES: usize = 50;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20
21 let master_clock: MasterClock = i2s::ExactSampleRate::_50000.into();
22
23 let sample_rate = master_clock.sample_rate();
24 info!("Sample rate: {}", sample_rate);
25
26 let config = Config::default()
27 .sample_width(SampleWidth::_16bit)
28 .channels(Channels::MonoLeft);
29
30 let irq = interrupt::take!(I2S);
31 let buffers = DoubleBuffering::<Sample, NUM_SAMPLES>::new();
32 let mut output_stream =
33 I2S::master(p.I2S, irq, p.P0_25, p.P0_26, p.P0_27, master_clock, config).output(p.P0_28, buffers);
34
35 let mut waveform = Waveform::new(1.0 / sample_rate as f32);
36
37 waveform.process(output_stream.buffer());
38
39 output_stream.start().await.expect("I2S Start");
40
41 loop {
42 waveform.process(output_stream.buffer());
43
44 if let Err(err) = output_stream.send().await {
45 error!("{}", err);
46 }
47 }
48}
49
50struct Waveform {
51 inv_sample_rate: f32,
52 carrier: SineOsc,
53 freq_mod: SineOsc,
54 amp_mod: SineOsc,
55}
56
57impl Waveform {
58 fn new(inv_sample_rate: f32) -> Self {
59 let mut carrier = SineOsc::new();
60 carrier.set_frequency(110.0, inv_sample_rate);
61
62 let mut freq_mod = SineOsc::new();
63 freq_mod.set_frequency(1.0, inv_sample_rate);
64 freq_mod.set_amplitude(1.0);
65
66 let mut amp_mod = SineOsc::new();
67 amp_mod.set_frequency(16.0, inv_sample_rate);
68 amp_mod.set_amplitude(0.5);
69
70 Self {
71 inv_sample_rate,
72 carrier,
73 freq_mod,
74 amp_mod,
75 }
76 }
77
78 fn process(&mut self, buf: &mut [Sample]) {
79 for sample in buf.chunks_mut(1) {
80 let freq_modulation = bipolar_to_unipolar(self.freq_mod.generate());
81 self.carrier
82 .set_frequency(110.0 + 440.0 * freq_modulation, self.inv_sample_rate);
83
84 let amp_modulation = bipolar_to_unipolar(self.amp_mod.generate());
85 self.carrier.set_amplitude(amp_modulation);
86
87 let signal = self.carrier.generate();
88
89 sample[0] = (Sample::SCALE as f32 * signal) as Sample;
90 }
91 }
92}
93
94struct SineOsc {
95 amplitude: f32,
96 modulo: f32,
97 phase_inc: f32,
98}
99
100impl SineOsc {
101 const B: f32 = 4.0 / PI;
102 const C: f32 = -4.0 / (PI * PI);
103 const P: f32 = 0.225;
104
105 pub fn new() -> Self {
106 Self {
107 amplitude: 1.0,
108 modulo: 0.0,
109 phase_inc: 0.0,
110 }
111 }
112
113 pub fn set_frequency(&mut self, freq: f32, inv_sample_rate: f32) {
114 self.phase_inc = freq * inv_sample_rate;
115 }
116
117 pub fn set_amplitude(&mut self, amplitude: f32) {
118 self.amplitude = amplitude;
119 }
120
121 pub fn generate(&mut self) -> f32 {
122 let signal = self.parabolic_sin(self.modulo);
123 self.modulo += self.phase_inc;
124 if self.modulo < 0.0 {
125 self.modulo += 1.0;
126 } else if self.modulo > 1.0 {
127 self.modulo -= 1.0;
128 }
129 signal * self.amplitude
130 }
131
132 fn parabolic_sin(&mut self, modulo: f32) -> f32 {
133 let angle = PI - modulo * 2.0 * PI;
134 let y = Self::B * angle + Self::C * angle * abs(angle);
135 Self::P * (y * abs(y) - y) + y
136 }
137}
138
139#[inline]
140fn abs(value: f32) -> f32 {
141 if value < 0.0 {
142 -value
143 } else {
144 value
145 }
146}
147
148#[inline]
149fn bipolar_to_unipolar(value: f32) -> f32 {
150 (value + 1.0) / 2.0
151}
diff --git a/examples/nrf52840/src/bin/lora_p2p_report.rs b/examples/nrf52840/src/bin/lora_p2p_report.rs
new file mode 100644
index 000000000..d512b83f6
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_report.rs
@@ -0,0 +1,78 @@
1//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
2//! Other nrf/sx126x combinations may work with appropriate pin modifications.
3//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_sense.rs.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![allow(dead_code)]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_lora::sx126x::*;
13use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
14use embassy_nrf::{interrupt, spim};
15use embassy_time::{Duration, Timer};
16use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor};
17use {defmt_rtt as _, panic_probe as _};
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let p = embassy_nrf::init(Default::default());
22 let mut spi_config = spim::Config::default();
23 spi_config.frequency = spim::Frequency::M16;
24
25 let mut radio = {
26 let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
27 let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
28
29 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
30 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
31 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
32 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
33 let antenna_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
34 let antenna_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
35
36 match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await {
37 Ok(r) => r,
38 Err(err) => {
39 info!("Sx126xRadio error = {}", err);
40 return;
41 }
42 }
43 };
44
45 let mut debug_indicator = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
46 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
47
48 start_indicator.set_high();
49 Timer::after(Duration::from_secs(5)).await;
50 start_indicator.set_low();
51
52 loop {
53 let rf_config = RfConfig {
54 frequency: 903900000, // channel in Hz
55 bandwidth: Bandwidth::_250KHz,
56 spreading_factor: SpreadingFactor::_10,
57 coding_rate: CodingRate::_4_8,
58 };
59
60 let mut buffer = [00u8; 100];
61
62 // P2P receive
63 match radio.rx(rf_config, &mut buffer).await {
64 Ok((buffer_len, rx_quality)) => info!(
65 "RX received = {:?} with length = {} rssi = {} snr = {}",
66 &buffer[0..buffer_len],
67 buffer_len,
68 rx_quality.rssi(),
69 rx_quality.snr()
70 ),
71 Err(err) => info!("RX error = {}", err),
72 }
73
74 debug_indicator.set_high();
75 Timer::after(Duration::from_secs(2)).await;
76 debug_indicator.set_low();
77 }
78}
diff --git a/examples/nrf52840/src/bin/lora_p2p_sense.rs b/examples/nrf52840/src/bin/lora_p2p_sense.rs
new file mode 100644
index 000000000..b9768874b
--- /dev/null
+++ b/examples/nrf52840/src/bin/lora_p2p_sense.rs
@@ -0,0 +1,125 @@
1//! This example runs on the RAK4631 WisBlock, which has an nRF52840 MCU and Semtech Sx126x radio.
2//! Other nrf/sx126x combinations may work with appropriate pin modifications.
3//! It demonstates LORA P2P functionality in conjunction with example lora_p2p_report.rs.
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8#![feature(alloc_error_handler)]
9#![allow(incomplete_features)]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_lora::sx126x::*;
14use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pin as _, Pull};
15use embassy_nrf::{interrupt, spim};
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
17use embassy_sync::pubsub::{PubSubChannel, Publisher};
18use embassy_time::{Duration, Timer};
19use lorawan_device::async_device::radio::{Bandwidth, CodingRate, PhyRxTx, RfConfig, SpreadingFactor, TxConfig};
20use {defmt_rtt as _, panic_probe as _, panic_probe as _};
21
22// Message bus: queue of 2, 1 subscriber (Lora P2P), 2 publishers (temperature, motion detection)
23static MESSAGE_BUS: PubSubChannel<CriticalSectionRawMutex, Message, 2, 1, 2> = PubSubChannel::new();
24
25#[derive(Clone, defmt::Format)]
26enum Message {
27 Temperature(i32),
28 MotionDetected,
29}
30
31#[embassy_executor::task]
32async fn temperature_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) {
33 // Publish a fake temperature every 43 seconds, minimizing LORA traffic.
34 loop {
35 Timer::after(Duration::from_secs(43)).await;
36 publisher.publish(Message::Temperature(9)).await;
37 }
38}
39
40#[embassy_executor::task]
41async fn motion_detection_task(publisher: Publisher<'static, CriticalSectionRawMutex, Message, 2, 1, 2>) {
42 // Publish a fake motion detection every 79 seconds, minimizing LORA traffic.
43 loop {
44 Timer::after(Duration::from_secs(79)).await;
45 publisher.publish(Message::MotionDetected).await;
46 }
47}
48
49#[embassy_executor::main]
50async fn main(spawner: Spawner) {
51 let p = embassy_nrf::init(Default::default());
52 // set up to funnel temperature and motion detection events to the Lora Tx task
53 let mut lora_tx_subscriber = unwrap!(MESSAGE_BUS.subscriber());
54 let temperature_publisher = unwrap!(MESSAGE_BUS.publisher());
55 let motion_detection_publisher = unwrap!(MESSAGE_BUS.publisher());
56
57 let mut spi_config = spim::Config::default();
58 spi_config.frequency = spim::Frequency::M16;
59
60 let mut radio = {
61 let irq = interrupt::take!(SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1);
62 let spim = spim::Spim::new(p.TWISPI1, irq, p.P1_11, p.P1_13, p.P1_12, spi_config);
63
64 let cs = Output::new(p.P1_10.degrade(), Level::High, OutputDrive::Standard);
65 let reset = Output::new(p.P1_06.degrade(), Level::High, OutputDrive::Standard);
66 let dio1 = Input::new(p.P1_15.degrade(), Pull::Down);
67 let busy = Input::new(p.P1_14.degrade(), Pull::Down);
68 let antenna_rx = Output::new(p.P1_05.degrade(), Level::Low, OutputDrive::Standard);
69 let antenna_tx = Output::new(p.P1_07.degrade(), Level::Low, OutputDrive::Standard);
70
71 match Sx126xRadio::new(spim, cs, reset, antenna_rx, antenna_tx, dio1, busy, false).await {
72 Ok(r) => r,
73 Err(err) => {
74 info!("Sx126xRadio error = {}", err);
75 return;
76 }
77 }
78 };
79
80 let mut start_indicator = Output::new(p.P1_04, Level::Low, OutputDrive::Standard);
81
82 start_indicator.set_high();
83 Timer::after(Duration::from_secs(5)).await;
84 start_indicator.set_low();
85
86 match radio.lora.sleep().await {
87 Ok(()) => info!("Sleep successful"),
88 Err(err) => info!("Sleep unsuccessful = {}", err),
89 }
90
91 unwrap!(spawner.spawn(temperature_task(temperature_publisher)));
92 unwrap!(spawner.spawn(motion_detection_task(motion_detection_publisher)));
93
94 loop {
95 let message = lora_tx_subscriber.next_message_pure().await;
96
97 let tx_config = TxConfig {
98 // 11 byte maximum payload for Bandwidth 125 and SF 10
99 pw: 10, // up to 20
100 rf: RfConfig {
101 frequency: 903900000, // channel in Hz, not MHz
102 bandwidth: Bandwidth::_250KHz,
103 spreading_factor: SpreadingFactor::_10,
104 coding_rate: CodingRate::_4_8,
105 },
106 };
107
108 let mut buffer = [0x00u8];
109 match message {
110 Message::Temperature(temperature) => buffer[0] = temperature as u8,
111 Message::MotionDetected => buffer[0] = 0x01u8,
112 };
113
114 // unencrypted
115 match radio.tx(tx_config, &buffer).await {
116 Ok(ret_val) => info!("TX ret_val = {}", ret_val),
117 Err(err) => info!("TX error = {}", err),
118 }
119
120 match radio.lora.sleep().await {
121 Ok(()) => info!("Sleep successful"),
122 Err(err) => info!("Sleep unsuccessful = {}", err),
123 }
124 }
125}
diff --git a/examples/nrf52840/src/bin/manually_create_executor.rs b/examples/nrf52840/src/bin/manually_create_executor.rs
new file mode 100644
index 000000000..12ce660f9
--- /dev/null
+++ b/examples/nrf52840/src/bin/manually_create_executor.rs
@@ -0,0 +1,49 @@
1// This example showcases how to manually create an executor.
2// This is what the #[embassy::main] macro does behind the scenes.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use cortex_m_rt::entry;
9use defmt::{info, unwrap};
10use embassy_executor::Executor;
11use embassy_time::{Duration, Timer};
12use static_cell::StaticCell;
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::task]
16async fn run1() {
17 loop {
18 info!("BIG INFREQUENT TICK");
19 Timer::after(Duration::from_ticks(64000)).await;
20 }
21}
22
23#[embassy_executor::task]
24async fn run2() {
25 loop {
26 info!("tick");
27 Timer::after(Duration::from_ticks(13000)).await;
28 }
29}
30
31static EXECUTOR: StaticCell<Executor> = StaticCell::new();
32
33#[entry]
34fn main() -> ! {
35 info!("Hello World!");
36
37 let _p = embassy_nrf::init(Default::default());
38
39 // Create the executor and put it in a StaticCell, because `run` needs `&'static mut Executor`.
40 let executor = EXECUTOR.init(Executor::new());
41
42 // Run it.
43 // `run` calls the closure then runs the executor forever. It never returns.
44 executor.run(|spawner| {
45 // Here we get access to a spawner to spawn the initial tasks.
46 unwrap!(spawner.spawn(run1()));
47 unwrap!(spawner.spawn(run2()));
48 });
49}
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
new file mode 100644
index 000000000..25806ae48
--- /dev/null
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -0,0 +1,140 @@
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(type_alias_impl_trait)]
59
60use cortex_m_rt::entry;
61use defmt::{info, unwrap};
62use embassy_nrf::executor::{Executor, InterruptExecutor};
63use embassy_nrf::interrupt;
64use embassy_nrf::interrupt::InterruptExt;
65use embassy_time::{Duration, Instant, Timer};
66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _};
68
69#[embassy_executor::task]
70async fn run_high() {
71 loop {
72 info!(" [high] tick!");
73 Timer::after(Duration::from_ticks(27374)).await;
74 }
75}
76
77#[embassy_executor::task]
78async fn run_med() {
79 loop {
80 let start = Instant::now();
81 info!(" [med] Starting long computation");
82
83 // Spin-wait to simulate a long CPU computation
84 cortex_m::asm::delay(32_000_000); // ~1 second
85
86 let end = Instant::now();
87 let ms = end.duration_since(start).as_ticks() / 33;
88 info!(" [med] done in {} ms", ms);
89
90 Timer::after(Duration::from_ticks(23421)).await;
91 }
92}
93
94#[embassy_executor::task]
95async fn run_low() {
96 loop {
97 let start = Instant::now();
98 info!("[low] Starting long computation");
99
100 // Spin-wait to simulate a long CPU computation
101 cortex_m::asm::delay(64_000_000); // ~2 seconds
102
103 let end = Instant::now();
104 let ms = end.duration_since(start).as_ticks() / 33;
105 info!("[low] done in {} ms", ms);
106
107 Timer::after(Duration::from_ticks(32983)).await;
108 }
109}
110
111static EXECUTOR_HIGH: StaticCell<InterruptExecutor<interrupt::SWI1_EGU1>> = StaticCell::new();
112static EXECUTOR_MED: StaticCell<InterruptExecutor<interrupt::SWI0_EGU0>> = StaticCell::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114
115#[entry]
116fn main() -> ! {
117 info!("Hello World!");
118
119 let _p = embassy_nrf::init(Default::default());
120
121 // High-priority executor: SWI1_EGU1, priority level 6
122 let irq = interrupt::take!(SWI1_EGU1);
123 irq.set_priority(interrupt::Priority::P6);
124 let executor = EXECUTOR_HIGH.init(InterruptExecutor::new(irq));
125 let spawner = executor.start();
126 unwrap!(spawner.spawn(run_high()));
127
128 // Medium-priority executor: SWI0_EGU0, priority level 7
129 let irq = interrupt::take!(SWI0_EGU0);
130 irq.set_priority(interrupt::Priority::P7);
131 let executor = EXECUTOR_MED.init(InterruptExecutor::new(irq));
132 let spawner = executor.start();
133 unwrap!(spawner.spawn(run_med()));
134
135 // Low priority executor: runs in thread mode, using WFE/SEV
136 let executor = EXECUTOR_LOW.init(Executor::new());
137 executor.run(|spawner| {
138 unwrap!(spawner.spawn(run_low()));
139 });
140}
diff --git a/examples/nrf52840/src/bin/mutex.rs b/examples/nrf52840/src/bin/mutex.rs
new file mode 100644
index 000000000..c402c6ba1
--- /dev/null
+++ b/examples/nrf52840/src/bin/mutex.rs
@@ -0,0 +1,42 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
8use embassy_sync::mutex::Mutex;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12static MUTEX: Mutex<ThreadModeRawMutex, u32> = Mutex::new(0);
13
14#[embassy_executor::task]
15async fn my_task() {
16 loop {
17 {
18 let mut m = MUTEX.lock().await;
19 info!("start long operation");
20 *m += 1000;
21
22 // Hold the mutex for a long time.
23 Timer::after(Duration::from_secs(1)).await;
24 info!("end long operation: count = {}", *m);
25 }
26
27 Timer::after(Duration::from_secs(1)).await;
28 }
29}
30
31#[embassy_executor::main]
32async fn main(spawner: Spawner) {
33 let _p = embassy_nrf::init(Default::default());
34 unwrap!(spawner.spawn(my_task()));
35
36 loop {
37 Timer::after(Duration::from_millis(300)).await;
38 let mut m = MUTEX.lock().await;
39 *m += 1;
40 info!("short operation: count = {}", *m);
41 }
42}
diff --git a/examples/nrf52840/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs
new file mode 100644
index 000000000..75d090fbb
--- /dev/null
+++ b/examples/nrf52840/src/bin/nvmc.rs
@@ -0,0 +1,43 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_nrf::nvmc::Nvmc;
8use embassy_time::{Duration, Timer};
9use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default());
15 info!("Hello NVMC!");
16
17 // probe-run breaks without this, I'm not sure why.
18 Timer::after(Duration::from_secs(1)).await;
19
20 let mut f = Nvmc::new(p.NVMC);
21 const ADDR: u32 = 0x80000;
22
23 info!("Reading...");
24 let mut buf = [0u8; 4];
25 unwrap!(f.read(ADDR, &mut buf));
26 info!("Read: {=[u8]:x}", buf);
27
28 info!("Erasing...");
29 unwrap!(f.erase(ADDR, ADDR + 4096));
30
31 info!("Reading...");
32 let mut buf = [0u8; 4];
33 unwrap!(f.read(ADDR, &mut buf));
34 info!("Read: {=[u8]:x}", buf);
35
36 info!("Writing...");
37 unwrap!(f.write(ADDR, &[1, 2, 3, 4]));
38
39 info!("Reading...");
40 let mut buf = [0u8; 4];
41 unwrap!(f.read(ADDR, &mut buf));
42 info!("Read: {=[u8]:x}", buf);
43}
diff --git a/examples/nrf52840/src/bin/pdm.rs b/examples/nrf52840/src/bin/pdm.rs
new file mode 100644
index 000000000..7388580fb
--- /dev/null
+++ b/examples/nrf52840/src/bin/pdm.rs
@@ -0,0 +1,33 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::pdm::{Config, Pdm};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_p: Spawner) {
14 let p = embassy_nrf::init(Default::default());
15 let config = Config::default();
16 let mut pdm = Pdm::new(p.PDM, interrupt::take!(PDM), p.P0_01, p.P0_00, config);
17
18 loop {
19 pdm.start().await;
20
21 // wait some time till the microphon settled
22 Timer::after(Duration::from_millis(1000)).await;
23
24 const SAMPLES: usize = 2048;
25 let mut buf = [0i16; SAMPLES];
26 pdm.sample(&mut buf).await.unwrap();
27
28 info!("samples: {:?}", &buf);
29
30 pdm.stop().await;
31 Timer::after(Duration::from_millis(100)).await;
32 }
33}
diff --git a/examples/nrf52840/src/bin/ppi.rs b/examples/nrf52840/src/bin/ppi.rs
new file mode 100644
index 000000000..d74ce4064
--- /dev/null
+++ b/examples/nrf52840/src/bin/ppi.rs
@@ -0,0 +1,73 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::future::pending;
6
7use defmt::info;
8use embassy_executor::Spawner;
9use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
10use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
11use embassy_nrf::ppi::Ppi;
12use gpiote::{OutputChannel, OutputChannelPolarity};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_nrf::init(Default::default());
18 info!("Starting!");
19
20 let button1 = InputChannel::new(
21 p.GPIOTE_CH0,
22 Input::new(p.P0_11, Pull::Up),
23 InputChannelPolarity::HiToLo,
24 );
25 let button2 = InputChannel::new(
26 p.GPIOTE_CH1,
27 Input::new(p.P0_12, Pull::Up),
28 InputChannelPolarity::HiToLo,
29 );
30 let button3 = InputChannel::new(
31 p.GPIOTE_CH2,
32 Input::new(p.P0_24, Pull::Up),
33 InputChannelPolarity::HiToLo,
34 );
35 let button4 = InputChannel::new(
36 p.GPIOTE_CH3,
37 Input::new(p.P0_25, Pull::Up),
38 InputChannelPolarity::HiToLo,
39 );
40
41 let led1 = OutputChannel::new(
42 p.GPIOTE_CH4,
43 Output::new(p.P0_13, Level::Low, OutputDrive::Standard),
44 OutputChannelPolarity::Toggle,
45 );
46
47 let led2 = OutputChannel::new(
48 p.GPIOTE_CH5,
49 Output::new(p.P0_14, Level::Low, OutputDrive::Standard),
50 OutputChannelPolarity::Toggle,
51 );
52
53 let mut ppi = Ppi::new_one_to_one(p.PPI_CH0, button1.event_in(), led1.task_out());
54 ppi.enable();
55
56 let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button2.event_in(), led1.task_clr());
57 ppi.enable();
58
59 let mut ppi = Ppi::new_one_to_one(p.PPI_CH2, button3.event_in(), led1.task_set());
60 ppi.enable();
61
62 let mut ppi = Ppi::new_one_to_two(p.PPI_CH3, button4.event_in(), led1.task_out(), led2.task_out());
63 ppi.enable();
64
65 info!("PPI setup!");
66 info!("Press button 1 to toggle LED 1");
67 info!("Press button 2 to turn on LED 1");
68 info!("Press button 3 to turn off LED 1");
69 info!("Press button 4 to toggle LEDs 1 and 2");
70
71 // Block forever so the above drivers don't get dropped
72 pending::<()>().await;
73}
diff --git a/examples/nrf52840/src/bin/pubsub.rs b/examples/nrf52840/src/bin/pubsub.rs
new file mode 100644
index 000000000..688e6d075
--- /dev/null
+++ b/examples/nrf52840/src/bin/pubsub.rs
@@ -0,0 +1,107 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::unwrap;
6use embassy_executor::Spawner;
7use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
8use embassy_sync::pubsub::{DynSubscriber, PubSubChannel, Subscriber};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12/// Create the message bus. It has a queue of 4, supports 3 subscribers and 1 publisher
13static MESSAGE_BUS: PubSubChannel<ThreadModeRawMutex, Message, 4, 3, 1> = PubSubChannel::new();
14
15#[derive(Clone, defmt::Format)]
16enum Message {
17 A,
18 B,
19 C,
20}
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 let _p = embassy_nrf::init(Default::default());
25 defmt::info!("Hello World!");
26
27 // It's good to set up the subscribers before publishing anything.
28 // A subscriber will only yield messages that have been published after its creation.
29
30 spawner.must_spawn(fast_logger(unwrap!(MESSAGE_BUS.subscriber())));
31 spawner.must_spawn(slow_logger(unwrap!(MESSAGE_BUS.dyn_subscriber())));
32 spawner.must_spawn(slow_logger_pure(unwrap!(MESSAGE_BUS.dyn_subscriber())));
33
34 // Get a publisher
35 let message_publisher = unwrap!(MESSAGE_BUS.publisher());
36 // We can't get more (normal) publishers
37 // We can have an infinite amount of immediate publishers. They can't await a publish, only do an immediate publish
38 defmt::assert!(MESSAGE_BUS.publisher().is_err());
39
40 let mut index = 0;
41 loop {
42 Timer::after(Duration::from_millis(500)).await;
43
44 let message = match index % 3 {
45 0 => Message::A,
46 1 => Message::B,
47 2..=u32::MAX => Message::C,
48 };
49
50 // We publish immediately and don't await anything.
51 // If the queue is full, it will cause the oldest message to not be received by some/all subscribers
52 message_publisher.publish_immediate(message);
53
54 // Try to comment out the last one and uncomment this line below.
55 // The behaviour will change:
56 // - The subscribers won't miss any messages any more
57 // - Trying to publish now has some wait time when the queue is full
58
59 // message_publisher.publish(message).await;
60
61 index += 1;
62 }
63}
64
65/// A logger task that just awaits the messages it receives
66///
67/// This takes the generic `Subscriber`. This is most performant, but requires you to write down all of the generics
68#[embassy_executor::task]
69async fn fast_logger(mut messages: Subscriber<'static, ThreadModeRawMutex, Message, 4, 3, 1>) {
70 loop {
71 let message = messages.next_message().await;
72 defmt::info!("Received message at fast logger: {:?}", message);
73 }
74}
75
76/// A logger task that awaits the messages, but also does some other work.
77/// Because of this, depeding on how the messages were published, the subscriber might miss some messages
78///
79/// This takes the dynamic `DynSubscriber`. This is not as performant as the generic version, but let's you ignore some of the generics
80#[embassy_executor::task]
81async fn slow_logger(mut messages: DynSubscriber<'static, Message>) {
82 loop {
83 // Do some work
84 Timer::after(Duration::from_millis(2000)).await;
85
86 // If the publisher has used the `publish_immediate` function, then we may receive a lag message here
87 let message = messages.next_message().await;
88 defmt::info!("Received message at slow logger: {:?}", message);
89
90 // If the previous one was a lag message, then we should receive the next message here immediately
91 let message = messages.next_message().await;
92 defmt::info!("Received message at slow logger: {:?}", message);
93 }
94}
95
96/// Same as `slow_logger` but it ignores lag results
97#[embassy_executor::task]
98async fn slow_logger_pure(mut messages: DynSubscriber<'static, Message>) {
99 loop {
100 // Do some work
101 Timer::after(Duration::from_millis(2000)).await;
102
103 // Instead of receiving lags here, we just ignore that and read the next message
104 let message = messages.next_message_pure().await;
105 defmt::info!("Received message at slow logger pure: {:?}", message);
106 }
107}
diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs
new file mode 100644
index 000000000..1698c0bc8
--- /dev/null
+++ b/examples/nrf52840/src/bin/pwm.rs
@@ -0,0 +1,89 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::pwm::{Prescaler, SimplePwm};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11// for i in range(1024): print(int((math.sin(i/512*math.pi)*0.4+0.5)**2*32767), ', ', end='')
12static DUTY: [u16; 1024] = [
13 8191, 8272, 8353, 8434, 8516, 8598, 8681, 8764, 8847, 8931, 9015, 9099, 9184, 9269, 9354, 9440, 9526, 9613, 9700,
14 9787, 9874, 9962, 10050, 10139, 10227, 10316, 10406, 10495, 10585, 10675, 10766, 10857, 10948, 11039, 11131, 11223,
15 11315, 11407, 11500, 11592, 11685, 11779, 11872, 11966, 12060, 12154, 12248, 12343, 12438, 12533, 12628, 12723,
16 12818, 12914, 13010, 13106, 13202, 13298, 13394, 13491, 13587, 13684, 13781, 13878, 13975, 14072, 14169, 14266,
17 14364, 14461, 14558, 14656, 14754, 14851, 14949, 15046, 15144, 15242, 15339, 15437, 15535, 15632, 15730, 15828,
18 15925, 16023, 16120, 16218, 16315, 16412, 16510, 16607, 16704, 16801, 16898, 16995, 17091, 17188, 17284, 17380,
19 17477, 17572, 17668, 17764, 17859, 17955, 18050, 18145, 18239, 18334, 18428, 18522, 18616, 18710, 18803, 18896,
20 18989, 19082, 19174, 19266, 19358, 19449, 19540, 19631, 19722, 19812, 19902, 19991, 20081, 20169, 20258, 20346,
21 20434, 20521, 20608, 20695, 20781, 20867, 20952, 21037, 21122, 21206, 21290, 21373, 21456, 21538, 21620, 21701,
22 21782, 21863, 21943, 22022, 22101, 22179, 22257, 22335, 22412, 22488, 22564, 22639, 22714, 22788, 22861, 22934,
23 23007, 23079, 23150, 23220, 23290, 23360, 23429, 23497, 23564, 23631, 23698, 23763, 23828, 23892, 23956, 24019,
24 24081, 24143, 24204, 24264, 24324, 24383, 24441, 24499, 24555, 24611, 24667, 24721, 24775, 24828, 24881, 24933,
25 24983, 25034, 25083, 25132, 25180, 25227, 25273, 25319, 25363, 25407, 25451, 25493, 25535, 25575, 25615, 25655,
26 25693, 25731, 25767, 25803, 25838, 25873, 25906, 25939, 25971, 26002, 26032, 26061, 26089, 26117, 26144, 26170,
27 26195, 26219, 26242, 26264, 26286, 26307, 26327, 26346, 26364, 26381, 26397, 26413, 26427, 26441, 26454, 26466,
28 26477, 26487, 26496, 26505, 26512, 26519, 26525, 26530, 26534, 26537, 26539, 26540, 26541, 26540, 26539, 26537,
29 26534, 26530, 26525, 26519, 26512, 26505, 26496, 26487, 26477, 26466, 26454, 26441, 26427, 26413, 26397, 26381,
30 26364, 26346, 26327, 26307, 26286, 26264, 26242, 26219, 26195, 26170, 26144, 26117, 26089, 26061, 26032, 26002,
31 25971, 25939, 25906, 25873, 25838, 25803, 25767, 25731, 25693, 25655, 25615, 25575, 25535, 25493, 25451, 25407,
32 25363, 25319, 25273, 25227, 25180, 25132, 25083, 25034, 24983, 24933, 24881, 24828, 24775, 24721, 24667, 24611,
33 24555, 24499, 24441, 24383, 24324, 24264, 24204, 24143, 24081, 24019, 23956, 23892, 23828, 23763, 23698, 23631,
34 23564, 23497, 23429, 23360, 23290, 23220, 23150, 23079, 23007, 22934, 22861, 22788, 22714, 22639, 22564, 22488,
35 22412, 22335, 22257, 22179, 22101, 22022, 21943, 21863, 21782, 21701, 21620, 21538, 21456, 21373, 21290, 21206,
36 21122, 21037, 20952, 20867, 20781, 20695, 20608, 20521, 20434, 20346, 20258, 20169, 20081, 19991, 19902, 19812,
37 19722, 19631, 19540, 19449, 19358, 19266, 19174, 19082, 18989, 18896, 18803, 18710, 18616, 18522, 18428, 18334,
38 18239, 18145, 18050, 17955, 17859, 17764, 17668, 17572, 17477, 17380, 17284, 17188, 17091, 16995, 16898, 16801,
39 16704, 16607, 16510, 16412, 16315, 16218, 16120, 16023, 15925, 15828, 15730, 15632, 15535, 15437, 15339, 15242,
40 15144, 15046, 14949, 14851, 14754, 14656, 14558, 14461, 14364, 14266, 14169, 14072, 13975, 13878, 13781, 13684,
41 13587, 13491, 13394, 13298, 13202, 13106, 13010, 12914, 12818, 12723, 12628, 12533, 12438, 12343, 12248, 12154,
42 12060, 11966, 11872, 11779, 11685, 11592, 11500, 11407, 11315, 11223, 11131, 11039, 10948, 10857, 10766, 10675,
43 10585, 10495, 10406, 10316, 10227, 10139, 10050, 9962, 9874, 9787, 9700, 9613, 9526, 9440, 9354, 9269, 9184, 9099,
44 9015, 8931, 8847, 8764, 8681, 8598, 8516, 8434, 8353, 8272, 8191, 8111, 8031, 7952, 7873, 7794, 7716, 7638, 7561,
45 7484, 7407, 7331, 7255, 7180, 7105, 7031, 6957, 6883, 6810, 6738, 6665, 6594, 6522, 6451, 6381, 6311, 6241, 6172,
46 6104, 6036, 5968, 5901, 5834, 5767, 5702, 5636, 5571, 5507, 5443, 5379, 5316, 5253, 5191, 5130, 5068, 5008, 4947,
47 4888, 4828, 4769, 4711, 4653, 4596, 4539, 4482, 4426, 4371, 4316, 4261, 4207, 4153, 4100, 4047, 3995, 3943, 3892,
48 3841, 3791, 3741, 3691, 3642, 3594, 3546, 3498, 3451, 3404, 3358, 3312, 3267, 3222, 3178, 3134, 3090, 3047, 3005,
49 2962, 2921, 2879, 2839, 2798, 2758, 2719, 2680, 2641, 2603, 2565, 2528, 2491, 2454, 2418, 2382, 2347, 2312, 2278,
50 2244, 2210, 2177, 2144, 2112, 2080, 2048, 2017, 1986, 1956, 1926, 1896, 1867, 1838, 1810, 1781, 1754, 1726, 1699,
51 1673, 1646, 1620, 1595, 1570, 1545, 1520, 1496, 1472, 1449, 1426, 1403, 1380, 1358, 1336, 1315, 1294, 1273, 1252,
52 1232, 1212, 1192, 1173, 1154, 1135, 1117, 1099, 1081, 1063, 1046, 1029, 1012, 996, 980, 964, 948, 933, 918, 903,
53 888, 874, 860, 846, 833, 819, 806, 793, 781, 768, 756, 744, 733, 721, 710, 699, 688, 677, 667, 657, 647, 637, 627,
54 618, 609, 599, 591, 582, 574, 565, 557, 549, 541, 534, 526, 519, 512, 505, 498, 492, 485, 479, 473, 467, 461, 455,
55 450, 444, 439, 434, 429, 424, 419, 415, 410, 406, 402, 398, 394, 390, 386, 383, 379, 376, 373, 370, 367, 364, 361,
56 359, 356, 354, 351, 349, 347, 345, 343, 342, 340, 338, 337, 336, 334, 333, 332, 331, 330, 330, 329, 328, 328, 328,
57 327, 327, 327, 327, 327, 328, 328, 328, 329, 330, 330, 331, 332, 333, 334, 336, 337, 338, 340, 342, 343, 345, 347,
58 349, 351, 354, 356, 359, 361, 364, 367, 370, 373, 376, 379, 383, 386, 390, 394, 398, 402, 406, 410, 415, 419, 424,
59 429, 434, 439, 444, 450, 455, 461, 467, 473, 479, 485, 492, 498, 505, 512, 519, 526, 534, 541, 549, 557, 565, 574,
60 582, 591, 599, 609, 618, 627, 637, 647, 657, 667, 677, 688, 699, 710, 721, 733, 744, 756, 768, 781, 793, 806, 819,
61 833, 846, 860, 874, 888, 903, 918, 933, 948, 964, 980, 996, 1012, 1029, 1046, 1063, 1081, 1099, 1117, 1135, 1154,
62 1173, 1192, 1212, 1232, 1252, 1273, 1294, 1315, 1336, 1358, 1380, 1403, 1426, 1449, 1472, 1496, 1520, 1545, 1570,
63 1595, 1620, 1646, 1673, 1699, 1726, 1754, 1781, 1810, 1838, 1867, 1896, 1926, 1956, 1986, 2017, 2048, 2080, 2112,
64 2144, 2177, 2210, 2244, 2278, 2312, 2347, 2382, 2418, 2454, 2491, 2528, 2565, 2603, 2641, 2680, 2719, 2758, 2798,
65 2839, 2879, 2921, 2962, 3005, 3047, 3090, 3134, 3178, 3222, 3267, 3312, 3358, 3404, 3451, 3498, 3546, 3594, 3642,
66 3691, 3741, 3791, 3841, 3892, 3943, 3995, 4047, 4100, 4153, 4207, 4261, 4316, 4371, 4426, 4482, 4539, 4596, 4653,
67 4711, 4769, 4828, 4888, 4947, 5008, 5068, 5130, 5191, 5253, 5316, 5379, 5443, 5507, 5571, 5636, 5702, 5767, 5834,
68 5901, 5968, 6036, 6104, 6172, 6241, 6311, 6381, 6451, 6522, 6594, 6665, 6738, 6810, 6883, 6957, 7031, 7105, 7180,
69 7255, 7331, 7407, 7484, 7561, 7638, 7716, 7794, 7873, 7952, 8031, 8111,
70];
71
72#[embassy_executor::main]
73async fn main(_spawner: Spawner) {
74 let p = embassy_nrf::init(Default::default());
75 let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15);
76 pwm.set_prescaler(Prescaler::Div1);
77 pwm.set_max_duty(32767);
78 info!("pwm initialized!");
79
80 let mut i = 0;
81 loop {
82 i += 1;
83 pwm.set_duty(0, DUTY[i % 1024]);
84 pwm.set_duty(1, DUTY[(i + 256) % 1024]);
85 pwm.set_duty(2, DUTY[(i + 512) % 1024]);
86 pwm.set_duty(3, DUTY[(i + 768) % 1024]);
87 Timer::after(Duration::from_millis(3)).await;
88 }
89}
diff --git a/examples/nrf52840/src/bin/pwm_double_sequence.rs b/examples/nrf52840/src/bin/pwm_double_sequence.rs
new file mode 100644
index 000000000..16e50e909
--- /dev/null
+++ b/examples/nrf52840/src/bin/pwm_double_sequence.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::pwm::{
8 Config, Prescaler, Sequence, SequenceConfig, SequenceMode, SequencePwm, Sequencer, StartSequence,
9};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16 let seq_words_0: [u16; 5] = [1000, 250, 100, 50, 0];
17 let seq_words_1: [u16; 4] = [50, 100, 250, 1000];
18
19 let mut config = Config::default();
20 config.prescaler = Prescaler::Div128;
21 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
22 // but say we want to hold the value for 5000ms
23 // so we want to repeat our value as many times as necessary until 5000ms passes
24 // want 5000/8 = 625 periods total to occur, so 624 (we get the one period for free remember)
25 let mut seq_config = SequenceConfig::default();
26 seq_config.refresh = 624;
27 // thus our sequence takes 5 * 5000ms or 25 seconds
28
29 let mut pwm = unwrap!(SequencePwm::new_1ch(p.PWM0, p.P0_13, config));
30
31 let sequence_0 = Sequence::new(&seq_words_0, seq_config.clone());
32 let sequence_1 = Sequence::new(&seq_words_1, seq_config);
33 let sequencer = Sequencer::new(&mut pwm, sequence_0, Some(sequence_1));
34 unwrap!(sequencer.start(StartSequence::Zero, SequenceMode::Loop(1)));
35
36 // we can abort a sequence if we need to before its complete with pwm.stop()
37 // or stop is also implicitly called when the pwm peripheral is dropped
38 // when it goes out of scope
39 Timer::after(Duration::from_millis(40000)).await;
40 info!("pwm stopped early!");
41}
diff --git a/examples/nrf52840/src/bin/pwm_sequence.rs b/examples/nrf52840/src/bin/pwm_sequence.rs
new file mode 100644
index 000000000..b9aca9aaa
--- /dev/null
+++ b/examples/nrf52840/src/bin/pwm_sequence.rs
@@ -0,0 +1,36 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::pwm::{Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 let seq_words: [u16; 5] = [1000, 250, 100, 50, 0];
15
16 let mut config = Config::default();
17 config.prescaler = Prescaler::Div128;
18 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
19 // but say we want to hold the value for 5000ms
20 // so we want to repeat our value as many times as necessary until 5000ms passes
21 // want 5000/8 = 625 periods total to occur, so 624 (we get the one period for free remember)
22 let mut seq_config = SequenceConfig::default();
23 seq_config.refresh = 624;
24 // thus our sequence takes 5 * 5000ms or 25 seconds
25
26 let mut pwm = unwrap!(SequencePwm::new_1ch(p.PWM0, p.P0_13, config,));
27
28 let sequencer = SingleSequencer::new(&mut pwm, &seq_words, seq_config);
29 unwrap!(sequencer.start(SingleSequenceMode::Times(1)));
30
31 // we can abort a sequence if we need to before its complete with pwm.stop()
32 // or stop is also implicitly called when the pwm peripheral is dropped
33 // when it goes out of scope
34 Timer::after(Duration::from_millis(20000)).await;
35 info!("pwm stopped early!");
36}
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
new file mode 100644
index 000000000..6594fa348
--- /dev/null
+++ b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
@@ -0,0 +1,67 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::future::pending;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nrf::gpio::{Input, Pull};
10use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
11use embassy_nrf::ppi::Ppi;
12use embassy_nrf::pwm::{Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_nrf::init(Default::default());
18 let seq_words: [u16; 5] = [1000, 250, 100, 50, 0];
19
20 let mut config = Config::default();
21 config.prescaler = Prescaler::Div128;
22 // 1 period is 1000 * (128/16mhz = 0.000008s = 0.008ms) = 8us
23 // but say we want to hold the value for 250ms 250ms/8 = 31.25 periods
24 // so round to 31 - 1 (we get the one period for free remember)
25 // thus our sequence takes 5 * 250ms or 1.25 seconds
26 let mut seq_config = SequenceConfig::default();
27 seq_config.refresh = 30;
28
29 let mut pwm = unwrap!(SequencePwm::new_1ch(p.PWM0, p.P0_13, config));
30
31 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work
32 // so its going to have to start running in order load the configuration
33
34 let button1 = InputChannel::new(
35 p.GPIOTE_CH0,
36 Input::new(p.P0_11, Pull::Up),
37 InputChannelPolarity::HiToLo,
38 );
39
40 let button2 = InputChannel::new(
41 p.GPIOTE_CH1,
42 Input::new(p.P0_12, Pull::Up),
43 InputChannelPolarity::HiToLo,
44 );
45
46 // messing with the pwm tasks is ill advised
47 // Times::Ininite and Times even are seq0, Times odd is seq1
48 let start = unsafe { pwm.task_start_seq0() };
49 let stop = unsafe { pwm.task_stop() };
50
51 let sequencer = SingleSequencer::new(&mut pwm, &seq_words, seq_config);
52 unwrap!(sequencer.start(SingleSequenceMode::Infinite));
53
54 let mut ppi = Ppi::new_one_to_one(p.PPI_CH1, button1.event_in(), start);
55 ppi.enable();
56
57 let mut ppi2 = Ppi::new_one_to_one(p.PPI_CH0, button2.event_in(), stop);
58 ppi2.enable();
59
60 info!("PPI setup!");
61 info!("Press button 1 to start LED 1");
62 info!("Press button 2 to stop LED 1");
63 info!("Note! task_stop stops the sequence, but not the pin output");
64
65 // Block forever so the above drivers don't get dropped
66 pending::<()>().await;
67}
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
new file mode 100644
index 000000000..711c8a17b
--- /dev/null
+++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
@@ -0,0 +1,75 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::pwm::{
8 Config, Prescaler, SequenceConfig, SequenceLoad, SequencePwm, SingleSequenceMode, SingleSequencer,
9};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13// WS2812B LED light demonstration. Drives just one light.
14// The following reference on WS2812B may be of use:
15// https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf.
16// This demo lights up a single LED in blue. It then proceeds
17// to pulsate the LED rapidly.
18
19// In the following declarations, setting the high bit tells the PWM
20// to reverse polarity, which is what the WS2812B expects.
21
22const T1H: u16 = 0x8000 | 13; // Duty = 13/20 ticks (0.8us/1.25us) for a 1
23const T0H: u16 = 0x8000 | 7; // Duty 7/20 ticks (0.4us/1.25us) for a 0
24const RES: u16 = 0x8000;
25
26// Provides data to a WS2812b (Neopixel) LED and makes it go blue. The data
27// line is assumed to be P1_05.
28#[embassy_executor::main]
29async fn main(_spawner: Spawner) {
30 let p = embassy_nrf::init(Default::default());
31 let mut config = Config::default();
32 config.sequence_load = SequenceLoad::Common;
33 config.prescaler = Prescaler::Div1;
34 config.max_duty = 20; // 1.25us (1s / 16Mhz * 20)
35 let mut pwm = unwrap!(SequencePwm::new_1ch(p.PWM0, p.P1_05, config));
36
37 // Declare the bits of 24 bits in a buffer we'll be
38 // mutating later.
39 let mut seq_words = [
40 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // G
41 T0H, T0H, T0H, T0H, T0H, T0H, T0H, T0H, // R
42 T1H, T1H, T1H, T1H, T1H, T1H, T1H, T1H, // B
43 RES,
44 ];
45 let mut seq_config = SequenceConfig::default();
46 seq_config.end_delay = 799; // 50us (20 ticks * 40) - 1 tick because we've already got one RES;
47
48 let mut color_bit = 16;
49 let mut bit_value = T0H;
50
51 loop {
52 let sequences = SingleSequencer::new(&mut pwm, &seq_words, seq_config.clone());
53 unwrap!(sequences.start(SingleSequenceMode::Times(1)));
54
55 Timer::after(Duration::from_millis(50)).await;
56
57 if bit_value == T0H {
58 if color_bit == 20 {
59 bit_value = T1H;
60 } else {
61 color_bit += 1;
62 }
63 } else {
64 if color_bit == 16 {
65 bit_value = T0H;
66 } else {
67 color_bit -= 1;
68 }
69 }
70
71 drop(sequences);
72
73 seq_words[color_bit] = bit_value;
74 }
75}
diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs
new file mode 100644
index 000000000..19228f433
--- /dev/null
+++ b/examples/nrf52840/src/bin/pwm_servo.rs
@@ -0,0 +1,47 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::pwm::{Prescaler, SimplePwm};
8use embassy_time::{Duration, Timer};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05);
15 // sg90 microervo requires 50hz or 20ms period
16 // set_period can only set down to 125khz so we cant use it directly
17 // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top
18 pwm.set_prescaler(Prescaler::Div128);
19 pwm.set_max_duty(2500);
20 info!("pwm initialized!");
21
22 Timer::after(Duration::from_millis(5000)).await;
23
24 // 1ms 0deg (1/.008=125), 1.5ms 90deg (1.5/.008=187.5), 2ms 180deg (2/.008=250),
25 loop {
26 info!("45 deg");
27 // poor mans inverting, subtract our value from max_duty
28 pwm.set_duty(0, 2500 - 156);
29 Timer::after(Duration::from_millis(5000)).await;
30
31 info!("90 deg");
32 pwm.set_duty(0, 2500 - 187);
33 Timer::after(Duration::from_millis(5000)).await;
34
35 info!("135 deg");
36 pwm.set_duty(0, 2500 - 218);
37 Timer::after(Duration::from_millis(5000)).await;
38
39 info!("180 deg");
40 pwm.set_duty(0, 2500 - 250);
41 Timer::after(Duration::from_millis(5000)).await;
42
43 info!("0 deg");
44 pwm.set_duty(0, 2500 - 125);
45 Timer::after(Duration::from_millis(5000)).await;
46 }
47}
diff --git a/examples/nrf52840/src/bin/qdec.rs b/examples/nrf52840/src/bin/qdec.rs
new file mode 100644
index 000000000..600bba07a
--- /dev/null
+++ b/examples/nrf52840/src/bin/qdec.rs
@@ -0,0 +1,24 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::qdec::{self, Qdec};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 let irq = interrupt::take!(QDEC);
15 let config = qdec::Config::default();
16 let mut rotary_enc = Qdec::new(p.QDEC, irq, p.P0_31, p.P0_30, config);
17
18 info!("Turn rotary encoder!");
19 let mut value = 0;
20 loop {
21 value += rotary_enc.read().await;
22 info!("Value: {}", value);
23 }
24}
diff --git a/examples/nrf52840/src/bin/qspi.rs b/examples/nrf52840/src/bin/qspi.rs
new file mode 100644
index 000000000..bdcf710b8
--- /dev/null
+++ b/examples/nrf52840/src/bin/qspi.rs
@@ -0,0 +1,76 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{assert_eq, info, unwrap};
6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, qspi};
8use {defmt_rtt as _, panic_probe as _};
9
10const PAGE_SIZE: usize = 4096;
11
12// Workaround for alignment requirements.
13// Nicer API will probably come in the future.
14#[repr(C, align(4))]
15struct AlignedBuf([u8; 4096]);
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20 // Config for the MX25R64 present in the nRF52840 DK
21 let mut config = qspi::Config::default();
22 config.read_opcode = qspi::ReadOpcode::READ4IO;
23 config.write_opcode = qspi::WriteOpcode::PP4IO;
24 config.write_page_size = qspi::WritePageSize::_256BYTES;
25
26 let irq = interrupt::take!(QSPI);
27 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
28 p.QSPI, irq, p.P0_19, p.P0_17, p.P0_20, p.P0_21, p.P0_22, p.P0_23, config,
29 );
30
31 let mut id = [1; 3];
32 unwrap!(q.custom_instruction(0x9F, &[], &mut id).await);
33 info!("id: {}", id);
34
35 // Read status register
36 let mut status = [4; 1];
37 unwrap!(q.custom_instruction(0x05, &[], &mut status).await);
38
39 info!("status: {:?}", status[0]);
40
41 if status[0] & 0x40 == 0 {
42 status[0] |= 0x40;
43
44 unwrap!(q.custom_instruction(0x01, &status, &mut []).await);
45
46 info!("enabled quad in status");
47 }
48
49 let mut buf = AlignedBuf([0u8; PAGE_SIZE]);
50
51 let pattern = |a: u32| (a ^ (a >> 8) ^ (a >> 16) ^ (a >> 24)) as u8;
52
53 for i in 0..8 {
54 info!("page {:?}: erasing... ", i);
55 unwrap!(q.erase(i * PAGE_SIZE).await);
56
57 for j in 0..PAGE_SIZE {
58 buf.0[j] = pattern((j + i * PAGE_SIZE) as u32);
59 }
60
61 info!("programming...");
62 unwrap!(q.write(i * PAGE_SIZE, &buf.0).await);
63 }
64
65 for i in 0..8 {
66 info!("page {:?}: reading... ", i);
67 unwrap!(q.read(i * PAGE_SIZE, &mut buf.0).await);
68
69 info!("verifying...");
70 for j in 0..PAGE_SIZE {
71 assert_eq!(buf.0[j], pattern((j + i * PAGE_SIZE) as u32));
72 }
73 }
74
75 info!("done!")
76}
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
new file mode 100644
index 000000000..9341a2376
--- /dev/null
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -0,0 +1,78 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::{info, unwrap};
8use embassy_executor::Spawner;
9use embassy_nrf::{interrupt, qspi};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13// Workaround for alignment requirements.
14// Nicer API will probably come in the future.
15#[repr(C, align(4))]
16struct AlignedBuf([u8; 64]);
17
18#[embassy_executor::main]
19async fn main(_p: Spawner) {
20 let mut p = embassy_nrf::init(Default::default());
21 let mut irq = interrupt::take!(QSPI);
22
23 loop {
24 // Config for the MX25R64 present in the nRF52840 DK
25 let mut config = qspi::Config::default();
26 config.read_opcode = qspi::ReadOpcode::READ4IO;
27 config.write_opcode = qspi::WriteOpcode::PP4IO;
28 config.write_page_size = qspi::WritePageSize::_256BYTES;
29 config.deep_power_down = Some(qspi::DeepPowerDownConfig {
30 enter_time: 3, // tDP = 30uS
31 exit_time: 3, // tRDP = 35uS
32 });
33
34 let mut q: qspi::Qspi<_, 67108864> = qspi::Qspi::new(
35 &mut p.QSPI,
36 &mut irq,
37 &mut p.P0_19,
38 &mut p.P0_17,
39 &mut p.P0_20,
40 &mut p.P0_21,
41 &mut p.P0_22,
42 &mut p.P0_23,
43 config,
44 );
45
46 let mut id = [1; 3];
47 unwrap!(q.custom_instruction(0x9F, &[], &mut id).await);
48 info!("id: {}", id);
49
50 // Read status register
51 let mut status = [4; 1];
52 unwrap!(q.custom_instruction(0x05, &[], &mut status).await);
53
54 info!("status: {:?}", status[0]);
55
56 if status[0] & 0x40 == 0 {
57 status[0] |= 0x40;
58
59 unwrap!(q.custom_instruction(0x01, &status, &mut []).await);
60
61 info!("enabled quad in status");
62 }
63
64 let mut buf = AlignedBuf([0u8; 64]);
65
66 info!("reading...");
67 unwrap!(q.read(0, &mut buf.0).await);
68 info!("read: {=[u8]:x}", buf.0);
69
70 // Drop the QSPI instance. This disables the peripehral and deconfigures the pins.
71 // This clears the borrow on the singletons, so they can now be used again.
72 mem::drop(q);
73
74 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
75 // During this sleep, the nRF chip should only use ~3uA
76 Timer::after(Duration::from_secs(1)).await;
77 }
78}
diff --git a/examples/nrf52840/src/bin/raw_spawn.rs b/examples/nrf52840/src/bin/raw_spawn.rs
new file mode 100644
index 000000000..1b067f5e4
--- /dev/null
+++ b/examples/nrf52840/src/bin/raw_spawn.rs
@@ -0,0 +1,52 @@
1#![no_std]
2#![no_main]
3
4use core::mem;
5
6use cortex_m_rt::entry;
7use defmt::{info, unwrap};
8use embassy_executor::raw::TaskStorage;
9use embassy_executor::Executor;
10use embassy_time::{Duration, Timer};
11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _};
13
14async fn run1() {
15 loop {
16 info!("BIG INFREQUENT TICK");
17 Timer::after(Duration::from_ticks(64000)).await;
18 }
19}
20
21async fn run2() {
22 loop {
23 info!("tick");
24 Timer::after(Duration::from_ticks(13000)).await;
25 }
26}
27
28static EXECUTOR: StaticCell<Executor> = StaticCell::new();
29
30#[entry]
31fn main() -> ! {
32 info!("Hello World!");
33
34 let _p = embassy_nrf::init(Default::default());
35 let executor = EXECUTOR.init(Executor::new());
36
37 let run1_task = TaskStorage::new();
38 let run2_task = TaskStorage::new();
39
40 // Safety: these variables do live forever if main never returns.
41 let run1_task = unsafe { make_static(&run1_task) };
42 let run2_task = unsafe { make_static(&run2_task) };
43
44 executor.run(|spawner| {
45 unwrap!(spawner.spawn(run1_task.spawn(|| run1())));
46 unwrap!(spawner.spawn(run2_task.spawn(|| run2())));
47 });
48}
49
50unsafe fn make_static<T>(t: &T) -> &'static T {
51 mem::transmute(t)
52}
diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs
new file mode 100644
index 000000000..647073949
--- /dev/null
+++ b/examples/nrf52840/src/bin/rng.rs
@@ -0,0 +1,30 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use embassy_executor::Spawner;
6use embassy_nrf::interrupt;
7use embassy_nrf::rng::Rng;
8use rand::Rng as _;
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
15
16 // Async API
17 let mut bytes = [0; 4];
18 rng.fill_bytes(&mut bytes).await;
19 defmt::info!("Some random bytes: {:?}", bytes);
20
21 // Sync API with `rand`
22 defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10));
23
24 let mut bytes = [0; 1024];
25 rng.fill_bytes(&mut bytes).await;
26 let zero_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_zeros());
27 let one_count: u32 = bytes.iter().fold(0, |acc, val| acc + val.count_ones());
28 defmt::info!("Chance of zero: {}%", zero_count * 100 / (bytes.len() as u32 * 8));
29 defmt::info!("Chance of one: {}%", one_count * 100 / (bytes.len() as u32 * 8));
30}
diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
new file mode 100644
index 000000000..7cf588090
--- /dev/null
+++ b/examples/nrf52840/src/bin/saadc.rs
@@ -0,0 +1,25 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc};
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_p: Spawner) {
14 let mut p = embassy_nrf::init(Default::default());
15 let config = Config::default();
16 let channel_config = ChannelConfig::single_ended(&mut p.P0_02);
17 let mut saadc = Saadc::new(p.SAADC, interrupt::take!(SAADC), config, [channel_config]);
18
19 loop {
20 let mut buf = [0; 1];
21 saadc.sample(&mut buf).await;
22 info!("sample: {=i16}", &buf[0]);
23 Timer::after(Duration::from_millis(100)).await;
24 }
25}
diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
new file mode 100644
index 000000000..bb50ac65e
--- /dev/null
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::saadc::{ChannelConfig, Config, Saadc, SamplerState};
9use embassy_nrf::timer::Frequency;
10use embassy_time::Duration;
11use {defmt_rtt as _, panic_probe as _};
12
13// Demonstrates both continuous sampling and scanning multiple channels driven by a PPI linked timer
14
15#[embassy_executor::main]
16async fn main(_p: Spawner) {
17 let mut p = embassy_nrf::init(Default::default());
18 let config = Config::default();
19 let channel_1_config = ChannelConfig::single_ended(&mut p.P0_02);
20 let channel_2_config = ChannelConfig::single_ended(&mut p.P0_03);
21 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04);
22 let mut saadc = Saadc::new(
23 p.SAADC,
24 interrupt::take!(SAADC),
25 config,
26 [channel_1_config, channel_2_config, channel_3_config],
27 );
28
29 // This delay demonstrates that starting the timer prior to running
30 // the task sampler is benign given the calibration that follows.
31 embassy_time::Timer::after(Duration::from_millis(500)).await;
32 saadc.calibrate().await;
33
34 let mut bufs = [[[0; 3]; 500]; 2];
35
36 let mut c = 0;
37 let mut a: i32 = 0;
38
39 saadc
40 .run_task_sampler(
41 &mut p.TIMER0,
42 &mut p.PPI_CH0,
43 &mut p.PPI_CH1,
44 Frequency::F1MHz,
45 1000, // We want to sample at 1KHz
46 &mut bufs,
47 move |buf| {
48 // NOTE: It is important that the time spent within this callback
49 // does not exceed the time taken to acquire the 1500 samples we
50 // have in this example, which would be 10us + 2us per
51 // sample * 1500 = 18ms. You need to measure the time taken here
52 // and set the sample buffer size accordingly. Exceeding this
53 // time can lead to the peripheral re-writing the other buffer.
54 for b in buf {
55 a += b[0] as i32;
56 }
57 c += buf.len();
58 if c > 1000 {
59 a = a / c as i32;
60 info!("channel 1: {=i32}", a);
61 c = 0;
62 a = 0;
63 }
64 SamplerState::Sampled
65 },
66 )
67 .await;
68}
diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
new file mode 100644
index 000000000..196255a52
--- /dev/null
+++ b/examples/nrf52840/src/bin/self_spawn.rs
@@ -0,0 +1,22 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::task(pool_size = 2)]
11async fn my_task(spawner: Spawner, n: u32) {
12 Timer::after(Duration::from_secs(1)).await;
13 info!("Spawning self! {}", n);
14 unwrap!(spawner.spawn(my_task(spawner, n + 1)));
15}
16
17#[embassy_executor::main]
18async fn main(spawner: Spawner) {
19 let _p = embassy_nrf::init(Default::default());
20 info!("Hello World!");
21 unwrap!(spawner.spawn(my_task(spawner, 0)));
22}
diff --git a/examples/nrf52840/src/bin/self_spawn_current_executor.rs b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
new file mode 100644
index 000000000..8a179886c
--- /dev/null
+++ b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
@@ -0,0 +1,22 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::task(pool_size = 2)]
11async fn my_task(n: u32) {
12 Timer::after(Duration::from_secs(1)).await;
13 info!("Spawning self! {}", n);
14 unwrap!(Spawner::for_current_executor().await.spawn(my_task(n + 1)));
15}
16
17#[embassy_executor::main]
18async fn main(spawner: Spawner) {
19 let _p = embassy_nrf::init(Default::default());
20 info!("Hello World!");
21 unwrap!(spawner.spawn(my_task(0)));
22}
diff --git a/examples/nrf52840/src/bin/spim.rs b/examples/nrf52840/src/bin/spim.rs
new file mode 100644
index 000000000..132e01660
--- /dev/null
+++ b/examples/nrf52840/src/bin/spim.rs
@@ -0,0 +1,68 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive};
8use embassy_nrf::{interrupt, spim};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("running!");
15
16 let mut config = spim::Config::default();
17 config.frequency = spim::Frequency::M16;
18
19 let irq = interrupt::take!(SPIM3);
20 let mut spim = spim::Spim::new(p.SPI3, irq, p.P0_29, p.P0_28, p.P0_30, config);
21
22 let mut ncs = Output::new(p.P0_31, Level::High, OutputDrive::Standard);
23
24 // Example on how to talk to an ENC28J60 chip
25
26 // softreset
27 cortex_m::asm::delay(10);
28 ncs.set_low();
29 cortex_m::asm::delay(5);
30 let tx = [0xFF];
31 unwrap!(spim.transfer(&mut [], &tx).await);
32 cortex_m::asm::delay(10);
33 ncs.set_high();
34
35 cortex_m::asm::delay(100000);
36
37 let mut rx = [0; 2];
38
39 // read ESTAT
40 cortex_m::asm::delay(5000);
41 ncs.set_low();
42 cortex_m::asm::delay(5000);
43 let tx = [0b000_11101, 0];
44 unwrap!(spim.transfer(&mut rx, &tx).await);
45 cortex_m::asm::delay(5000);
46 ncs.set_high();
47 info!("estat: {=[?]}", rx);
48
49 // Switch to bank 3
50 cortex_m::asm::delay(10);
51 ncs.set_low();
52 cortex_m::asm::delay(5);
53 let tx = [0b100_11111, 0b11];
54 unwrap!(spim.transfer(&mut rx, &tx).await);
55 cortex_m::asm::delay(10);
56 ncs.set_high();
57
58 // read EREVID
59 cortex_m::asm::delay(10);
60 ncs.set_low();
61 cortex_m::asm::delay(5);
62 let tx = [0b000_10010, 0];
63 unwrap!(spim.transfer(&mut rx, &tx).await);
64 cortex_m::asm::delay(10);
65 ncs.set_high();
66
67 info!("erevid: {=[?]}", rx);
68}
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
new file mode 100644
index 000000000..fe3b0c53d
--- /dev/null
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -0,0 +1,27 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::spis::{Config, Spis};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Running!");
15
16 let irq = interrupt::take!(SPIM2_SPIS2_SPI2);
17 let mut spis = Spis::new(p.SPI2, irq, p.P0_31, p.P0_29, p.P0_28, p.P0_30, Config::default());
18
19 loop {
20 let mut rx_buf = [0_u8; 64];
21 let tx_buf = [1_u8, 2, 3, 4, 5, 6, 7, 8];
22 if let Ok((n_rx, n_tx)) = spis.transfer(&mut rx_buf, &tx_buf).await {
23 info!("RX: {:?}", rx_buf[..n_rx]);
24 info!("TX: {:?}", tx_buf[..n_tx]);
25 }
26 }
27}
diff --git a/examples/nrf52840/src/bin/temp.rs b/examples/nrf52840/src/bin/temp.rs
new file mode 100644
index 000000000..b06ac709e
--- /dev/null
+++ b/examples/nrf52840/src/bin/temp.rs
@@ -0,0 +1,23 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::info;
6use embassy_executor::Spawner;
7use embassy_nrf::interrupt;
8use embassy_nrf::temp::Temp;
9use embassy_time::{Duration, Timer};
10use {defmt_rtt as _, panic_probe as _};
11
12#[embassy_executor::main]
13async fn main(_spawner: Spawner) {
14 let p = embassy_nrf::init(Default::default());
15 let irq = interrupt::take!(TEMP);
16 let mut temp = Temp::new(p.TEMP, irq);
17
18 loop {
19 let value = temp.read().await;
20 info!("temperature: {}℃", value.to_num::<u16>());
21 Timer::after(Duration::from_secs(1)).await;
22 }
23}
diff --git a/examples/nrf52840/src/bin/timer.rs b/examples/nrf52840/src/bin/timer.rs
new file mode 100644
index 000000000..c22b5acd5
--- /dev/null
+++ b/examples/nrf52840/src/bin/timer.rs
@@ -0,0 +1,31 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::{info, unwrap};
6use embassy_executor::Spawner;
7use embassy_time::{Duration, Timer};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::task]
11async fn run1() {
12 loop {
13 info!("BIG INFREQUENT TICK");
14 Timer::after(Duration::from_ticks(64000)).await;
15 }
16}
17
18#[embassy_executor::task]
19async fn run2() {
20 loop {
21 info!("tick");
22 Timer::after(Duration::from_ticks(13000)).await;
23 }
24}
25
26#[embassy_executor::main]
27async fn main(spawner: Spawner) {
28 let _p = embassy_nrf::init(Default::default());
29 unwrap!(spawner.spawn(run1()));
30 unwrap!(spawner.spawn(run2()));
31}
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
new file mode 100644
index 000000000..a027cc1e7
--- /dev/null
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -0,0 +1,31 @@
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(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_nrf::interrupt;
12use embassy_nrf::twim::{self, Twim};
13use {defmt_rtt as _, panic_probe as _};
14
15const ADDRESS: u8 = 0x50;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20 info!("Initializing TWI...");
21 let config = twim::Config::default();
22 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
23 let mut twi = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
24
25 info!("Reading...");
26
27 let mut buf = [0u8; 16];
28 unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf));
29
30 info!("Read: {=[u8]:x}", buf);
31}
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
new file mode 100644
index 000000000..e30cc9688
--- /dev/null
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -0,0 +1,50 @@
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(type_alias_impl_trait)]
10
11use core::mem;
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_nrf::interrupt;
16use embassy_nrf::twim::{self, Twim};
17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _};
19
20const ADDRESS: u8 = 0x50;
21
22#[embassy_executor::main]
23async fn main(_p: Spawner) {
24 let mut p = embassy_nrf::init(Default::default());
25 info!("Started!");
26 let mut irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
27
28 loop {
29 info!("Initializing TWI...");
30 let config = twim::Config::default();
31
32 // Create the TWIM instance with borrowed singletons, so they're not consumed.
33 let mut twi = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
34
35 info!("Reading...");
36
37 let mut buf = [0u8; 16];
38 unwrap!(twi.blocking_write_read(ADDRESS, &mut [0x00], &mut buf));
39
40 info!("Read: {=[u8]:x}", buf);
41
42 // Drop the TWIM instance. This disables the peripehral and deconfigures the pins.
43 // This clears the borrow on the singletons, so they can now be used again.
44 mem::drop(twi);
45
46 // Sleep for 1 second. The executor ensures the core sleeps with a WFE when it has nothing to do.
47 // During this sleep, the nRF chip should only use ~3uA
48 Timer::after(Duration::from_secs(1)).await;
49 }
50}
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
new file mode 100644
index 000000000..54cba9494
--- /dev/null
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -0,0 +1,46 @@
1//! TWIS example
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_nrf::interrupt;
10use embassy_nrf::twis::{self, Command, Twis};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_nrf::init(Default::default());
16
17 let irq = interrupt::take!(SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0);
18 let mut config = twis::Config::default();
19 // Set i2c address
20 config.address0 = 0x55;
21 let mut i2c = Twis::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
22
23 info!("Listening...");
24 loop {
25 let response = [1, 2, 3, 4, 5, 6, 7, 8];
26 // This buffer is used if the i2c master performs a Write or WriteRead
27 let mut buf = [0u8; 16];
28 match i2c.listen(&mut buf).await {
29 Ok(Command::Read) => {
30 info!("Got READ command. Respond with data:\n{:?}\n", response);
31 if let Err(e) = i2c.respond_to_read(&response).await {
32 error!("{:?}", e);
33 }
34 }
35 Ok(Command::Write(n)) => info!("Got WRITE command with data:\n{:?}\n", buf[..n]),
36 Ok(Command::WriteRead(n)) => {
37 info!("Got WRITE/READ command with data:\n{:?}", buf[..n]);
38 info!("Respond with data:\n{:?}\n", response);
39 if let Err(e) = i2c.respond_to_read(&response).await {
40 error!("{:?}", e);
41 }
42 }
43 Err(e) => error!("{:?}", e),
44 }
45 }
46}
diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
new file mode 100644
index 000000000..600f7a6ef
--- /dev/null
+++ b/examples/nrf52840/src/bin/uart.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 let mut config = uarte::Config::default();
14 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200;
16
17 let irq = interrupt::take!(UARTE0_UART0);
18 let mut uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19
20 info!("uarte initialized!");
21
22 // Message must be in SRAM
23 let mut buf = [0; 8];
24 buf.copy_from_slice(b"Hello!\r\n");
25
26 unwrap!(uart.write(&buf).await);
27 info!("wrote hello in uart!");
28
29 loop {
30 info!("reading...");
31 unwrap!(uart.read(&mut buf).await);
32 info!("writing...");
33 unwrap!(uart.write(&buf).await);
34 }
35}
diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
new file mode 100644
index 000000000..6af4f7097
--- /dev/null
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -0,0 +1,35 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::{interrupt, uarte};
8use {defmt_rtt as _, panic_probe as _};
9
10#[embassy_executor::main]
11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default());
13 let mut config = uarte::Config::default();
14 config.parity = uarte::Parity::EXCLUDED;
15 config.baudrate = uarte::Baudrate::BAUD115200;
16
17 let irq = interrupt::take!(UARTE0_UART0);
18 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
19 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
20
21 info!("uarte initialized!");
22
23 // Message must be in SRAM
24 let mut buf = [0; 8];
25 buf.copy_from_slice(b"Hello!\r\n");
26
27 unwrap!(tx.write(&buf).await);
28 info!("wrote hello in uart!");
29
30 loop {
31 info!("reading...");
32 let n = unwrap!(rx.read_until_idle(&mut buf).await);
33 info!("got {} bytes", n);
34 }
35}
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
new file mode 100644
index 000000000..1adaf53fd
--- /dev/null
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -0,0 +1,60 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::peripherals::UARTE0;
8use embassy_nrf::uarte::UarteRx;
9use embassy_nrf::{interrupt, uarte};
10use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
11use embassy_sync::channel::Channel;
12use {defmt_rtt as _, panic_probe as _};
13
14static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
15
16#[embassy_executor::main]
17async fn main(spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19 let mut config = uarte::Config::default();
20 config.parity = uarte::Parity::EXCLUDED;
21 config.baudrate = uarte::Baudrate::BAUD115200;
22
23 let irq = interrupt::take!(UARTE0_UART0);
24 let uart = uarte::Uarte::new(p.UARTE0, irq, p.P0_08, p.P0_06, config);
25 let (mut tx, rx) = uart.split();
26
27 info!("uarte initialized!");
28
29 // Spawn a task responsible purely for reading
30
31 unwrap!(spawner.spawn(reader(rx)));
32
33 // Message must be in SRAM
34 {
35 let mut buf = [0; 23];
36 buf.copy_from_slice(b"Type 8 chars to echo!\r\n");
37
38 unwrap!(tx.write(&buf).await);
39 info!("wrote hello in uart!");
40 }
41
42 // Continue reading in this main task and write
43 // back out the buffer we receive from the read
44 // task.
45 loop {
46 let buf = CHANNEL.recv().await;
47 info!("writing...");
48 unwrap!(tx.write(&buf).await);
49 }
50}
51
52#[embassy_executor::task]
53async fn reader(mut rx: UarteRx<'static, UARTE0>) {
54 let mut buf = [0; 8];
55 loop {
56 info!("reading...");
57 unwrap!(rx.read(&mut buf).await);
58 CHANNEL.send(buf).await;
59 }
60}
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..e5f704524
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -0,0 +1,169 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_net::tcp::TcpSocket;
10use embassy_net::{Stack, StackResources};
11use embassy_nrf::rng::Rng;
12use embassy_nrf::usb::{Driver, PowerUsb};
13use embassy_nrf::{interrupt, pac, peripherals};
14use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
16use embassy_usb::{Builder, Config, UsbDevice};
17use embedded_io::asynch::Write;
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
22
23macro_rules! singleton {
24 ($val:expr) => {{
25 type T = impl Sized;
26 static STATIC_CELL: StaticCell<T> = StaticCell::new();
27 let (x,) = STATIC_CELL.init(($val,));
28 x
29 }};
30}
31
32const MTU: usize = 1514;
33
34#[embassy_executor::task]
35async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
36 device.run().await
37}
38
39#[embassy_executor::task]
40async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
41 class.run().await
42}
43
44#[embassy_executor::task]
45async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
46 stack.run().await
47}
48
49#[embassy_executor::main]
50async fn main(spawner: Spawner) {
51 let p = embassy_nrf::init(Default::default());
52 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
53
54 info!("Enabling ext hfosc...");
55 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
56 while clock.events_hfclkstarted.read().bits() != 1 {}
57
58 // Create the driver, from the HAL.
59 let irq = interrupt::take!(USBD);
60 let power_irq = interrupt::take!(POWER_CLOCK);
61 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
62
63 // Create embassy-usb Config
64 let mut config = Config::new(0xc0de, 0xcafe);
65 config.manufacturer = Some("Embassy");
66 config.product = Some("USB-Ethernet example");
67 config.serial_number = Some("12345678");
68 config.max_power = 100;
69 config.max_packet_size_0 = 64;
70
71 // Required for Windows support.
72 config.composite_with_iads = true;
73 config.device_class = 0xEF;
74 config.device_sub_class = 0x02;
75 config.device_protocol = 0x01;
76
77 // Create embassy-usb DeviceBuilder using the driver and config.
78 let mut builder = Builder::new(
79 driver,
80 config,
81 &mut singleton!([0; 256])[..],
82 &mut singleton!([0; 256])[..],
83 &mut singleton!([0; 256])[..],
84 &mut singleton!([0; 128])[..],
85 None,
86 );
87
88 // Our MAC addr.
89 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
90 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
91 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
92
93 // Create classes on the builder.
94 let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64);
95
96 // Build the builder.
97 let usb = builder.build();
98
99 unwrap!(spawner.spawn(usb_task(usb)));
100
101 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
102 unwrap!(spawner.spawn(usb_ncm_task(runner)));
103
104 let config = embassy_net::ConfigStrategy::Dhcp;
105 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
106 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
107 // dns_servers: Vec::new(),
108 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
109 //});
110
111 // Generate random seed
112 let mut rng = Rng::new(p.RNG, interrupt::take!(RNG));
113 let mut seed = [0; 8];
114 rng.blocking_fill_bytes(&mut seed);
115 let seed = u64::from_le_bytes(seed);
116
117 // Init network stack
118 let stack = &*singleton!(Stack::new(
119 device,
120 config,
121 singleton!(StackResources::<1, 2, 8>::new()),
122 seed
123 ));
124
125 unwrap!(spawner.spawn(net_task(stack)));
126
127 // And now we can use it!
128
129 let mut rx_buffer = [0; 4096];
130 let mut tx_buffer = [0; 4096];
131 let mut buf = [0; 4096];
132
133 loop {
134 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
135 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
136
137 info!("Listening on TCP:1234...");
138 if let Err(e) = socket.accept(1234).await {
139 warn!("accept error: {:?}", e);
140 continue;
141 }
142
143 info!("Received connection from {:?}", socket.remote_endpoint());
144
145 loop {
146 let n = match socket.read(&mut buf).await {
147 Ok(0) => {
148 warn!("read EOF");
149 break;
150 }
151 Ok(n) => n,
152 Err(e) => {
153 warn!("read error: {:?}", e);
154 break;
155 }
156 };
157
158 info!("rxd {:02x}", &buf[..n]);
159
160 match socket.write_all(&buf[..n]).await {
161 Ok(()) => {}
162 Err(e) => {
163 warn!("write error: {:?}", e);
164 break;
165 }
166 };
167 }
168 }
169}
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..76e198719
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,222 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6use core::sync::atomic::{AtomicBool, Ordering};
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_futures::join::join;
11use embassy_futures::select::{select, Either};
12use embassy_nrf::gpio::{Input, Pin, Pull};
13use embassy_nrf::usb::{Driver, PowerUsb};
14use embassy_nrf::{interrupt, pac};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal;
17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
18use embassy_usb::control::OutResponse;
19use embassy_usb::{Builder, Config, DeviceStateHandler};
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
21use {defmt_rtt as _, panic_probe as _};
22
23static SUSPENDED: AtomicBool = AtomicBool::new(false);
24
25#[embassy_executor::main]
26async fn main(_spawner: Spawner) {
27 let p = embassy_nrf::init(Default::default());
28 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
29
30 info!("Enabling ext hfosc...");
31 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
32 while clock.events_hfclkstarted.read().bits() != 1 {}
33
34 // Create the driver, from the HAL.
35 let irq = interrupt::take!(USBD);
36 let power_irq = interrupt::take!(POWER_CLOCK);
37 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
38
39 // Create embassy-usb Config
40 let mut config = Config::new(0xc0de, 0xcafe);
41 config.manufacturer = Some("Embassy");
42 config.product = Some("HID keyboard example");
43 config.serial_number = Some("12345678");
44 config.max_power = 100;
45 config.max_packet_size_0 = 64;
46 config.supports_remote_wakeup = true;
47
48 // Create embassy-usb DeviceBuilder using the driver and config.
49 // It needs some buffers for building the descriptors.
50 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64];
54 let request_handler = MyRequestHandler {};
55 let device_state_handler = MyDeviceStateHandler::new();
56
57 let mut state = State::new();
58
59 let mut builder = Builder::new(
60 driver,
61 config,
62 &mut device_descriptor,
63 &mut config_descriptor,
64 &mut bos_descriptor,
65 &mut control_buf,
66 Some(&device_state_handler),
67 );
68
69 // Create classes on the builder.
70 let config = embassy_usb::class::hid::Config {
71 report_descriptor: KeyboardReport::desc(),
72 request_handler: Some(&request_handler),
73 poll_ms: 60,
74 max_packet_size: 64,
75 };
76 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
77
78 // Build the builder.
79 let mut usb = builder.build();
80
81 let remote_wakeup: Signal<CriticalSectionRawMutex, _> = Signal::new();
82
83 // Run the USB device.
84 let usb_fut = async {
85 loop {
86 usb.run_until_suspend().await;
87 match select(usb.wait_resume(), remote_wakeup.wait()).await {
88 Either::First(_) => (),
89 Either::Second(_) => unwrap!(usb.remote_wakeup().await),
90 }
91 }
92 };
93
94 let mut button = Input::new(p.P0_11.degrade(), Pull::Up);
95
96 let (reader, mut writer) = hid.split();
97
98 // Do stuff with the class!
99 let in_fut = async {
100 loop {
101 button.wait_for_low().await;
102 info!("PRESSED");
103
104 if SUSPENDED.load(Ordering::Acquire) {
105 info!("Triggering remote wakeup");
106 remote_wakeup.signal(());
107 } else {
108 let report = KeyboardReport {
109 keycodes: [4, 0, 0, 0, 0, 0],
110 leds: 0,
111 modifier: 0,
112 reserved: 0,
113 };
114 match writer.write_serialize(&report).await {
115 Ok(()) => {}
116 Err(e) => warn!("Failed to send report: {:?}", e),
117 };
118 }
119
120 button.wait_for_high().await;
121 info!("RELEASED");
122 let report = KeyboardReport {
123 keycodes: [0, 0, 0, 0, 0, 0],
124 leds: 0,
125 modifier: 0,
126 reserved: 0,
127 };
128 match writer.write_serialize(&report).await {
129 Ok(()) => {}
130 Err(e) => warn!("Failed to send report: {:?}", e),
131 };
132 }
133 };
134
135 let out_fut = async {
136 reader.run(false, &request_handler).await;
137 };
138
139 // Run everything concurrently.
140 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
141 join(usb_fut, join(in_fut, out_fut)).await;
142}
143
144struct MyRequestHandler {}
145
146impl RequestHandler for MyRequestHandler {
147 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
148 info!("Get report for {:?}", id);
149 None
150 }
151
152 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
153 info!("Set report for {:?}: {=[u8]}", id, data);
154 OutResponse::Accepted
155 }
156
157 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
158 info!("Set idle rate for {:?} to {:?}", id, dur);
159 }
160
161 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
162 info!("Get idle rate for {:?}", id);
163 None
164 }
165}
166
167struct MyDeviceStateHandler {
168 configured: AtomicBool,
169}
170
171impl MyDeviceStateHandler {
172 fn new() -> Self {
173 MyDeviceStateHandler {
174 configured: AtomicBool::new(false),
175 }
176 }
177}
178
179impl DeviceStateHandler for MyDeviceStateHandler {
180 fn enabled(&self, enabled: bool) {
181 self.configured.store(false, Ordering::Relaxed);
182 SUSPENDED.store(false, Ordering::Release);
183 if enabled {
184 info!("Device enabled");
185 } else {
186 info!("Device disabled");
187 }
188 }
189
190 fn reset(&self) {
191 self.configured.store(false, Ordering::Relaxed);
192 info!("Bus reset, the Vbus current limit is 100mA");
193 }
194
195 fn addressed(&self, addr: u8) {
196 self.configured.store(false, Ordering::Relaxed);
197 info!("USB address set to: {}", addr);
198 }
199
200 fn configured(&self, configured: bool) {
201 self.configured.store(configured, Ordering::Relaxed);
202 if configured {
203 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
204 } else {
205 info!("Device is no longer configured, the Vbus current limit is 100mA.");
206 }
207 }
208
209 fn suspended(&self, suspended: bool) {
210 if suspended {
211 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled).");
212 SUSPENDED.store(true, Ordering::Release);
213 } else {
214 SUSPENDED.store(false, Ordering::Release);
215 if self.configured.load(Ordering::Relaxed) {
216 info!("Device resumed, it may now draw up to the configured current limit from Vbus");
217 } else {
218 info!("Device resumed, the Vbus current limit is 100mA");
219 }
220 }
221 }
222}
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
new file mode 100644
index 000000000..4916a38d4
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -0,0 +1,124 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, PowerUsb};
11use embassy_nrf::{interrupt, pac};
12use embassy_time::{Duration, Timer};
13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State};
14use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config};
16use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
17use {defmt_rtt as _, panic_probe as _};
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 let p = embassy_nrf::init(Default::default());
22 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
23
24 info!("Enabling ext hfosc...");
25 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
26 while clock.events_hfclkstarted.read().bits() != 1 {}
27
28 // Create the driver, from the HAL.
29 let irq = interrupt::take!(USBD);
30 let power_irq = interrupt::take!(POWER_CLOCK);
31 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
32
33 // Create embassy-usb Config
34 let mut config = Config::new(0xc0de, 0xcafe);
35 config.manufacturer = Some("Embassy");
36 config.product = Some("HID mouse example");
37 config.serial_number = Some("12345678");
38 config.max_power = 100;
39 config.max_packet_size_0 = 64;
40
41 // Create embassy-usb DeviceBuilder using the driver and config.
42 // It needs some buffers for building the descriptors.
43 let mut device_descriptor = [0; 256];
44 let mut config_descriptor = [0; 256];
45 let mut bos_descriptor = [0; 256];
46 let mut control_buf = [0; 64];
47 let request_handler = MyRequestHandler {};
48
49 let mut state = State::new();
50
51 let mut builder = Builder::new(
52 driver,
53 config,
54 &mut device_descriptor,
55 &mut config_descriptor,
56 &mut bos_descriptor,
57 &mut control_buf,
58 None,
59 );
60
61 // Create classes on the builder.
62 let config = embassy_usb::class::hid::Config {
63 report_descriptor: MouseReport::desc(),
64 request_handler: Some(&request_handler),
65 poll_ms: 60,
66 max_packet_size: 8,
67 };
68
69 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
70
71 // Build the builder.
72 let mut usb = builder.build();
73
74 // Run the USB device.
75 let usb_fut = usb.run();
76
77 // Do stuff with the class!
78 let hid_fut = async {
79 let mut y: i8 = 5;
80 loop {
81 Timer::after(Duration::from_millis(500)).await;
82
83 y = -y;
84 let report = MouseReport {
85 buttons: 0,
86 x: 0,
87 y,
88 wheel: 0,
89 pan: 0,
90 };
91 match writer.write_serialize(&report).await {
92 Ok(()) => {}
93 Err(e) => warn!("Failed to send report: {:?}", e),
94 }
95 }
96 };
97
98 // Run everything concurrently.
99 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
100 join(usb_fut, hid_fut).await;
101}
102
103struct MyRequestHandler {}
104
105impl RequestHandler for MyRequestHandler {
106 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
107 info!("Get report for {:?}", id);
108 None
109 }
110
111 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
112 info!("Set report for {:?}: {=[u8]}", id, data);
113 OutResponse::Accepted
114 }
115
116 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
117 info!("Set idle rate for {:?} to {:?}", id, dur);
118 }
119
120 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
121 info!("Get idle rate for {:?}", id);
122 None
123 }
124}
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
new file mode 100644
index 000000000..7c9c4184b
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -0,0 +1,110 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::{info, panic};
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_nrf::usb::{Driver, Instance, PowerUsb, UsbSupply};
11use embassy_nrf::{interrupt, pac};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError;
14use embassy_usb::{Builder, Config};
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_nrf::init(Default::default());
20 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
21
22 info!("Enabling ext hfosc...");
23 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
24 while clock.events_hfclkstarted.read().bits() != 1 {}
25
26 // Create the driver, from the HAL.
27 let irq = interrupt::take!(USBD);
28 let power_irq = interrupt::take!(POWER_CLOCK);
29 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
30
31 // Create embassy-usb Config
32 let mut config = Config::new(0xc0de, 0xcafe);
33 config.manufacturer = Some("Embassy");
34 config.product = Some("USB-serial example");
35 config.serial_number = Some("12345678");
36 config.max_power = 100;
37 config.max_packet_size_0 = 64;
38
39 // Required for windows compatiblity.
40 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
41 config.device_class = 0xEF;
42 config.device_sub_class = 0x02;
43 config.device_protocol = 0x01;
44 config.composite_with_iads = true;
45
46 // Create embassy-usb DeviceBuilder using the driver and config.
47 // It needs some buffers for building the descriptors.
48 let mut device_descriptor = [0; 256];
49 let mut config_descriptor = [0; 256];
50 let mut bos_descriptor = [0; 256];
51 let mut control_buf = [0; 64];
52
53 let mut state = State::new();
54
55 let mut builder = Builder::new(
56 driver,
57 config,
58 &mut device_descriptor,
59 &mut config_descriptor,
60 &mut bos_descriptor,
61 &mut control_buf,
62 None,
63 );
64
65 // Create classes on the builder.
66 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
67
68 // Build the builder.
69 let mut usb = builder.build();
70
71 // Run the USB device.
72 let usb_fut = usb.run();
73
74 // Do stuff with the class!
75 let echo_fut = async {
76 loop {
77 class.wait_connection().await;
78 info!("Connected");
79 let _ = echo(&mut class).await;
80 info!("Disconnected");
81 }
82 };
83
84 // Run everything concurrently.
85 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
86 join(usb_fut, echo_fut).await;
87}
88
89struct Disconnected {}
90
91impl From<EndpointError> for Disconnected {
92 fn from(val: EndpointError) -> Self {
93 match val {
94 EndpointError::BufferOverflow => panic!("Buffer overflow"),
95 EndpointError::Disabled => Disconnected {},
96 }
97 }
98}
99
100async fn echo<'d, T: Instance + 'd, P: UsbSupply + 'd>(
101 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
102) -> Result<(), Disconnected> {
103 let mut buf = [0; 64];
104 loop {
105 let n = class.read_packet(&mut buf).await?;
106 let data = &buf[..n];
107 info!("data: {:x}", data);
108 class.write_packet(data).await?;
109 }
110}
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
new file mode 100644
index 000000000..93efc2fe6
--- /dev/null
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -0,0 +1,118 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::mem;
6
7use defmt::{info, panic, unwrap};
8use embassy_executor::Spawner;
9use embassy_nrf::usb::{Driver, PowerUsb};
10use embassy_nrf::{interrupt, pac, peripherals};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError;
13use embassy_usb::{Builder, Config, UsbDevice};
14use static_cell::StaticCell;
15use {defmt_rtt as _, panic_probe as _};
16
17type MyDriver = Driver<'static, peripherals::USBD, PowerUsb>;
18
19#[embassy_executor::task]
20async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
21 device.run().await;
22}
23
24#[embassy_executor::task]
25async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) {
26 loop {
27 class.wait_connection().await;
28 info!("Connected");
29 let _ = echo(&mut class).await;
30 info!("Disconnected");
31 }
32}
33
34#[embassy_executor::main]
35async fn main(spawner: Spawner) {
36 let p = embassy_nrf::init(Default::default());
37 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
38
39 info!("Enabling ext hfosc...");
40 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) });
41 while clock.events_hfclkstarted.read().bits() != 1 {}
42 // Create the driver, from the HAL.
43 let irq = interrupt::take!(USBD);
44 let power_irq = interrupt::take!(POWER_CLOCK);
45 let driver = Driver::new(p.USBD, irq, PowerUsb::new(power_irq));
46
47 // Create embassy-usb Config
48 let mut config = Config::new(0xc0de, 0xcafe);
49 config.manufacturer = Some("Embassy");
50 config.product = Some("USB-serial example");
51 config.serial_number = Some("12345678");
52 config.max_power = 100;
53 config.max_packet_size_0 = 64;
54
55 // Required for windows compatiblity.
56 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
57 config.device_class = 0xEF;
58 config.device_sub_class = 0x02;
59 config.device_protocol = 0x01;
60 config.composite_with_iads = true;
61
62 struct Resources {
63 device_descriptor: [u8; 256],
64 config_descriptor: [u8; 256],
65 bos_descriptor: [u8; 256],
66 control_buf: [u8; 64],
67 serial_state: State<'static>,
68 }
69 static RESOURCES: StaticCell<Resources> = StaticCell::new();
70 let res = RESOURCES.init(Resources {
71 device_descriptor: [0; 256],
72 config_descriptor: [0; 256],
73 bos_descriptor: [0; 256],
74 control_buf: [0; 64],
75 serial_state: State::new(),
76 });
77
78 // Create embassy-usb DeviceBuilder using the driver and config.
79 let mut builder = Builder::new(
80 driver,
81 config,
82 &mut res.device_descriptor,
83 &mut res.config_descriptor,
84 &mut res.bos_descriptor,
85 &mut res.control_buf,
86 None,
87 );
88
89 // Create classes on the builder.
90 let class = CdcAcmClass::new(&mut builder, &mut res.serial_state, 64);
91
92 // Build the builder.
93 let usb = builder.build();
94
95 unwrap!(spawner.spawn(usb_task(usb)));
96 unwrap!(spawner.spawn(echo_task(class)));
97}
98
99struct Disconnected {}
100
101impl From<EndpointError> for Disconnected {
102 fn from(val: EndpointError) -> Self {
103 match val {
104 EndpointError::BufferOverflow => panic!("Buffer overflow"),
105 EndpointError::Disabled => Disconnected {},
106 }
107 }
108}
109
110async fn echo(class: &mut CdcAcmClass<'static, MyDriver>) -> Result<(), Disconnected> {
111 let mut buf = [0; 64];
112 loop {
113 let n = class.read_packet(&mut buf).await?;
114 let data = &buf[..n];
115 info!("data: {:x}", data);
116 class.write_packet(data).await?;
117 }
118}
diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
new file mode 100644
index 000000000..b0b9c3b81
--- /dev/null
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -0,0 +1,41 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Input, Pull};
8use embassy_nrf::wdt::{Config, Watchdog};
9use {defmt_rtt as _, panic_probe as _};
10
11#[embassy_executor::main]
12async fn main(_spawner: Spawner) {
13 let p = embassy_nrf::init(Default::default());
14 info!("Hello World!");
15
16 let mut config = Config::default();
17 config.timeout_ticks = 32768 * 3; // 3 seconds
18
19 // This is needed for `probe-run` to be able to catch the panic message
20 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
21 config.run_during_debug_halt = false;
22
23 let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) {
24 Ok(x) => x,
25 Err(_) => {
26 info!("Watchdog already active with wrong config, waiting for it to timeout...");
27 loop {}
28 }
29 };
30
31 let mut button = Input::new(p.P0_11, Pull::Up);
32
33 info!("Watchdog started, press button 1 to pet it or I'll reset in 3 seconds!");
34
35 loop {
36 button.wait_for_high().await;
37 button.wait_for_low().await;
38 info!("Button pressed, petting watchdog!");
39 handle.pet();
40 }
41}