aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf52840/src/bin
diff options
context:
space:
mode:
authorDominik Boehi <[email protected]>2023-01-09 22:29:58 +0100
committerDominik Boehi <[email protected]>2023-01-09 22:30:02 +0100
commit0a27b6cedb52453123190671f294bbd34918e09a (patch)
tree3888e0b352388ace235517ec97c4d3a88fd7fcfa /examples/nrf52840/src/bin
parent401185b1d95a2519ee94e5d5654cc9325fe85eec (diff)
Rename examples/nrf to examples/nrf52840
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}