aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf52840/src
diff options
context:
space:
mode:
authorDion Dokter <[email protected]>2025-11-20 13:22:38 +0100
committerDion Dokter <[email protected]>2025-11-20 13:22:38 +0100
commit4f2c36e447455e8d33607d586859d3d075cabf1d (patch)
tree003cd822d688acd7c074dd229663b4648d100f71 /examples/nrf52840/src
parent663732d85abbae400f2dbab2c411802a5b60e9b1 (diff)
parent661874d11de7d93ed52e08e020a9d4c7ee11122d (diff)
Merge branch 'main' into u0-lcd
Diffstat (limited to 'examples/nrf52840/src')
-rw-r--r--examples/nrf52840/src/bin/buffered_uart.rs4
-rw-r--r--examples/nrf52840/src/bin/channel.rs6
-rw-r--r--examples/nrf52840/src/bin/channel_sender_receiver.rs13
-rw-r--r--examples/nrf52840/src/bin/egu.rs46
-rw-r--r--examples/nrf52840/src/bin/ethernet_enc28j60.rs25
-rw-r--r--examples/nrf52840/src/bin/executor_fairness_test.rs6
-rw-r--r--examples/nrf52840/src/bin/gpiote_channel.rs26
-rw-r--r--examples/nrf52840/src/bin/gpiote_port.rs8
-rw-r--r--examples/nrf52840/src/bin/i2s_effect.rs8
-rw-r--r--examples/nrf52840/src/bin/i2s_monitor.rs11
-rw-r--r--examples/nrf52840/src/bin/i2s_waveform.rs8
-rw-r--r--examples/nrf52840/src/bin/ieee802154_receive.rs38
-rw-r--r--examples/nrf52840/src/bin/ieee802154_send.rs39
-rw-r--r--examples/nrf52840/src/bin/manually_create_executor.rs4
-rw-r--r--examples/nrf52840/src/bin/multiprio.rs26
-rw-r--r--examples/nrf52840/src/bin/mutex.rs2
-rw-r--r--examples/nrf52840/src/bin/nfct.rs323
-rw-r--r--examples/nrf52840/src/bin/pdm_continuous.rs4
-rw-r--r--examples/nrf52840/src/bin/ppi.rs34
-rw-r--r--examples/nrf52840/src/bin/pubsub.rs6
-rw-r--r--examples/nrf52840/src/bin/pwm.rs14
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ppi.rs14
-rw-r--r--examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs10
-rw-r--r--examples/nrf52840/src/bin/pwm_servo.rs14
-rw-r--r--examples/nrf52840/src/bin/qspi_lowpower.rs14
-rw-r--r--examples/nrf52840/src/bin/raw_spawn.rs8
-rwxr-xr-x[-rw-r--r--]examples/nrf52840/src/bin/rng.rs2
-rw-r--r--examples/nrf52840/src/bin/rtc.rs56
-rw-r--r--examples/nrf52840/src/bin/saadc.rs2
-rw-r--r--examples/nrf52840/src/bin/saadc_continuous.rs12
-rw-r--r--examples/nrf52840/src/bin/self_spawn.rs4
-rw-r--r--examples/nrf52840/src/bin/self_spawn_current_executor.rs5
-rw-r--r--examples/nrf52840/src/bin/sixlowpan.rs120
-rw-r--r--examples/nrf52840/src/bin/spis.rs2
-rw-r--r--examples/nrf52840/src/bin/timer.rs4
-rw-r--r--examples/nrf52840/src/bin/twim.rs6
-rw-r--r--examples/nrf52840/src/bin/twim_lowpower.rs12
-rw-r--r--examples/nrf52840/src/bin/twis.rs2
-rw-r--r--examples/nrf52840/src/bin/uart.rs4
-rw-r--r--examples/nrf52840/src/bin/uart_idle.rs4
-rw-r--r--examples/nrf52840/src/bin/uart_split.rs8
-rw-r--r--examples/nrf52840/src/bin/usb_ethernet.rs36
-rw-r--r--examples/nrf52840/src/bin/usb_hid_keyboard.rs74
-rw-r--r--examples/nrf52840/src/bin/usb_hid_mouse.rs65
-rw-r--r--examples/nrf52840/src/bin/usb_serial.rs22
-rw-r--r--examples/nrf52840/src/bin/usb_serial_multitask.rs24
-rw-r--r--examples/nrf52840/src/bin/usb_serial_winusb.rs22
-rw-r--r--examples/nrf52840/src/bin/wdt.rs4
-rw-r--r--examples/nrf52840/src/bin/wifi_esp_hosted.rs38
49 files changed, 921 insertions, 318 deletions
diff --git a/examples/nrf52840/src/bin/buffered_uart.rs b/examples/nrf52840/src/bin/buffered_uart.rs
index 6ac72bcaf..f0a066818 100644
--- a/examples/nrf52840/src/bin/buffered_uart.rs
+++ b/examples/nrf52840/src/bin/buffered_uart.rs
@@ -9,7 +9,7 @@ use embedded_io_async::Write;
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
11bind_interrupts!(struct Irqs { 11bind_interrupts!(struct Irqs {
12 UARTE0_UART0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>; 12 UARTE0 => buffered_uarte::InterruptHandler<peripherals::UARTE0>;
13}); 13});
14 14
15#[embassy_executor::main] 15#[embassy_executor::main]
@@ -28,9 +28,9 @@ async fn main(_spawner: Spawner) {
28 p.PPI_CH0, 28 p.PPI_CH0,
29 p.PPI_CH1, 29 p.PPI_CH1,
30 p.PPI_GROUP0, 30 p.PPI_GROUP0,
31 Irqs,
32 p.P0_08, 31 p.P0_08,
33 p.P0_06, 32 p.P0_06,
33 Irqs,
34 config, 34 config,
35 &mut rx_buffer, 35 &mut rx_buffer,
36 &mut tx_buffer, 36 &mut tx_buffer,
diff --git a/examples/nrf52840/src/bin/channel.rs b/examples/nrf52840/src/bin/channel.rs
index 7fcea9dbd..ffa539808 100644
--- a/examples/nrf52840/src/bin/channel.rs
+++ b/examples/nrf52840/src/bin/channel.rs
@@ -31,12 +31,12 @@ async fn main(spawner: Spawner) {
31 let p = embassy_nrf::init(Default::default()); 31 let p = embassy_nrf::init(Default::default());
32 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard); 32 let mut led = Output::new(p.P0_13, Level::Low, OutputDrive::Standard);
33 33
34 unwrap!(spawner.spawn(my_task())); 34 spawner.spawn(unwrap!(my_task()));
35 35
36 loop { 36 loop {
37 match CHANNEL.receive().await { 37 match CHANNEL.receive().await {
38 LedState::On => led.set_high(), 38 LedState::On => led.set_low(),
39 LedState::Off => led.set_low(), 39 LedState::Off => led.set_high(),
40 } 40 }
41 } 41 }
42} 42}
diff --git a/examples/nrf52840/src/bin/channel_sender_receiver.rs b/examples/nrf52840/src/bin/channel_sender_receiver.rs
index 3095a04ec..de694eaa0 100644
--- a/examples/nrf52840/src/bin/channel_sender_receiver.rs
+++ b/examples/nrf52840/src/bin/channel_sender_receiver.rs
@@ -3,7 +3,8 @@
3 3
4use defmt::unwrap; 4use defmt::unwrap;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; 6use embassy_nrf::Peri;
7use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive};
7use embassy_sync::blocking_mutex::raw::NoopRawMutex; 8use embassy_sync::blocking_mutex::raw::NoopRawMutex;
8use embassy_sync::channel::{Channel, Receiver, Sender}; 9use embassy_sync::channel::{Channel, Receiver, Sender};
9use embassy_time::Timer; 10use embassy_time::Timer;
@@ -28,13 +29,13 @@ async fn send_task(sender: Sender<'static, NoopRawMutex, LedState, 1>) {
28} 29}
29 30
30#[embassy_executor::task] 31#[embassy_executor::task]
31async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) { 32async fn recv_task(led: Peri<'static, AnyPin>, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) {
32 let mut led = Output::new(led, Level::Low, OutputDrive::Standard); 33 let mut led = Output::new(led, Level::Low, OutputDrive::Standard);
33 34
34 loop { 35 loop {
35 match receiver.receive().await { 36 match receiver.receive().await {
36 LedState::On => led.set_high(), 37 LedState::On => led.set_low(),
37 LedState::Off => led.set_low(), 38 LedState::Off => led.set_high(),
38 } 39 }
39 } 40 }
40} 41}
@@ -44,6 +45,6 @@ async fn main(spawner: Spawner) {
44 let p = embassy_nrf::init(Default::default()); 45 let p = embassy_nrf::init(Default::default());
45 let channel = CHANNEL.init(Channel::new()); 46 let channel = CHANNEL.init(Channel::new());
46 47
47 unwrap!(spawner.spawn(send_task(channel.sender()))); 48 spawner.spawn(unwrap!(send_task(channel.sender())));
48 unwrap!(spawner.spawn(recv_task(p.P0_13.degrade(), channel.receiver()))); 49 spawner.spawn(unwrap!(recv_task(p.P0_13.into(), channel.receiver())));
49} 50}
diff --git a/examples/nrf52840/src/bin/egu.rs b/examples/nrf52840/src/bin/egu.rs
new file mode 100644
index 000000000..36eba8084
--- /dev/null
+++ b/examples/nrf52840/src/bin/egu.rs
@@ -0,0 +1,46 @@
1//! This example shows the use of the EGU peripheral combined with PPI.
2//!
3//! It chains events from button -> egu0-trigger0 -> egu0-trigger1 -> led
4#![no_std]
5#![no_main]
6
7use embassy_executor::Spawner;
8use embassy_nrf::egu::{Egu, TriggerNumber};
9use embassy_nrf::gpio::{Level, OutputDrive, Pull};
10use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity, OutputChannel, OutputChannelPolarity};
11use embassy_nrf::peripherals::{PPI_CH0, PPI_CH1, PPI_CH2};
12use embassy_nrf::ppi::Ppi;
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let p = embassy_nrf::init(Default::default());
19
20 let mut egu1 = Egu::new(p.EGU0);
21 let led1 = OutputChannel::new(
22 p.GPIOTE_CH0,
23 p.P0_13,
24 Level::High,
25 OutputDrive::Standard,
26 OutputChannelPolarity::Toggle,
27 );
28 let btn1 = InputChannel::new(p.GPIOTE_CH1, p.P0_11, Pull::Up, InputChannelPolarity::LoToHi);
29
30 let trigger0 = egu1.trigger(TriggerNumber::Trigger0);
31 let trigger1 = egu1.trigger(TriggerNumber::Trigger1);
32
33 let mut ppi1: Ppi<PPI_CH0, 1, 1> = Ppi::new_one_to_one(p.PPI_CH0, btn1.event_in(), trigger0.task());
34 ppi1.enable();
35
36 let mut ppi2: Ppi<PPI_CH1, 1, 1> = Ppi::new_one_to_one(p.PPI_CH1, trigger0.event(), trigger1.task());
37 ppi2.enable();
38
39 let mut ppi3: Ppi<PPI_CH2, 1, 1> = Ppi::new_one_to_one(p.PPI_CH2, trigger1.event(), led1.task_out());
40 ppi3.enable();
41
42 defmt::info!("Push the button to toggle the LED");
43 loop {
44 Timer::after(Duration::from_secs(60)).await;
45 }
46}
diff --git a/examples/nrf52840/src/bin/ethernet_enc28j60.rs b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
index 279f32edc..5a988d89b 100644
--- a/examples/nrf52840/src/bin/ethernet_enc28j60.rs
+++ b/examples/nrf52840/src/bin/ethernet_enc28j60.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::StackResources;
6use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources};
8use embassy_net_enc28j60::Enc28j60; 8use embassy_net_enc28j60::Enc28j60;
9use embassy_nrf::gpio::{Level, Output, OutputDrive}; 9use embassy_nrf::gpio::{Level, Output, OutputDrive};
10use embassy_nrf::rng::Rng; 10use embassy_nrf::rng::Rng;
@@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs {
23 23
24#[embassy_executor::task] 24#[embassy_executor::task]
25async fn net_task( 25async fn net_task(
26 stack: &'static Stack< 26 mut runner: embassy_net::Runner<
27 Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>, 27 'static,
28 Enc28j60<ExclusiveDevice<Spim<'static>, Output<'static>, Delay>, Output<'static>>,
28 >, 29 >,
29) -> ! { 30) -> ! {
30 stack.run().await 31 runner.run().await
31} 32}
32 33
33#[embassy_executor::main] 34#[embassy_executor::main]
@@ -66,18 +67,10 @@ async fn main(spawner: Spawner) {
66 let seed = u64::from_le_bytes(seed); 67 let seed = u64::from_le_bytes(seed);
67 68
68 // Init network stack 69 // Init network stack
69 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 70 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
70 static STACK: StaticCell< 71 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
71 Stack<Enc28j60<ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, Output<'static>>>, 72
72 > = StaticCell::new(); 73 spawner.spawn(unwrap!(net_task(runner)));
73 let stack = STACK.init(Stack::new(
74 device,
75 config,
76 RESOURCES.init(StackResources::<2>::new()),
77 seed,
78 ));
79
80 unwrap!(spawner.spawn(net_task(stack)));
81 74
82 // And now we can use it! 75 // And now we can use it!
83 76
diff --git a/examples/nrf52840/src/bin/executor_fairness_test.rs b/examples/nrf52840/src/bin/executor_fairness_test.rs
index df6e7af3f..70c9405f0 100644
--- a/examples/nrf52840/src/bin/executor_fairness_test.rs
+++ b/examples/nrf52840/src/bin/executor_fairness_test.rs
@@ -36,7 +36,7 @@ async fn run3() {
36#[embassy_executor::main] 36#[embassy_executor::main]
37async fn main(spawner: Spawner) { 37async fn main(spawner: Spawner) {
38 let _p = embassy_nrf::init(Default::default()); 38 let _p = embassy_nrf::init(Default::default());
39 unwrap!(spawner.spawn(run1())); 39 spawner.spawn(unwrap!(run1()));
40 unwrap!(spawner.spawn(run2())); 40 spawner.spawn(unwrap!(run2()));
41 unwrap!(spawner.spawn(run3())); 41 spawner.spawn(unwrap!(run3()));
42} 42}
diff --git a/examples/nrf52840/src/bin/gpiote_channel.rs b/examples/nrf52840/src/bin/gpiote_channel.rs
index dcfe7723a..e358779b2 100644
--- a/examples/nrf52840/src/bin/gpiote_channel.rs
+++ b/examples/nrf52840/src/bin/gpiote_channel.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::info; 4use defmt::info;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Input, Pull}; 6use embassy_nrf::gpio::Pull;
7use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; 7use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -12,26 +12,10 @@ async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 12 let p = embassy_nrf::init(Default::default());
13 info!("Starting!"); 13 info!("Starting!");
14 14
15 let ch1 = InputChannel::new( 15 let mut ch1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo);
16 p.GPIOTE_CH0, 16 let mut ch2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::LoToHi);
17 Input::new(p.P0_11, Pull::Up), 17 let mut ch3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::Toggle);
18 InputChannelPolarity::HiToLo, 18 let mut ch4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::Toggle);
19 );
20 let ch2 = InputChannel::new(
21 p.GPIOTE_CH1,
22 Input::new(p.P0_12, Pull::Up),
23 InputChannelPolarity::LoToHi,
24 );
25 let ch3 = InputChannel::new(
26 p.GPIOTE_CH2,
27 Input::new(p.P0_24, Pull::Up),
28 InputChannelPolarity::Toggle,
29 );
30 let ch4 = InputChannel::new(
31 p.GPIOTE_CH3,
32 Input::new(p.P0_25, Pull::Up),
33 InputChannelPolarity::Toggle,
34 );
35 19
36 let button1 = async { 20 let button1 = async {
37 loop { 21 loop {
diff --git a/examples/nrf52840/src/bin/gpiote_port.rs b/examples/nrf52840/src/bin/gpiote_port.rs
index 0dddb1a97..66dbd32dc 100644
--- a/examples/nrf52840/src/bin/gpiote_port.rs
+++ b/examples/nrf52840/src/bin/gpiote_port.rs
@@ -26,8 +26,8 @@ async fn main(spawner: Spawner) {
26 let btn3 = Input::new(p.P0_24, Pull::Up); 26 let btn3 = Input::new(p.P0_24, Pull::Up);
27 let btn4 = Input::new(p.P0_25, Pull::Up); 27 let btn4 = Input::new(p.P0_25, Pull::Up);
28 28
29 unwrap!(spawner.spawn(button_task(1, btn1))); 29 spawner.spawn(unwrap!(button_task(1, btn1)));
30 unwrap!(spawner.spawn(button_task(2, btn2))); 30 spawner.spawn(unwrap!(button_task(2, btn2)));
31 unwrap!(spawner.spawn(button_task(3, btn3))); 31 spawner.spawn(unwrap!(button_task(3, btn3)));
32 unwrap!(spawner.spawn(button_task(4, btn4))); 32 spawner.spawn(unwrap!(button_task(4, btn4)));
33} 33}
diff --git a/examples/nrf52840/src/bin/i2s_effect.rs b/examples/nrf52840/src/bin/i2s_effect.rs
index 9eadeb4e4..c31b78614 100644
--- a/examples/nrf52840/src/bin/i2s_effect.rs
+++ b/examples/nrf52840/src/bin/i2s_effect.rs
@@ -5,7 +5,7 @@ use core::f32::consts::PI;
5 5
6use defmt::{error, info}; 6use defmt::{error, info};
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; 8use embassy_nrf::i2s::{self, Channels, Config, I2S, MasterClock, MultiBuffering, Sample as _, SampleWidth};
9use embassy_nrf::{bind_interrupts, peripherals}; 9use embassy_nrf::{bind_interrupts, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -102,11 +102,7 @@ impl SineOsc {
102 102
103#[inline] 103#[inline]
104fn abs(value: f32) -> f32 { 104fn abs(value: f32) -> f32 {
105 if value < 0.0 { 105 if value < 0.0 { -value } else { value }
106 -value
107 } else {
108 value
109 }
110} 106}
111 107
112#[inline] 108#[inline]
diff --git a/examples/nrf52840/src/bin/i2s_monitor.rs b/examples/nrf52840/src/bin/i2s_monitor.rs
index 799be351f..a54659101 100644
--- a/examples/nrf52840/src/bin/i2s_monitor.rs
+++ b/examples/nrf52840/src/bin/i2s_monitor.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::{debug, error, info}; 4use defmt::{debug, error, info};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; 6use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth};
7use embassy_nrf::pwm::{Prescaler, SimplePwm}; 7use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm};
8use embassy_nrf::{bind_interrupts, peripherals}; 8use embassy_nrf::{bind_interrupts, peripherals};
9use {defmt_rtt as _, panic_probe as _}; 9use {defmt_rtt as _, panic_probe as _};
10 10
@@ -34,7 +34,7 @@ async fn main(_spawner: Spawner) {
34 I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers); 34 I2S::new_master(p.I2S, Irqs, p.P0_25, p.P0_26, p.P0_27, master_clock, config).input(p.P0_29, buffers);
35 35
36 // Configure the PWM to use the pins corresponding to the RGB leds 36 // Configure the PWM to use the pins corresponding to the RGB leds
37 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24); 37 let mut pwm = SimplePwm::new_3ch(p.PWM0, p.P0_23, p.P0_22, p.P0_24, &Default::default());
38 pwm.set_prescaler(Prescaler::Div1); 38 pwm.set_prescaler(Prescaler::Div1);
39 pwm.set_max_duty(255); 39 pwm.set_max_duty(255);
40 40
@@ -47,9 +47,8 @@ async fn main(_spawner: Spawner) {
47 let rgb = rgb_from_rms(rms); 47 let rgb = rgb_from_rms(rms);
48 48
49 debug!("RMS: {}, RGB: {:?}", rms, rgb); 49 debug!("RMS: {}, RGB: {:?}", rms, rgb);
50 for i in 0..3 { 50 let duties = rgb.map(|byte| DutyCycle::normal(u16::from(byte)));
51 pwm.set_duty(i, rgb[i].into()); 51 pwm.set_all_duties([duties[0], duties[1], duties[2], DutyCycle::normal(0)]);
52 }
53 52
54 if let Err(err) = input_stream.receive().await { 53 if let Err(err) = input_stream.receive().await {
55 error!("{}", err); 54 error!("{}", err);
diff --git a/examples/nrf52840/src/bin/i2s_waveform.rs b/examples/nrf52840/src/bin/i2s_waveform.rs
index 137d82840..ce7a68d3a 100644
--- a/examples/nrf52840/src/bin/i2s_waveform.rs
+++ b/examples/nrf52840/src/bin/i2s_waveform.rs
@@ -5,7 +5,7 @@ use core::f32::consts::PI;
5 5
6use defmt::{error, info}; 6use defmt::{error, info};
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; 8use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth};
9use embassy_nrf::{bind_interrupts, peripherals}; 9use embassy_nrf::{bind_interrupts, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
@@ -140,11 +140,7 @@ impl SineOsc {
140 140
141#[inline] 141#[inline]
142fn abs(value: f32) -> f32 { 142fn abs(value: f32) -> f32 {
143 if value < 0.0 { 143 if value < 0.0 { -value } else { value }
144 -value
145 } else {
146 value
147 }
148} 144}
149 145
150#[inline] 146#[inline]
diff --git a/examples/nrf52840/src/bin/ieee802154_receive.rs b/examples/nrf52840/src/bin/ieee802154_receive.rs
new file mode 100644
index 000000000..ede8fca65
--- /dev/null
+++ b/examples/nrf52840/src/bin/ieee802154_receive.rs
@@ -0,0 +1,38 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::config::{Config, HfclkSource};
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_nrf::radio::ieee802154::{self, Packet};
8use embassy_nrf::{peripherals, radio};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12embassy_nrf::bind_interrupts!(struct Irqs {
13 RADIO => radio::InterruptHandler<peripherals::RADIO>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.hfclk_source = HfclkSource::ExternalXtal;
20 let peripherals = embassy_nrf::init(config);
21
22 // assumes LED on P0_15 with active-high polarity
23 let mut gpo_led = Output::new(peripherals.P0_15, Level::Low, OutputDrive::Standard);
24
25 let mut radio = ieee802154::Radio::new(peripherals.RADIO, Irqs);
26 let mut packet = Packet::new();
27
28 loop {
29 gpo_led.set_low();
30 let rv = radio.receive(&mut packet).await;
31 gpo_led.set_high();
32 match rv {
33 Err(_) => defmt::error!("receive() Err"),
34 Ok(_) => defmt::info!("receive() {:?}", *packet),
35 }
36 Timer::after_millis(100u64).await;
37 }
38}
diff --git a/examples/nrf52840/src/bin/ieee802154_send.rs b/examples/nrf52840/src/bin/ieee802154_send.rs
new file mode 100644
index 000000000..7af9d1d06
--- /dev/null
+++ b/examples/nrf52840/src/bin/ieee802154_send.rs
@@ -0,0 +1,39 @@
1#![no_std]
2#![no_main]
3
4use embassy_executor::Spawner;
5use embassy_nrf::config::{Config, HfclkSource};
6use embassy_nrf::gpio::{Level, Output, OutputDrive};
7use embassy_nrf::radio::ieee802154::{self, Packet};
8use embassy_nrf::{peripherals, radio};
9use embassy_time::Timer;
10use {defmt_rtt as _, panic_probe as _};
11
12embassy_nrf::bind_interrupts!(struct Irqs {
13 RADIO => radio::InterruptHandler<peripherals::RADIO>;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = Config::default();
19 config.hfclk_source = HfclkSource::ExternalXtal;
20 let peripherals = embassy_nrf::init(config);
21
22 // assumes LED on P0_15 with active-high polarity
23 let mut gpo_led = Output::new(peripherals.P0_15, Level::Low, OutputDrive::Standard);
24
25 let mut radio = ieee802154::Radio::new(peripherals.RADIO, Irqs);
26 let mut packet = Packet::new();
27
28 loop {
29 packet.copy_from_slice(&[0_u8; 16]);
30 gpo_led.set_high();
31 let rv = radio.try_send(&mut packet).await;
32 gpo_led.set_low();
33 match rv {
34 Err(_) => defmt::error!("try_send() Err"),
35 Ok(_) => defmt::info!("try_send() {:?}", *packet),
36 }
37 Timer::after_millis(1000u64).await;
38 }
39}
diff --git a/examples/nrf52840/src/bin/manually_create_executor.rs b/examples/nrf52840/src/bin/manually_create_executor.rs
index 7ca39348e..f0639eb23 100644
--- a/examples/nrf52840/src/bin/manually_create_executor.rs
+++ b/examples/nrf52840/src/bin/manually_create_executor.rs
@@ -42,7 +42,7 @@ fn main() -> ! {
42 // `run` calls the closure then runs the executor forever. It never returns. 42 // `run` calls the closure then runs the executor forever. It never returns.
43 executor.run(|spawner| { 43 executor.run(|spawner| {
44 // Here we get access to a spawner to spawn the initial tasks. 44 // Here we get access to a spawner to spawn the initial tasks.
45 unwrap!(spawner.spawn(run1())); 45 spawner.spawn(unwrap!(run1()));
46 unwrap!(spawner.spawn(run2())); 46 spawner.spawn(unwrap!(run2()));
47 }); 47 });
48} 48}
diff --git a/examples/nrf52840/src/bin/multiprio.rs b/examples/nrf52840/src/bin/multiprio.rs
index 797be93a7..dc566adee 100644
--- a/examples/nrf52840/src/bin/multiprio.rs
+++ b/examples/nrf52840/src/bin/multiprio.rs
@@ -112,13 +112,13 @@ static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); 112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113 113
114#[interrupt] 114#[interrupt]
115unsafe fn SWI1_EGU1() { 115unsafe fn EGU1_SWI1() {
116 EXECUTOR_HIGH.on_interrupt() 116 unsafe { EXECUTOR_HIGH.on_interrupt() }
117} 117}
118 118
119#[interrupt] 119#[interrupt]
120unsafe fn SWI0_EGU0() { 120unsafe fn EGU0_SWI0() {
121 EXECUTOR_MED.on_interrupt() 121 unsafe { EXECUTOR_MED.on_interrupt() }
122} 122}
123 123
124#[entry] 124#[entry]
@@ -127,19 +127,19 @@ fn main() -> ! {
127 127
128 let _p = embassy_nrf::init(Default::default()); 128 let _p = embassy_nrf::init(Default::default());
129 129
130 // High-priority executor: SWI1_EGU1, priority level 6 130 // High-priority executor: EGU1_SWI1, priority level 6
131 interrupt::SWI1_EGU1.set_priority(Priority::P6); 131 interrupt::EGU1_SWI1.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::SWI1_EGU1); 132 let spawner = EXECUTOR_HIGH.start(interrupt::EGU1_SWI1);
133 unwrap!(spawner.spawn(run_high())); 133 spawner.spawn(unwrap!(run_high()));
134 134
135 // Medium-priority executor: SWI0_EGU0, priority level 7 135 // Medium-priority executor: EGU0_SWI0, priority level 7
136 interrupt::SWI0_EGU0.set_priority(Priority::P7); 136 interrupt::EGU0_SWI0.set_priority(Priority::P7);
137 let spawner = EXECUTOR_MED.start(interrupt::SWI0_EGU0); 137 let spawner = EXECUTOR_MED.start(interrupt::EGU0_SWI0);
138 unwrap!(spawner.spawn(run_med())); 138 spawner.spawn(unwrap!(run_med()));
139 139
140 // Low priority executor: runs in thread mode, using WFE/SEV 140 // Low priority executor: runs in thread mode, using WFE/SEV
141 let executor = EXECUTOR_LOW.init(Executor::new()); 141 let executor = EXECUTOR_LOW.init(Executor::new());
142 executor.run(|spawner| { 142 executor.run(|spawner| {
143 unwrap!(spawner.spawn(run_low())); 143 spawner.spawn(unwrap!(run_low()));
144 }); 144 });
145} 145}
diff --git a/examples/nrf52840/src/bin/mutex.rs b/examples/nrf52840/src/bin/mutex.rs
index 5c22279b5..a8e9a82cc 100644
--- a/examples/nrf52840/src/bin/mutex.rs
+++ b/examples/nrf52840/src/bin/mutex.rs
@@ -30,7 +30,7 @@ async fn my_task() {
30#[embassy_executor::main] 30#[embassy_executor::main]
31async fn main(spawner: Spawner) { 31async fn main(spawner: Spawner) {
32 let _p = embassy_nrf::init(Default::default()); 32 let _p = embassy_nrf::init(Default::default());
33 unwrap!(spawner.spawn(my_task())); 33 spawner.spawn(unwrap!(my_task()));
34 34
35 loop { 35 loop {
36 Timer::after_millis(300).await; 36 Timer::after_millis(300).await;
diff --git a/examples/nrf52840/src/bin/nfct.rs b/examples/nrf52840/src/bin/nfct.rs
new file mode 100644
index 000000000..fafa37f48
--- /dev/null
+++ b/examples/nrf52840/src/bin/nfct.rs
@@ -0,0 +1,323 @@
1#![no_std]
2#![no_main]
3
4use defmt::{todo, *};
5use embassy_executor::Spawner;
6use embassy_nrf::config::HfclkSource;
7use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT};
8use embassy_nrf::{bind_interrupts, nfct};
9use iso14443_4::{Card, IsoDep};
10use {defmt_rtt as _, embassy_nrf as _, panic_probe as _};
11
12bind_interrupts!(struct Irqs {
13 NFCT => nfct::InterruptHandler;
14});
15
16#[embassy_executor::main]
17async fn main(_spawner: Spawner) {
18 let mut config = embassy_nrf::config::Config::default();
19 config.hfclk_source = HfclkSource::ExternalXtal;
20 let p = embassy_nrf::init(config);
21
22 dbg!("Setting up...");
23 let config = NfcConfig {
24 nfcid1: NfcId::DoubleSize([0x04, 0x68, 0x95, 0x71, 0xFA, 0x5C, 0x64]),
25 sdd_pat: nfct::SddPat::SDD00100,
26 plat_conf: 0b0000,
27 protocol: nfct::SelResProtocol::Type4A,
28 };
29
30 let mut nfc = NfcT::new(p.NFCT, Irqs, &config);
31
32 let mut buf = [0u8; 256];
33
34 let cc = &[
35 0x00, 0x0f, /* CCEN_HI, CCEN_LOW */
36 0x20, /* VERSION */
37 0x00, 0x7f, /* MLe_HI, MLe_LOW */
38 0x00, 0x7f, /* MLc_HI, MLc_LOW */
39 /* TLV */
40 0x04, 0x06, 0xe1, 0x04, 0x00, 0x7f, 0x00, 0x00,
41 ];
42
43 let ndef = &[
44 0x00, 0x10, 0xd1, 0x1, 0xc, 0x55, 0x4, 0x65, 0x6d, 0x62, 0x61, 0x73, 0x73, 0x79, 0x2e, 0x64, 0x65, 0x76,
45 ];
46 let mut selected: &[u8] = cc;
47
48 loop {
49 info!("activating");
50 nfc.activate().await;
51 info!("activated!");
52
53 let mut nfc = IsoDep::new(iso14443_3::Logger(&mut nfc));
54
55 loop {
56 let n = match nfc.receive(&mut buf).await {
57 Ok(n) => n,
58 Err(e) => {
59 error!("rx error {}", e);
60 break;
61 }
62 };
63 let req = &buf[..n];
64 info!("iso-dep rx {:02x}", req);
65
66 let Ok(apdu) = Apdu::parse(req) else {
67 error!("apdu parse error");
68 break;
69 };
70
71 info!("apdu: {:?}", apdu);
72
73 let resp = match (apdu.cla, apdu.ins, apdu.p1, apdu.p2) {
74 (0, 0xa4, 4, 0) => {
75 info!("select app");
76 &[0x90, 0x00][..]
77 }
78 (0, 0xa4, 0, 12) => {
79 info!("select df");
80 match apdu.data {
81 [0xe1, 0x03] => {
82 selected = cc;
83 &[0x90, 0x00][..]
84 }
85 [0xe1, 0x04] => {
86 selected = ndef;
87 &[0x90, 0x00][..]
88 }
89 _ => todo!(), // return NOT FOUND
90 }
91 }
92 (0, 0xb0, p1, p2) => {
93 info!("read");
94 let offs = u16::from_be_bytes([p1 & 0x7f, p2]) as usize;
95 let len = if apdu.le == 0 { usize::MAX } else { apdu.le as usize };
96 let n = len.min(selected.len() - offs);
97 buf[..n].copy_from_slice(&selected[offs..][..n]);
98 buf[n..][..2].copy_from_slice(&[0x90, 0x00]);
99 &buf[..n + 2]
100 }
101 _ => {
102 info!("Got unknown command!");
103 &[0xFF, 0xFF]
104 }
105 };
106
107 info!("iso-dep tx {:02x}", resp);
108
109 match nfc.transmit(resp).await {
110 Ok(()) => {}
111 Err(e) => {
112 error!("tx error {}", e);
113 break;
114 }
115 }
116 }
117 }
118}
119
120#[derive(Debug, Clone, defmt::Format)]
121struct Apdu<'a> {
122 pub cla: u8,
123 pub ins: u8,
124 pub p1: u8,
125 pub p2: u8,
126 pub data: &'a [u8],
127 pub le: u16,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
131struct ApduParseError;
132
133impl<'a> Apdu<'a> {
134 pub fn parse(apdu: &'a [u8]) -> Result<Self, ApduParseError> {
135 if apdu.len() < 4 {
136 return Err(ApduParseError);
137 }
138
139 let (data, le) = match apdu.len() - 4 {
140 0 => (&[][..], 0),
141 1 => (&[][..], apdu[4]),
142 n if n == 1 + apdu[4] as usize && apdu[4] != 0 => (&apdu[5..][..apdu[4] as usize], 0),
143 n if n == 2 + apdu[4] as usize && apdu[4] != 0 => (&apdu[5..][..apdu[4] as usize], apdu[apdu.len() - 1]),
144 _ => return Err(ApduParseError),
145 };
146
147 Ok(Apdu {
148 cla: apdu[0],
149 ins: apdu[1],
150 p1: apdu[2],
151 p2: apdu[3],
152 data,
153 le: le as _,
154 })
155 }
156}
157
158mod iso14443_3 {
159 use core::future::Future;
160
161 use defmt::info;
162 use embassy_nrf::nfct::{Error, NfcT};
163
164 pub trait Card {
165 type Error;
166 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
167 async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
168 }
169
170 impl<'a, T: Card> Card for &'a mut T {
171 type Error = T::Error;
172
173 fn receive(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> {
174 T::receive(self, buf)
175 }
176
177 fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> {
178 T::transmit(self, buf)
179 }
180 }
181
182 impl<'a> Card for NfcT<'a> {
183 type Error = Error;
184
185 fn receive(&mut self, buf: &mut [u8]) -> impl Future<Output = Result<usize, Self::Error>> {
186 self.receive(buf)
187 }
188
189 fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> {
190 self.transmit(buf)
191 }
192 }
193
194 pub struct Logger<T: Card>(pub T);
195
196 impl<T: Card> Card for Logger<T> {
197 type Error = T::Error;
198
199 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
200 let n = T::receive(&mut self.0, buf).await?;
201 info!("<- {:02x}", &buf[..n]);
202 Ok(n)
203 }
204
205 fn transmit(&mut self, buf: &[u8]) -> impl Future<Output = Result<(), Self::Error>> {
206 info!("-> {:02x}", buf);
207 T::transmit(&mut self.0, buf)
208 }
209 }
210}
211
212mod iso14443_4 {
213 use defmt::info;
214
215 use crate::iso14443_3;
216
217 #[derive(defmt::Format)]
218 pub enum Error<T> {
219 Deselected,
220 Protocol,
221 Lower(T),
222 }
223
224 pub trait Card {
225 type Error;
226 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
227 async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
228 }
229
230 pub struct IsoDep<T: iso14443_3::Card> {
231 nfc: T,
232
233 /// Block count spin bit: 0 or 1
234 block_num: u8,
235
236 /// true if deselected. This is permanent, you must create another IsoDep
237 /// instance if we get selected again.
238 deselected: bool,
239
240 /// last response, in case we need to retransmit.
241 resp: [u8; 256],
242 resp_len: usize,
243 }
244
245 impl<T: iso14443_3::Card> IsoDep<T> {
246 pub fn new(nfc: T) -> Self {
247 Self {
248 nfc,
249 block_num: 1,
250 deselected: false,
251 resp: [0u8; 256],
252 resp_len: 0,
253 }
254 }
255 }
256
257 impl<T: iso14443_3::Card> Card for IsoDep<T> {
258 type Error = Error<T::Error>;
259
260 async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
261 if self.deselected {
262 return Err(Error::Deselected);
263 }
264
265 let mut temp = [0u8; 256];
266
267 loop {
268 let n = self.nfc.receive(&mut temp).await.map_err(Error::Lower)?;
269 assert!(n != 0);
270 match temp[0] {
271 0x02 | 0x03 => {
272 self.block_num ^= 0x01;
273 assert!(temp[0] == 0x02 | self.block_num);
274 buf[..n - 1].copy_from_slice(&temp[1..n]);
275 return Ok(n - 1);
276 }
277 0xb2 | 0xb3 => {
278 if temp[0] & 0x01 != self.block_num {
279 info!("Got NAK, transmitting ACK.");
280 let resp = &[0xA2 | self.block_num];
281 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
282 } else {
283 info!("Got NAK, retransmitting.");
284 let resp: &[u8] = &self.resp[..self.resp_len];
285 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
286 }
287 }
288 0xe0 => {
289 info!("Got RATS, tx'ing ATS");
290 let resp = &[0x06, 0x77, 0x77, 0x81, 0x02, 0x80];
291 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
292 }
293 0xc2 => {
294 info!("Got deselect!");
295 self.deselected = true;
296 let resp = &[0xC2];
297 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
298 return Err(Error::Deselected);
299 }
300 _ => {
301 info!("Got unknown command {:02x}!", temp[0]);
302 return Err(Error::Protocol);
303 }
304 };
305 }
306 }
307
308 async fn transmit(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
309 if self.deselected {
310 return Err(Error::Deselected);
311 }
312
313 self.resp[0] = 0x02 | self.block_num;
314 self.resp[1..][..buf.len()].copy_from_slice(buf);
315 self.resp_len = 1 + buf.len();
316
317 let resp: &[u8] = &self.resp[..self.resp_len];
318 self.nfc.transmit(resp).await.map_err(Error::Lower)?;
319
320 Ok(())
321 }
322 }
323}
diff --git a/examples/nrf52840/src/bin/pdm_continuous.rs b/examples/nrf52840/src/bin/pdm_continuous.rs
index e948203a5..0d76636b0 100644
--- a/examples/nrf52840/src/bin/pdm_continuous.rs
+++ b/examples/nrf52840/src/bin/pdm_continuous.rs
@@ -20,14 +20,14 @@ bind_interrupts!(struct Irqs {
20 20
21#[embassy_executor::main] 21#[embassy_executor::main]
22async fn main(_p: Spawner) { 22async fn main(_p: Spawner) {
23 let mut p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
24 let mut config = Config::default(); 24 let mut config = Config::default();
25 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense. 25 // Pins are correct for the onboard microphone on the Feather nRF52840 Sense.
26 config.frequency = Frequency::_1280K; // 16 kHz sample rate 26 config.frequency = Frequency::_1280K; // 16 kHz sample rate
27 config.ratio = Ratio::RATIO80; 27 config.ratio = Ratio::RATIO80;
28 config.operation_mode = OperationMode::Mono; 28 config.operation_mode = OperationMode::Mono;
29 config.gain_left = I7F1::from_bits(5); // 2.5 dB 29 config.gain_left = I7F1::from_bits(5); // 2.5 dB
30 let mut pdm = Pdm::new(p.PDM, Irqs, &mut p.P0_00, &mut p.P0_01, config); 30 let mut pdm = Pdm::new(p.PDM, Irqs, p.P0_00, p.P0_01, config);
31 31
32 let mut bufs = [[0; 1024]; 2]; 32 let mut bufs = [[0; 1024]; 2];
33 33
diff --git a/examples/nrf52840/src/bin/ppi.rs b/examples/nrf52840/src/bin/ppi.rs
index 129ad06e7..177f6a06d 100644
--- a/examples/nrf52840/src/bin/ppi.rs
+++ b/examples/nrf52840/src/bin/ppi.rs
@@ -5,7 +5,7 @@ use core::future::pending;
5 5
6use defmt::info; 6use defmt::info;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 8use embassy_nrf::gpio::{Level, OutputDrive, Pull};
9use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; 9use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity};
10use embassy_nrf::ppi::Ppi; 10use embassy_nrf::ppi::Ppi;
11use gpiote::{OutputChannel, OutputChannelPolarity}; 11use gpiote::{OutputChannel, OutputChannelPolarity};
@@ -16,36 +16,24 @@ async fn main(_spawner: Spawner) {
16 let p = embassy_nrf::init(Default::default()); 16 let p = embassy_nrf::init(Default::default());
17 info!("Starting!"); 17 info!("Starting!");
18 18
19 let button1 = InputChannel::new( 19 let button1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo);
20 p.GPIOTE_CH0, 20 let button2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::HiToLo);
21 Input::new(p.P0_11, Pull::Up), 21 let button3 = InputChannel::new(p.GPIOTE_CH2, p.P0_24, Pull::Up, InputChannelPolarity::HiToLo);
22 InputChannelPolarity::HiToLo, 22 let button4 = InputChannel::new(p.GPIOTE_CH3, p.P0_25, Pull::Up, InputChannelPolarity::HiToLo);
23 );
24 let button2 = InputChannel::new(
25 p.GPIOTE_CH1,
26 Input::new(p.P0_12, Pull::Up),
27 InputChannelPolarity::HiToLo,
28 );
29 let button3 = InputChannel::new(
30 p.GPIOTE_CH2,
31 Input::new(p.P0_24, Pull::Up),
32 InputChannelPolarity::HiToLo,
33 );
34 let button4 = InputChannel::new(
35 p.GPIOTE_CH3,
36 Input::new(p.P0_25, Pull::Up),
37 InputChannelPolarity::HiToLo,
38 );
39 23
40 let led1 = OutputChannel::new( 24 let led1 = OutputChannel::new(
41 p.GPIOTE_CH4, 25 p.GPIOTE_CH4,
42 Output::new(p.P0_13, Level::Low, OutputDrive::Standard), 26 p.P0_13,
27 Level::Low,
28 OutputDrive::Standard,
43 OutputChannelPolarity::Toggle, 29 OutputChannelPolarity::Toggle,
44 ); 30 );
45 31
46 let led2 = OutputChannel::new( 32 let led2 = OutputChannel::new(
47 p.GPIOTE_CH5, 33 p.GPIOTE_CH5,
48 Output::new(p.P0_14, Level::Low, OutputDrive::Standard), 34 p.P0_14,
35 Level::Low,
36 OutputDrive::Standard,
49 OutputChannelPolarity::Toggle, 37 OutputChannelPolarity::Toggle,
50 ); 38 );
51 39
diff --git a/examples/nrf52840/src/bin/pubsub.rs b/examples/nrf52840/src/bin/pubsub.rs
index 5ebea9220..c0392b18c 100644
--- a/examples/nrf52840/src/bin/pubsub.rs
+++ b/examples/nrf52840/src/bin/pubsub.rs
@@ -26,9 +26,9 @@ async fn main(spawner: Spawner) {
26 // It's good to set up the subscribers before publishing anything. 26 // It's good to set up the subscribers before publishing anything.
27 // A subscriber will only yield messages that have been published after its creation. 27 // A subscriber will only yield messages that have been published after its creation.
28 28
29 spawner.must_spawn(fast_logger(unwrap!(MESSAGE_BUS.subscriber()))); 29 spawner.spawn(fast_logger(unwrap!(MESSAGE_BUS.subscriber())).unwrap());
30 spawner.must_spawn(slow_logger(unwrap!(MESSAGE_BUS.dyn_subscriber()))); 30 spawner.spawn(slow_logger(unwrap!(MESSAGE_BUS.dyn_subscriber())).unwrap());
31 spawner.must_spawn(slow_logger_pure(unwrap!(MESSAGE_BUS.dyn_subscriber()))); 31 spawner.spawn(slow_logger_pure(unwrap!(MESSAGE_BUS.dyn_subscriber())).unwrap());
32 32
33 // Get a publisher 33 // Get a publisher
34 let message_publisher = unwrap!(MESSAGE_BUS.publisher()); 34 let message_publisher = unwrap!(MESSAGE_BUS.publisher());
diff --git a/examples/nrf52840/src/bin/pwm.rs b/examples/nrf52840/src/bin/pwm.rs
index a5bb1347a..02f9b4191 100644
--- a/examples/nrf52840/src/bin/pwm.rs
+++ b/examples/nrf52840/src/bin/pwm.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::pwm::{Prescaler, SimplePwm}; 6use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm};
7use embassy_time::Timer; 7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
@@ -71,7 +71,7 @@ static DUTY: [u16; 1024] = [
71#[embassy_executor::main] 71#[embassy_executor::main]
72async fn main(_spawner: Spawner) { 72async fn main(_spawner: Spawner) {
73 let p = embassy_nrf::init(Default::default()); 73 let p = embassy_nrf::init(Default::default());
74 let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15); 74 let mut pwm = SimplePwm::new_4ch(p.PWM0, p.P0_13, p.P0_14, p.P0_16, p.P0_15, &Default::default());
75 pwm.set_prescaler(Prescaler::Div1); 75 pwm.set_prescaler(Prescaler::Div1);
76 pwm.set_max_duty(32767); 76 pwm.set_max_duty(32767);
77 info!("pwm initialized!"); 77 info!("pwm initialized!");
@@ -79,10 +79,12 @@ async fn main(_spawner: Spawner) {
79 let mut i = 0; 79 let mut i = 0;
80 loop { 80 loop {
81 i += 1; 81 i += 1;
82 pwm.set_duty(0, DUTY[i % 1024]); 82 pwm.set_all_duties([
83 pwm.set_duty(1, DUTY[(i + 256) % 1024]); 83 DutyCycle::normal(DUTY[i % 1024]),
84 pwm.set_duty(2, DUTY[(i + 512) % 1024]); 84 DutyCycle::normal(DUTY[(i + 256) % 1024]),
85 pwm.set_duty(3, DUTY[(i + 768) % 1024]); 85 DutyCycle::normal(DUTY[(i + 512) % 1024]),
86 DutyCycle::normal(DUTY[(i + 768) % 1024]),
87 ]);
86 Timer::after_millis(3).await; 88 Timer::after_millis(3).await;
87 } 89 }
88} 90}
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
index 60ea712b5..fff7decb2 100644
--- a/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ppi.rs
@@ -5,7 +5,7 @@ use core::future::pending;
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_nrf::gpio::{Input, Pull}; 8use embassy_nrf::gpio::Pull;
9use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; 9use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity};
10use embassy_nrf::ppi::Ppi; 10use embassy_nrf::ppi::Ppi;
11use embassy_nrf::pwm::{Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer}; 11use embassy_nrf::pwm::{Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer};
@@ -30,17 +30,9 @@ async fn main(_spawner: Spawner) {
30 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work 30 // pwm.stop() deconfigures pins, and then the task_start_seq0 task cant work
31 // so its going to have to start running in order load the configuration 31 // so its going to have to start running in order load the configuration
32 32
33 let button1 = InputChannel::new( 33 let button1 = InputChannel::new(p.GPIOTE_CH0, p.P0_11, Pull::Up, InputChannelPolarity::HiToLo);
34 p.GPIOTE_CH0,
35 Input::new(p.P0_11, Pull::Up),
36 InputChannelPolarity::HiToLo,
37 );
38 34
39 let button2 = InputChannel::new( 35 let button2 = InputChannel::new(p.GPIOTE_CH1, p.P0_12, Pull::Up, InputChannelPolarity::HiToLo);
40 p.GPIOTE_CH1,
41 Input::new(p.P0_12, Pull::Up),
42 InputChannelPolarity::HiToLo,
43 );
44 36
45 // messing with the pwm tasks is ill advised 37 // messing with the pwm tasks is ill advised
46 // Times::Ininite and Times even are seq0, Times odd is seq1 38 // Times::Ininite and Times even are seq0, Times odd is seq1
diff --git a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
index 751cf4425..df8da8800 100644
--- a/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
+++ b/examples/nrf52840/src/bin/pwm_sequence_ws2812b.rs
@@ -14,6 +14,16 @@ use {defmt_rtt as _, panic_probe as _};
14// https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf. 14// https://cdn-shop.adafruit.com/datasheets/WS2812B.pdf.
15// This demo lights up a single LED in blue. It then proceeds 15// This demo lights up a single LED in blue. It then proceeds
16// to pulsate the LED rapidly. 16// to pulsate the LED rapidly.
17//
18// /!\ NOTE FOR nRF52840-DK users /!\
19//
20// If you're using the nRF52840-DK, the default "Vdd" power source
21// will set the GPIO I/O voltage to 3.0v, using the onboard regulator.
22// This can sometimes not be enough to drive the WS2812B signal if you
23// are not using an external level shifter. If you set the board to "USB"
24// power instead (and provide power via the "nRF USB" connector), the board
25// will instead power the I/Os at 3.3v, which is often enough (but still
26// out of official spec) for the WS2812Bs to work properly.
17 27
18// In the following declarations, setting the high bit tells the PWM 28// In the following declarations, setting the high bit tells the PWM
19// to reverse polarity, which is what the WS2812B expects. 29// to reverse polarity, which is what the WS2812B expects.
diff --git a/examples/nrf52840/src/bin/pwm_servo.rs b/examples/nrf52840/src/bin/pwm_servo.rs
index d772d2f5d..93cb984e6 100644
--- a/examples/nrf52840/src/bin/pwm_servo.rs
+++ b/examples/nrf52840/src/bin/pwm_servo.rs
@@ -3,14 +3,14 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::pwm::{Prescaler, SimplePwm}; 6use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm};
7use embassy_time::Timer; 7use embassy_time::Timer;
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
11async fn main(_spawner: Spawner) { 11async fn main(_spawner: Spawner) {
12 let p = embassy_nrf::init(Default::default()); 12 let p = embassy_nrf::init(Default::default());
13 let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05); 13 let mut pwm = SimplePwm::new_1ch(p.PWM0, p.P0_05, &Default::default());
14 // sg90 microervo requires 50hz or 20ms period 14 // sg90 microervo requires 50hz or 20ms period
15 // set_period can only set down to 125khz so we cant use it directly 15 // set_period can only set down to 125khz so we cant use it directly
16 // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top 16 // Div128 is 125khz or 0.000008s or 0.008ms, 20/0.008 is 2500 is top
@@ -24,23 +24,23 @@ async fn main(_spawner: Spawner) {
24 loop { 24 loop {
25 info!("45 deg"); 25 info!("45 deg");
26 // poor mans inverting, subtract our value from max_duty 26 // poor mans inverting, subtract our value from max_duty
27 pwm.set_duty(0, 2500 - 156); 27 pwm.set_duty(0, DutyCycle::normal(2500 - 156));
28 Timer::after_millis(5000).await; 28 Timer::after_millis(5000).await;
29 29
30 info!("90 deg"); 30 info!("90 deg");
31 pwm.set_duty(0, 2500 - 187); 31 pwm.set_duty(0, DutyCycle::normal(2500 - 187));
32 Timer::after_millis(5000).await; 32 Timer::after_millis(5000).await;
33 33
34 info!("135 deg"); 34 info!("135 deg");
35 pwm.set_duty(0, 2500 - 218); 35 pwm.set_duty(0, DutyCycle::normal(2500 - 218));
36 Timer::after_millis(5000).await; 36 Timer::after_millis(5000).await;
37 37
38 info!("180 deg"); 38 info!("180 deg");
39 pwm.set_duty(0, 2500 - 250); 39 pwm.set_duty(0, DutyCycle::normal(2500 - 250));
40 Timer::after_millis(5000).await; 40 Timer::after_millis(5000).await;
41 41
42 info!("0 deg"); 42 info!("0 deg");
43 pwm.set_duty(0, 2500 - 125); 43 pwm.set_duty(0, DutyCycle::normal(2500 - 125));
44 Timer::after_millis(5000).await; 44 Timer::after_millis(5000).await;
45 } 45 }
46} 46}
diff --git a/examples/nrf52840/src/bin/qspi_lowpower.rs b/examples/nrf52840/src/bin/qspi_lowpower.rs
index 516c9b481..238a0d941 100644
--- a/examples/nrf52840/src/bin/qspi_lowpower.rs
+++ b/examples/nrf52840/src/bin/qspi_lowpower.rs
@@ -37,14 +37,14 @@ async fn main(_p: Spawner) {
37 }); 37 });
38 38
39 let mut q = qspi::Qspi::new( 39 let mut q = qspi::Qspi::new(
40 &mut p.QSPI, 40 p.QSPI.reborrow(),
41 Irqs, 41 Irqs,
42 &mut p.P0_19, 42 p.P0_19.reborrow(),
43 &mut p.P0_17, 43 p.P0_17.reborrow(),
44 &mut p.P0_20, 44 p.P0_20.reborrow(),
45 &mut p.P0_21, 45 p.P0_21.reborrow(),
46 &mut p.P0_22, 46 p.P0_22.reborrow(),
47 &mut p.P0_23, 47 p.P0_23.reborrow(),
48 config, 48 config,
49 ); 49 );
50 50
diff --git a/examples/nrf52840/src/bin/raw_spawn.rs b/examples/nrf52840/src/bin/raw_spawn.rs
index 717b0faa6..783be763d 100644
--- a/examples/nrf52840/src/bin/raw_spawn.rs
+++ b/examples/nrf52840/src/bin/raw_spawn.rs
@@ -5,8 +5,8 @@ use core::mem;
5 5
6use cortex_m_rt::entry; 6use cortex_m_rt::entry;
7use defmt::{info, unwrap}; 7use defmt::{info, unwrap};
8use embassy_executor::raw::TaskStorage;
9use embassy_executor::Executor; 8use embassy_executor::Executor;
9use embassy_executor::raw::TaskStorage;
10use embassy_time::Timer; 10use embassy_time::Timer;
11use static_cell::StaticCell; 11use static_cell::StaticCell;
12use {defmt_rtt as _, panic_probe as _}; 12use {defmt_rtt as _, panic_probe as _};
@@ -42,11 +42,11 @@ fn main() -> ! {
42 let run2_task = unsafe { make_static(&run2_task) }; 42 let run2_task = unsafe { make_static(&run2_task) };
43 43
44 executor.run(|spawner| { 44 executor.run(|spawner| {
45 unwrap!(spawner.spawn(run1_task.spawn(|| run1()))); 45 spawner.spawn(unwrap!(run1_task.spawn(|| run1())));
46 unwrap!(spawner.spawn(run2_task.spawn(|| run2()))); 46 spawner.spawn(unwrap!(run2_task.spawn(|| run2())));
47 }); 47 });
48} 48}
49 49
50unsafe fn make_static<T>(t: &T) -> &'static T { 50unsafe fn make_static<T>(t: &T) -> &'static T {
51 mem::transmute(t) 51 unsafe { mem::transmute(t) }
52} 52}
diff --git a/examples/nrf52840/src/bin/rng.rs b/examples/nrf52840/src/bin/rng.rs
index 326054c9a..f32d17cd9 100644..100755
--- a/examples/nrf52840/src/bin/rng.rs
+++ b/examples/nrf52840/src/bin/rng.rs
@@ -22,7 +22,7 @@ async fn main(_spawner: Spawner) {
22 defmt::info!("Some random bytes: {:?}", bytes); 22 defmt::info!("Some random bytes: {:?}", bytes);
23 23
24 // Sync API with `rand` 24 // Sync API with `rand`
25 defmt::info!("A random number from 1 to 10: {:?}", rng.gen_range(1..=10)); 25 defmt::info!("A random number from 1 to 10: {:?}", rng.random_range(1..=10));
26 26
27 let mut bytes = [0; 1024]; 27 let mut bytes = [0; 1024];
28 rng.fill_bytes(&mut bytes).await; 28 rng.fill_bytes(&mut bytes).await;
diff --git a/examples/nrf52840/src/bin/rtc.rs b/examples/nrf52840/src/bin/rtc.rs
new file mode 100644
index 000000000..56a0c25f4
--- /dev/null
+++ b/examples/nrf52840/src/bin/rtc.rs
@@ -0,0 +1,56 @@
1#![no_std]
2#![no_main]
3
4use core::cell::RefCell;
5
6use embassy_executor::Spawner;
7use embassy_nrf::gpio::{Level, Output, OutputDrive};
8use embassy_nrf::interrupt;
9use embassy_nrf::rtc::Rtc;
10use embassy_sync::blocking_mutex::Mutex;
11use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
12use portable_atomic::AtomicU64;
13use {defmt_rtt as _, panic_probe as _};
14
15// 64 bit counter which will never overflow.
16static TICK_COUNTER: AtomicU64 = AtomicU64::new(0);
17static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static>>>> = Mutex::new(RefCell::new(None));
18
19#[embassy_executor::main]
20async fn main(_spawner: Spawner) {
21 defmt::println!("nRF52840 RTC example");
22 let p = embassy_nrf::init(Default::default());
23 let mut led = Output::new(p.P0_13, Level::High, OutputDrive::Standard);
24 // Counter resolution is 125 ms.
25 let mut rtc = Rtc::new(p.RTC0, (1 << 12) - 1).unwrap();
26 rtc.enable_interrupt(embassy_nrf::rtc::Interrupt::Tick, true);
27 rtc.enable_event(embassy_nrf::rtc::Interrupt::Tick);
28 rtc.enable();
29 RTC.lock(|r| {
30 let mut rtc_borrow = r.borrow_mut();
31 *rtc_borrow = Some(rtc);
32 });
33
34 let mut last_counter_val = 0;
35 loop {
36 let current = TICK_COUNTER.load(core::sync::atomic::Ordering::Relaxed);
37 if current != last_counter_val {
38 led.toggle();
39 last_counter_val = current;
40 }
41 }
42}
43
44#[interrupt]
45fn RTC0() {
46 // For 64-bit, we do not need to worry about overflowing, at least not for realistic program
47 // lifetimes.
48 TICK_COUNTER.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
49 RTC.lock(|r| {
50 let mut rtc_borrow = r.borrow_mut();
51 rtc_borrow
52 .as_mut()
53 .unwrap()
54 .reset_event(embassy_nrf::rtc::Interrupt::Tick);
55 });
56}
diff --git a/examples/nrf52840/src/bin/saadc.rs b/examples/nrf52840/src/bin/saadc.rs
index 653b7d606..cf2d860ab 100644
--- a/examples/nrf52840/src/bin/saadc.rs
+++ b/examples/nrf52840/src/bin/saadc.rs
@@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs {
16async fn main(_p: Spawner) { 16async fn main(_p: Spawner) {
17 let mut p = embassy_nrf::init(Default::default()); 17 let mut p = embassy_nrf::init(Default::default());
18 let config = Config::default(); 18 let config = Config::default();
19 let channel_config = ChannelConfig::single_ended(&mut p.P0_02); 19 let channel_config = ChannelConfig::single_ended(p.P0_02.reborrow());
20 let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]); 20 let mut saadc = Saadc::new(p.SAADC, Irqs, config, [channel_config]);
21 21
22 loop { 22 loop {
diff --git a/examples/nrf52840/src/bin/saadc_continuous.rs b/examples/nrf52840/src/bin/saadc_continuous.rs
index f76fa3570..e8f169c8c 100644
--- a/examples/nrf52840/src/bin/saadc_continuous.rs
+++ b/examples/nrf52840/src/bin/saadc_continuous.rs
@@ -18,9 +18,9 @@ bind_interrupts!(struct Irqs {
18async fn main(_p: Spawner) { 18async fn main(_p: Spawner) {
19 let mut p = embassy_nrf::init(Default::default()); 19 let mut p = embassy_nrf::init(Default::default());
20 let config = Config::default(); 20 let config = Config::default();
21 let channel_1_config = ChannelConfig::single_ended(&mut p.P0_02); 21 let channel_1_config = ChannelConfig::single_ended(p.P0_02.reborrow());
22 let channel_2_config = ChannelConfig::single_ended(&mut p.P0_03); 22 let channel_2_config = ChannelConfig::single_ended(p.P0_03.reborrow());
23 let channel_3_config = ChannelConfig::single_ended(&mut p.P0_04); 23 let channel_3_config = ChannelConfig::single_ended(p.P0_04.reborrow());
24 let mut saadc = Saadc::new( 24 let mut saadc = Saadc::new(
25 p.SAADC, 25 p.SAADC,
26 Irqs, 26 Irqs,
@@ -40,9 +40,9 @@ async fn main(_p: Spawner) {
40 40
41 saadc 41 saadc
42 .run_task_sampler( 42 .run_task_sampler(
43 &mut p.TIMER0, 43 p.TIMER0.reborrow(),
44 &mut p.PPI_CH0, 44 p.PPI_CH0.reborrow(),
45 &mut p.PPI_CH1, 45 p.PPI_CH1.reborrow(),
46 Frequency::F1MHz, 46 Frequency::F1MHz,
47 1000, // We want to sample at 1KHz 47 1000, // We want to sample at 1KHz
48 &mut bufs, 48 &mut bufs,
diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
index 5bfefc2af..acb44f98b 100644
--- a/examples/nrf52840/src/bin/self_spawn.rs
+++ b/examples/nrf52840/src/bin/self_spawn.rs
@@ -14,12 +14,12 @@ mod config {
14async fn my_task(spawner: Spawner, n: u32) { 14async fn my_task(spawner: Spawner, n: u32) {
15 Timer::after_secs(1).await; 15 Timer::after_secs(1).await;
16 info!("Spawning self! {}", n); 16 info!("Spawning self! {}", n);
17 unwrap!(spawner.spawn(my_task(spawner, n + 1))); 17 spawner.spawn(unwrap!(my_task(spawner, n + 1)));
18} 18}
19 19
20#[embassy_executor::main] 20#[embassy_executor::main]
21async fn main(spawner: Spawner) { 21async fn main(spawner: Spawner) {
22 let _p = embassy_nrf::init(Default::default()); 22 let _p = embassy_nrf::init(Default::default());
23 info!("Hello World!"); 23 info!("Hello World!");
24 unwrap!(spawner.spawn(my_task(spawner, 0))); 24 spawner.spawn(unwrap!(my_task(spawner, 0)));
25} 25}
diff --git a/examples/nrf52840/src/bin/self_spawn_current_executor.rs b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
index ec9569a64..d93067592 100644
--- a/examples/nrf52840/src/bin/self_spawn_current_executor.rs
+++ b/examples/nrf52840/src/bin/self_spawn_current_executor.rs
@@ -10,12 +10,13 @@ use {defmt_rtt as _, panic_probe as _};
10async fn my_task(n: u32) { 10async fn my_task(n: u32) {
11 Timer::after_secs(1).await; 11 Timer::after_secs(1).await;
12 info!("Spawning self! {}", n); 12 info!("Spawning self! {}", n);
13 unwrap!(Spawner::for_current_executor().await.spawn(my_task(n + 1))); 13 let spawner = unsafe { Spawner::for_current_executor().await };
14 spawner.spawn(unwrap!(my_task(n + 1)));
14} 15}
15 16
16#[embassy_executor::main] 17#[embassy_executor::main]
17async fn main(spawner: Spawner) { 18async fn main(spawner: Spawner) {
18 let _p = embassy_nrf::init(Default::default()); 19 let _p = embassy_nrf::init(Default::default());
19 info!("Hello World!"); 20 info!("Hello World!");
20 unwrap!(spawner.spawn(my_task(0))); 21 spawner.spawn(unwrap!(my_task(0)));
21} 22}
diff --git a/examples/nrf52840/src/bin/sixlowpan.rs b/examples/nrf52840/src/bin/sixlowpan.rs
new file mode 100644
index 000000000..12e385e01
--- /dev/null
+++ b/examples/nrf52840/src/bin/sixlowpan.rs
@@ -0,0 +1,120 @@
1#![no_std]
2#![no_main]
3
4use core::net::Ipv6Addr;
5
6use defmt::{info, unwrap, warn};
7use embassy_executor::Spawner;
8use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
9use embassy_net::{IpAddress, IpEndpoint, IpListenEndpoint, Ipv6Cidr, StackResources, StaticConfigV6};
10use embassy_nrf::config::{Config, HfclkSource};
11use embassy_nrf::rng::Rng;
12use embassy_nrf::{bind_interrupts, embassy_net_802154_driver as net, peripherals, radio};
13use embassy_time::Delay;
14use embedded_hal_async::delay::DelayNs;
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 RADIO => radio::InterruptHandler<peripherals::RADIO>;
20 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
21});
22
23#[embassy_executor::task]
24async fn ieee802154_task(runner: net::Runner<'static>) -> ! {
25 runner.run().await
26}
27
28#[embassy_executor::task]
29async fn net_task(mut runner: embassy_net::Runner<'static, net::Device<'static>>) -> ! {
30 runner.run().await
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 let mut config = Config::default();
36 // Necessary to run the radio nrf52840 v1.11 5.4.1
37 config.hfclk_source = HfclkSource::ExternalXtal;
38 let p = embassy_nrf::init(config);
39
40 let mac_addr: [u8; 8] = [2, 3, 4, 5, 6, 7, 8, 9];
41 static NRF802154_STATE: StaticCell<net::State<20, 20>> = StaticCell::new();
42 let (device, runner) = net::new(mac_addr, p.RADIO, Irqs, NRF802154_STATE.init(net::State::new()))
43 .await
44 .unwrap();
45
46 spawner.spawn(unwrap!(ieee802154_task(runner)));
47
48 // Swap these when flashing a second board
49 let peer = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a4);
50 let local = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a5);
51
52 let config = embassy_net::Config::ipv6_static(StaticConfigV6 {
53 address: Ipv6Cidr::new(local, 64),
54 gateway: None,
55 dns_servers: Default::default(),
56 });
57
58 // Generate random seed
59 let mut rng = Rng::new(p.RNG, Irqs);
60 let mut seed = [0; 8];
61 rng.blocking_fill_bytes(&mut seed);
62 let seed = u64::from_le_bytes(seed);
63
64 // Init network stack
65 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
66 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
67
68 spawner.spawn(unwrap!(net_task(runner)));
69
70 let mut rx_buffer = [0; 2096];
71 let mut tx_buffer = [0; 2096];
72 let mut tx_m_buffer = [PacketMetadata::EMPTY; 5];
73 let mut rx_m_buffer = [PacketMetadata::EMPTY; 5];
74
75 let mut delay = Delay;
76 loop {
77 let mut socket = UdpSocket::new(
78 stack,
79 &mut tx_m_buffer,
80 &mut rx_buffer,
81 &mut rx_m_buffer,
82 &mut tx_buffer,
83 );
84 socket
85 .bind(IpListenEndpoint {
86 addr: Some(IpAddress::Ipv6(local)),
87 port: 1234,
88 })
89 .unwrap();
90 let rep = UdpMetadata {
91 endpoint: IpEndpoint {
92 addr: IpAddress::Ipv6(peer),
93 port: 1234,
94 },
95 local_address: Some(IpAddress::Ipv6(local)),
96 meta: Default::default(),
97 };
98
99 info!("Listening on {:?} UDP:1234...", local);
100
101 let mut recv_buf = [0; 12];
102 loop {
103 delay.delay_ms(2000).await;
104 if socket.may_recv() {
105 let n = match socket.recv_from(&mut recv_buf).await {
106 Ok((0, _)) => panic!(),
107 Ok((n, _)) => n,
108 Err(e) => {
109 warn!("read error: {:?}", e);
110 break;
111 }
112 };
113 info!("Received {:02x}", &recv_buf[..n]);
114 }
115
116 info!("Sending");
117 socket.send_to(b"Hello World", rep).await.unwrap();
118 }
119 }
120}
diff --git a/examples/nrf52840/src/bin/spis.rs b/examples/nrf52840/src/bin/spis.rs
index 613cd37ab..4f28da07e 100644
--- a/examples/nrf52840/src/bin/spis.rs
+++ b/examples/nrf52840/src/bin/spis.rs
@@ -8,7 +8,7 @@ use embassy_nrf::{bind_interrupts, peripherals, spis};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10bind_interrupts!(struct Irqs { 10bind_interrupts!(struct Irqs {
11 SPIM2_SPIS2_SPI2 => spis::InterruptHandler<peripherals::SPI2>; 11 SPI2 => spis::InterruptHandler<peripherals::SPI2>;
12}); 12});
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
diff --git a/examples/nrf52840/src/bin/timer.rs b/examples/nrf52840/src/bin/timer.rs
index 365695a20..5331ac246 100644
--- a/examples/nrf52840/src/bin/timer.rs
+++ b/examples/nrf52840/src/bin/timer.rs
@@ -25,6 +25,6 @@ async fn run2() {
25#[embassy_executor::main] 25#[embassy_executor::main]
26async fn main(spawner: Spawner) { 26async fn main(spawner: Spawner) {
27 let _p = embassy_nrf::init(Default::default()); 27 let _p = embassy_nrf::init(Default::default());
28 unwrap!(spawner.spawn(run1())); 28 spawner.spawn(unwrap!(run1()));
29 unwrap!(spawner.spawn(run2())); 29 spawner.spawn(unwrap!(run2()));
30} 30}
diff --git a/examples/nrf52840/src/bin/twim.rs b/examples/nrf52840/src/bin/twim.rs
index a9a0765e8..e30a3855d 100644
--- a/examples/nrf52840/src/bin/twim.rs
+++ b/examples/nrf52840/src/bin/twim.rs
@@ -9,12 +9,13 @@ use defmt::*;
9use embassy_executor::Spawner; 9use embassy_executor::Spawner;
10use embassy_nrf::twim::{self, Twim}; 10use embassy_nrf::twim::{self, Twim};
11use embassy_nrf::{bind_interrupts, peripherals}; 11use embassy_nrf::{bind_interrupts, peripherals};
12use static_cell::ConstStaticCell;
12use {defmt_rtt as _, panic_probe as _}; 13use {defmt_rtt as _, panic_probe as _};
13 14
14const ADDRESS: u8 = 0x50; 15const ADDRESS: u8 = 0x50;
15 16
16bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
17 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; 18 TWISPI0 => twim::InterruptHandler<peripherals::TWISPI0>;
18}); 19});
19 20
20#[embassy_executor::main] 21#[embassy_executor::main]
@@ -22,7 +23,8 @@ async fn main(_spawner: Spawner) {
22 let p = embassy_nrf::init(Default::default()); 23 let p = embassy_nrf::init(Default::default());
23 info!("Initializing TWI..."); 24 info!("Initializing TWI...");
24 let config = twim::Config::default(); 25 let config = twim::Config::default();
25 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config); 26 static RAM_BUFFER: ConstStaticCell<[u8; 16]> = ConstStaticCell::new([0; 16]);
27 let mut twi = Twim::new(p.TWISPI0, Irqs, p.P0_03, p.P0_04, config, RAM_BUFFER.take());
26 28
27 info!("Reading..."); 29 info!("Reading...");
28 30
diff --git a/examples/nrf52840/src/bin/twim_lowpower.rs b/examples/nrf52840/src/bin/twim_lowpower.rs
index c743614b8..f7380e20d 100644
--- a/examples/nrf52840/src/bin/twim_lowpower.rs
+++ b/examples/nrf52840/src/bin/twim_lowpower.rs
@@ -19,7 +19,7 @@ use {defmt_rtt as _, panic_probe as _};
19const ADDRESS: u8 = 0x50; 19const ADDRESS: u8 = 0x50;
20 20
21bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
22 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twim::InterruptHandler<peripherals::TWISPI0>; 22 TWISPI0 => twim::InterruptHandler<peripherals::TWISPI0>;
23}); 23});
24 24
25#[embassy_executor::main] 25#[embassy_executor::main]
@@ -30,9 +30,17 @@ async fn main(_p: Spawner) {
30 loop { 30 loop {
31 info!("Initializing TWI..."); 31 info!("Initializing TWI...");
32 let config = twim::Config::default(); 32 let config = twim::Config::default();
33 let mut ram_buffer = [0u8; 16];
33 34
34 // Create the TWIM instance with borrowed singletons, so they're not consumed. 35 // Create the TWIM instance with borrowed singletons, so they're not consumed.
35 let mut twi = Twim::new(&mut p.TWISPI0, Irqs, &mut p.P0_03, &mut p.P0_04, config); 36 let mut twi = Twim::new(
37 p.TWISPI0.reborrow(),
38 Irqs,
39 p.P0_03.reborrow(),
40 p.P0_04.reborrow(),
41 config,
42 &mut ram_buffer,
43 );
36 44
37 info!("Reading..."); 45 info!("Reading...");
38 46
diff --git a/examples/nrf52840/src/bin/twis.rs b/examples/nrf52840/src/bin/twis.rs
index 88bd4cceb..856b34140 100644
--- a/examples/nrf52840/src/bin/twis.rs
+++ b/examples/nrf52840/src/bin/twis.rs
@@ -10,7 +10,7 @@ use embassy_nrf::{bind_interrupts, peripherals};
10use {defmt_rtt as _, panic_probe as _}; 10use {defmt_rtt as _, panic_probe as _};
11 11
12bind_interrupts!(struct Irqs { 12bind_interrupts!(struct Irqs {
13 SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 => twis::InterruptHandler<peripherals::TWISPI0>; 13 TWISPI0 => twis::InterruptHandler<peripherals::TWISPI0>;
14}); 14});
15 15
16#[embassy_executor::main] 16#[embassy_executor::main]
diff --git a/examples/nrf52840/src/bin/uart.rs b/examples/nrf52840/src/bin/uart.rs
index accaccea1..f9f8d74ab 100644
--- a/examples/nrf52840/src/bin/uart.rs
+++ b/examples/nrf52840/src/bin/uart.rs
@@ -7,7 +7,7 @@ use embassy_nrf::{bind_interrupts, peripherals, uarte};
7use {defmt_rtt as _, panic_probe as _}; 7use {defmt_rtt as _, panic_probe as _};
8 8
9bind_interrupts!(struct Irqs { 9bind_interrupts!(struct Irqs {
10 UARTE0_UART0 => uarte::InterruptHandler<peripherals::UARTE0>; 10 UARTE0 => uarte::InterruptHandler<peripherals::UARTE0>;
11}); 11});
12 12
13#[embassy_executor::main] 13#[embassy_executor::main]
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 config.parity = uarte::Parity::EXCLUDED; 17 config.parity = uarte::Parity::EXCLUDED;
18 config.baudrate = uarte::Baudrate::BAUD115200; 18 config.baudrate = uarte::Baudrate::BAUD115200;
19 19
20 let mut uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); 20 let mut uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config);
21 21
22 info!("uarte initialized!"); 22 info!("uarte initialized!");
23 23
diff --git a/examples/nrf52840/src/bin/uart_idle.rs b/examples/nrf52840/src/bin/uart_idle.rs
index fa93bcf21..00e3ae904 100644
--- a/examples/nrf52840/src/bin/uart_idle.rs
+++ b/examples/nrf52840/src/bin/uart_idle.rs
@@ -8,7 +8,7 @@ use embassy_nrf::{bind_interrupts, uarte};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10bind_interrupts!(struct Irqs { 10bind_interrupts!(struct Irqs {
11 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; 11 UARTE0 => uarte::InterruptHandler<UARTE0>;
12}); 12});
13 13
14#[embassy_executor::main] 14#[embassy_executor::main]
@@ -18,7 +18,7 @@ async fn main(_spawner: Spawner) {
18 config.parity = uarte::Parity::EXCLUDED; 18 config.parity = uarte::Parity::EXCLUDED;
19 config.baudrate = uarte::Baudrate::BAUD115200; 19 config.baudrate = uarte::Baudrate::BAUD115200;
20 20
21 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); 21 let uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config);
22 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1); 22 let (mut tx, mut rx) = uart.split_with_idle(p.TIMER0, p.PPI_CH0, p.PPI_CH1);
23 23
24 info!("uarte initialized!"); 24 info!("uarte initialized!");
diff --git a/examples/nrf52840/src/bin/uart_split.rs b/examples/nrf52840/src/bin/uart_split.rs
index c7510a9a8..d75143126 100644
--- a/examples/nrf52840/src/bin/uart_split.rs
+++ b/examples/nrf52840/src/bin/uart_split.rs
@@ -13,7 +13,7 @@ use {defmt_rtt as _, panic_probe as _};
13static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); 13static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new();
14 14
15bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
16 UARTE0_UART0 => uarte::InterruptHandler<UARTE0>; 16 UARTE0 => uarte::InterruptHandler<UARTE0>;
17}); 17});
18 18
19#[embassy_executor::main] 19#[embassy_executor::main]
@@ -23,14 +23,14 @@ async fn main(spawner: Spawner) {
23 config.parity = uarte::Parity::EXCLUDED; 23 config.parity = uarte::Parity::EXCLUDED;
24 config.baudrate = uarte::Baudrate::BAUD115200; 24 config.baudrate = uarte::Baudrate::BAUD115200;
25 25
26 let uart = uarte::Uarte::new(p.UARTE0, Irqs, p.P0_08, p.P0_06, config); 26 let uart = uarte::Uarte::new(p.UARTE0, p.P0_08, p.P0_06, Irqs, config);
27 let (mut tx, rx) = uart.split(); 27 let (mut tx, rx) = uart.split();
28 28
29 info!("uarte initialized!"); 29 info!("uarte initialized!");
30 30
31 // Spawn a task responsible purely for reading 31 // Spawn a task responsible purely for reading
32 32
33 unwrap!(spawner.spawn(reader(rx))); 33 spawner.spawn(unwrap!(reader(rx)));
34 34
35 // Message must be in SRAM 35 // Message must be in SRAM
36 { 36 {
@@ -52,7 +52,7 @@ async fn main(spawner: Spawner) {
52} 52}
53 53
54#[embassy_executor::task] 54#[embassy_executor::task]
55async fn reader(mut rx: UarteRx<'static, UARTE0>) { 55async fn reader(mut rx: UarteRx<'static>) {
56 let mut buf = [0; 8]; 56 let mut buf = [0; 8];
57 loop { 57 loop {
58 info!("reading..."); 58 info!("reading...");
diff --git a/examples/nrf52840/src/bin/usb_ethernet.rs b/examples/nrf52840/src/bin/usb_ethernet.rs
index a7e5c2668..14a1004d7 100644
--- a/examples/nrf52840/src/bin/usb_ethernet.rs
+++ b/examples/nrf52840/src/bin/usb_ethernet.rs
@@ -1,15 +1,13 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::*; 4use defmt::*;
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::StackResources;
8use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
9use embassy_net::{Stack, StackResources};
10use embassy_nrf::rng::Rng; 8use embassy_nrf::rng::Rng;
11use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
12use embassy_nrf::usb::Driver; 9use embassy_nrf::usb::Driver;
10use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; 11use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb};
14use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; 12use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
15use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; 13use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
@@ -20,11 +18,11 @@ use {defmt_rtt as _, panic_probe as _};
20 18
21bind_interrupts!(struct Irqs { 19bind_interrupts!(struct Irqs {
22 USBD => usb::InterruptHandler<peripherals::USBD>; 20 USBD => usb::InterruptHandler<peripherals::USBD>;
23 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 21 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
24 RNG => rng::InterruptHandler<peripherals::RNG>; 22 RNG => rng::InterruptHandler<peripherals::RNG>;
25}); 23});
26 24
27type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 25type MyDriver = Driver<'static, HardwareVbusDetect>;
28 26
29const MTU: usize = 1514; 27const MTU: usize = 1514;
30 28
@@ -39,18 +37,17 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
39} 37}
40 38
41#[embassy_executor::task] 39#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { 40async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! {
43 stack.run().await 41 runner.run().await
44} 42}
45 43
46#[embassy_executor::main] 44#[embassy_executor::main]
47async fn main(spawner: Spawner) { 45async fn main(spawner: Spawner) {
48 let p = embassy_nrf::init(Default::default()); 46 let p = embassy_nrf::init(Default::default());
49 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
50 47
51 info!("Enabling ext hfosc..."); 48 info!("Enabling ext hfosc...");
52 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 49 pac::CLOCK.tasks_hfclkstart().write_value(1);
53 while clock.events_hfclkstarted.read().bits() != 1 {} 50 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
54 51
55 // Create the driver, from the HAL. 52 // Create the driver, from the HAL.
56 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 53 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -63,12 +60,6 @@ async fn main(spawner: Spawner) {
63 config.max_power = 100; 60 config.max_power = 100;
64 config.max_packet_size_0 = 64; 61 config.max_packet_size_0 = 64;
65 62
66 // Required for Windows support.
67 config.composite_with_iads = true;
68 config.device_class = 0xEF;
69 config.device_sub_class = 0x02;
70 config.device_protocol = 0x01;
71
72 // Create embassy-usb DeviceBuilder using the driver and config. 63 // Create embassy-usb DeviceBuilder using the driver and config.
73 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 64 static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new();
74 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); 65 static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new();
@@ -95,11 +86,11 @@ async fn main(spawner: Spawner) {
95 // Build the builder. 86 // Build the builder.
96 let usb = builder.build(); 87 let usb = builder.build();
97 88
98 unwrap!(spawner.spawn(usb_task(usb))); 89 spawner.spawn(unwrap!(usb_task(usb)));
99 90
100 static NET_STATE: StaticCell<NetState<MTU, 4, 4>> = StaticCell::new(); 91 static NET_STATE: StaticCell<NetState<MTU, 4, 4>> = StaticCell::new();
101 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(NET_STATE.init(NetState::new()), our_mac_addr); 92 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(NET_STATE.init(NetState::new()), our_mac_addr);
102 unwrap!(spawner.spawn(usb_ncm_task(runner))); 93 spawner.spawn(unwrap!(usb_ncm_task(runner)));
103 94
104 let config = embassy_net::Config::dhcpv4(Default::default()); 95 let config = embassy_net::Config::dhcpv4(Default::default());
105 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { 96 // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
@@ -115,11 +106,10 @@ async fn main(spawner: Spawner) {
115 let seed = u64::from_le_bytes(seed); 106 let seed = u64::from_le_bytes(seed);
116 107
117 // Init network stack 108 // Init network stack
118 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 109 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
119 static STACK: StaticCell<Stack<Device<'static, MTU>>> = StaticCell::new(); 110 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
120 let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed));
121 111
122 unwrap!(spawner.spawn(net_task(stack))); 112 spawner.spawn(unwrap!(net_task(runner)));
123 113
124 // And now we can use it! 114 // And now we can use it!
125 115
diff --git a/examples/nrf52840/src/bin/usb_hid_keyboard.rs b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
index e33ee5866..7b7303526 100644
--- a/examples/nrf52840/src/bin/usb_hid_keyboard.rs
+++ b/examples/nrf52840/src/bin/usb_hid_keyboard.rs
@@ -1,20 +1,21 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem; 4use core::sync::atomic::{AtomicBool, AtomicU8, Ordering};
5use core::sync::atomic::{AtomicBool, Ordering};
6 5
7use defmt::*; 6use defmt::*;
8use embassy_executor::Spawner; 7use embassy_executor::Spawner;
9use embassy_futures::join::join; 8use embassy_futures::join::join;
10use embassy_futures::select::{select, Either}; 9use embassy_futures::select::{Either, select};
11use embassy_nrf::gpio::{Input, Pull}; 10use embassy_nrf::gpio::{Input, Pull};
12use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
13use embassy_nrf::usb::Driver; 11use embassy_nrf::usb::Driver;
12use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
14use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 13use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
15use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; 14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
16use embassy_sync::signal::Signal; 15use embassy_sync::signal::Signal;
17use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; 16use embassy_usb::class::hid::{
17 HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State,
18};
18use embassy_usb::control::OutResponse; 19use embassy_usb::control::OutResponse;
19use embassy_usb::{Builder, Config, Handler}; 20use embassy_usb::{Builder, Config, Handler};
20use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; 21use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
@@ -22,19 +23,20 @@ use {defmt_rtt as _, panic_probe as _};
22 23
23bind_interrupts!(struct Irqs { 24bind_interrupts!(struct Irqs {
24 USBD => usb::InterruptHandler<peripherals::USBD>; 25 USBD => usb::InterruptHandler<peripherals::USBD>;
25 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 26 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
26}); 27});
27 28
28static SUSPENDED: AtomicBool = AtomicBool::new(false); 29static SUSPENDED: AtomicBool = AtomicBool::new(false);
29 30
31static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
32
30#[embassy_executor::main] 33#[embassy_executor::main]
31async fn main(_spawner: Spawner) { 34async fn main(_spawner: Spawner) {
32 let p = embassy_nrf::init(Default::default()); 35 let p = embassy_nrf::init(Default::default());
33 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
34 36
35 info!("Enabling ext hfosc..."); 37 info!("Enabling ext hfosc...");
36 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 38 pac::CLOCK.tasks_hfclkstart().write_value(1);
37 while clock.events_hfclkstarted.read().bits() != 1 {} 39 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
38 40
39 // Create the driver, from the HAL. 41 // Create the driver, from the HAL.
40 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 42 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -47,6 +49,10 @@ async fn main(_spawner: Spawner) {
47 config.max_power = 100; 49 config.max_power = 100;
48 config.max_packet_size_0 = 64; 50 config.max_packet_size_0 = 64;
49 config.supports_remote_wakeup = true; 51 config.supports_remote_wakeup = true;
52 config.composite_with_iads = false;
53 config.device_class = 0;
54 config.device_sub_class = 0;
55 config.device_protocol = 0;
50 56
51 // Create embassy-usb DeviceBuilder using the driver and config. 57 // Create embassy-usb DeviceBuilder using the driver and config.
52 // It needs some buffers for building the descriptors. 58 // It needs some buffers for building the descriptors.
@@ -76,6 +82,8 @@ async fn main(_spawner: Spawner) {
76 request_handler: None, 82 request_handler: None,
77 poll_ms: 60, 83 poll_ms: 60,
78 max_packet_size: 64, 84 max_packet_size: 64,
85 hid_subclass: HidSubclass::Boot,
86 hid_boot_protocol: HidBootProtocol::Keyboard,
79 }; 87 };
80 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config); 88 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
81 89
@@ -108,6 +116,11 @@ async fn main(_spawner: Spawner) {
108 if SUSPENDED.load(Ordering::Acquire) { 116 if SUSPENDED.load(Ordering::Acquire) {
109 info!("Triggering remote wakeup"); 117 info!("Triggering remote wakeup");
110 remote_wakeup.signal(()); 118 remote_wakeup.signal(());
119 } else if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
120 match writer.write(&[0, 0, 4, 0, 0, 0, 0, 0]).await {
121 Ok(()) => {}
122 Err(e) => warn!("Failed to send boot report: {:?}", e),
123 };
111 } else { 124 } else {
112 let report = KeyboardReport { 125 let report = KeyboardReport {
113 keycodes: [4, 0, 0, 0, 0, 0], 126 keycodes: [4, 0, 0, 0, 0, 0],
@@ -123,16 +136,23 @@ async fn main(_spawner: Spawner) {
123 136
124 button.wait_for_high().await; 137 button.wait_for_high().await;
125 info!("RELEASED"); 138 info!("RELEASED");
126 let report = KeyboardReport { 139 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
127 keycodes: [0, 0, 0, 0, 0, 0], 140 match writer.write(&[0, 0, 0, 0, 0, 0, 0, 0]).await {
128 leds: 0, 141 Ok(()) => {}
129 modifier: 0, 142 Err(e) => warn!("Failed to send boot report: {:?}", e),
130 reserved: 0, 143 };
131 }; 144 } else {
132 match writer.write_serialize(&report).await { 145 let report = KeyboardReport {
133 Ok(()) => {} 146 keycodes: [0, 0, 0, 0, 0, 0],
134 Err(e) => warn!("Failed to send report: {:?}", e), 147 leds: 0,
135 }; 148 modifier: 0,
149 reserved: 0,
150 };
151 match writer.write_serialize(&report).await {
152 Ok(()) => {}
153 Err(e) => warn!("Failed to send report: {:?}", e),
154 };
155 }
136 } 156 }
137 }; 157 };
138 158
@@ -158,6 +178,18 @@ impl RequestHandler for MyRequestHandler {
158 OutResponse::Accepted 178 OutResponse::Accepted
159 } 179 }
160 180
181 fn get_protocol(&self) -> HidProtocolMode {
182 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
183 info!("The current HID protocol mode is: {}", protocol);
184 protocol
185 }
186
187 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
188 info!("Switching to HID protocol mode: {}", protocol);
189 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
190 OutResponse::Accepted
191 }
192
161 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 193 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
162 info!("Set idle rate for {:?} to {:?}", id, dur); 194 info!("Set idle rate for {:?} to {:?}", id, dur);
163 } 195 }
@@ -212,7 +244,9 @@ impl Handler for MyDeviceHandler {
212 244
213 fn suspended(&mut self, suspended: bool) { 245 fn suspended(&mut self, suspended: bool) {
214 if suspended { 246 if suspended {
215 info!("Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."); 247 info!(
248 "Device suspended, the Vbus current limit is 500µA (or 2.5mA for high-power devices with remote wakeup enabled)."
249 );
216 SUSPENDED.store(true, Ordering::Release); 250 SUSPENDED.store(true, Ordering::Release);
217 } else { 251 } else {
218 SUSPENDED.store(false, Ordering::Release); 252 SUSPENDED.store(false, Ordering::Release);
diff --git a/examples/nrf52840/src/bin/usb_hid_mouse.rs b/examples/nrf52840/src/bin/usb_hid_mouse.rs
index 8076ac283..6bee4546b 100644
--- a/examples/nrf52840/src/bin/usb_hid_mouse.rs
+++ b/examples/nrf52840/src/bin/usb_hid_mouse.rs
@@ -1,16 +1,18 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem; 4use core::sync::atomic::{AtomicU8, Ordering};
5 5
6use defmt::*; 6use defmt::*;
7use embassy_executor::Spawner; 7use embassy_executor::Spawner;
8use embassy_futures::join::join; 8use embassy_futures::join::join;
9use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
10use embassy_nrf::usb::Driver; 9use embassy_nrf::usb::Driver;
10use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
11use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 11use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_time::Timer; 12use embassy_time::Timer;
13use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; 13use embassy_usb::class::hid::{
14 HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State,
15};
14use embassy_usb::control::OutResponse; 16use embassy_usb::control::OutResponse;
15use embassy_usb::{Builder, Config}; 17use embassy_usb::{Builder, Config};
16use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; 18use usbd_hid::descriptor::{MouseReport, SerializedDescriptor};
@@ -18,17 +20,18 @@ use {defmt_rtt as _, panic_probe as _};
18 20
19bind_interrupts!(struct Irqs { 21bind_interrupts!(struct Irqs {
20 USBD => usb::InterruptHandler<peripherals::USBD>; 22 USBD => usb::InterruptHandler<peripherals::USBD>;
21 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 23 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
22}); 24});
23 25
26static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8);
27
24#[embassy_executor::main] 28#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 29async fn main(_spawner: Spawner) {
26 let p = embassy_nrf::init(Default::default()); 30 let p = embassy_nrf::init(Default::default());
27 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
28 31
29 info!("Enabling ext hfosc..."); 32 info!("Enabling ext hfosc...");
30 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 33 pac::CLOCK.tasks_hfclkstart().write_value(1);
31 while clock.events_hfclkstarted.read().bits() != 1 {} 34 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
32 35
33 // Create the driver, from the HAL. 36 // Create the driver, from the HAL.
34 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 37 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -40,6 +43,10 @@ async fn main(_spawner: Spawner) {
40 config.serial_number = Some("12345678"); 43 config.serial_number = Some("12345678");
41 config.max_power = 100; 44 config.max_power = 100;
42 config.max_packet_size_0 = 64; 45 config.max_packet_size_0 = 64;
46 config.composite_with_iads = false;
47 config.device_class = 0;
48 config.device_sub_class = 0;
49 config.device_protocol = 0;
43 50
44 // Create embassy-usb DeviceBuilder using the driver and config. 51 // Create embassy-usb DeviceBuilder using the driver and config.
45 // It needs some buffers for building the descriptors. 52 // It needs some buffers for building the descriptors.
@@ -66,6 +73,8 @@ async fn main(_spawner: Spawner) {
66 request_handler: Some(&mut request_handler), 73 request_handler: Some(&mut request_handler),
67 poll_ms: 60, 74 poll_ms: 60,
68 max_packet_size: 8, 75 max_packet_size: 8,
76 hid_subclass: HidSubclass::Boot,
77 hid_boot_protocol: HidBootProtocol::Mouse,
69 }; 78 };
70 79
71 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config); 80 let mut writer = HidWriter::<_, 5>::new(&mut builder, &mut state, config);
@@ -83,16 +92,26 @@ async fn main(_spawner: Spawner) {
83 Timer::after_millis(500).await; 92 Timer::after_millis(500).await;
84 93
85 y = -y; 94 y = -y;
86 let report = MouseReport { 95
87 buttons: 0, 96 if HID_PROTOCOL_MODE.load(Ordering::Relaxed) == HidProtocolMode::Boot as u8 {
88 x: 0, 97 let buttons = 0u8;
89 y, 98 let x = 0i8;
90 wheel: 0, 99 match writer.write(&[buttons, x as u8, y as u8]).await {
91 pan: 0, 100 Ok(()) => {}
92 }; 101 Err(e) => warn!("Failed to send boot report: {:?}", e),
93 match writer.write_serialize(&report).await { 102 }
94 Ok(()) => {} 103 } else {
95 Err(e) => warn!("Failed to send report: {:?}", e), 104 let report = MouseReport {
105 buttons: 0,
106 x: 0,
107 y,
108 wheel: 0,
109 pan: 0,
110 };
111 match writer.write_serialize(&report).await {
112 Ok(()) => {}
113 Err(e) => warn!("Failed to send report: {:?}", e),
114 }
96 } 115 }
97 } 116 }
98 }; 117 };
@@ -115,6 +134,18 @@ impl RequestHandler for MyRequestHandler {
115 OutResponse::Accepted 134 OutResponse::Accepted
116 } 135 }
117 136
137 fn get_protocol(&self) -> HidProtocolMode {
138 let protocol = HidProtocolMode::from(HID_PROTOCOL_MODE.load(Ordering::Relaxed));
139 info!("The current HID protocol mode is: {}", protocol);
140 protocol
141 }
142
143 fn set_protocol(&mut self, protocol: HidProtocolMode) -> OutResponse {
144 info!("Switching to HID protocol mode: {}", protocol);
145 HID_PROTOCOL_MODE.store(protocol as u8, Ordering::Relaxed);
146 OutResponse::Accepted
147 }
148
118 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) { 149 fn set_idle_ms(&mut self, id: Option<ReportId>, dur: u32) {
119 info!("Set idle rate for {:?} to {:?}", id, dur); 150 info!("Set idle rate for {:?} to {:?}", id, dur);
120 } 151 }
diff --git a/examples/nrf52840/src/bin/usb_serial.rs b/examples/nrf52840/src/bin/usb_serial.rs
index 02048e692..469002bc7 100644
--- a/examples/nrf52840/src/bin/usb_serial.rs
+++ b/examples/nrf52840/src/bin/usb_serial.rs
@@ -1,13 +1,11 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::{info, panic}; 4use defmt::{info, panic};
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_nrf::usb::Driver;
9use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; 8use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
10use embassy_nrf::usb::{Driver, Instance};
11use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 9use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
@@ -16,17 +14,16 @@ use {defmt_rtt as _, panic_probe as _};
16 14
17bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
18 USBD => usb::InterruptHandler<peripherals::USBD>; 16 USBD => usb::InterruptHandler<peripherals::USBD>;
19 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 17 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
20}); 18});
21 19
22#[embassy_executor::main] 20#[embassy_executor::main]
23async fn main(_spawner: Spawner) { 21async fn main(_spawner: Spawner) {
24 let p = embassy_nrf::init(Default::default()); 22 let p = embassy_nrf::init(Default::default());
25 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
26 23
27 info!("Enabling ext hfosc..."); 24 info!("Enabling ext hfosc...");
28 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 25 pac::CLOCK.tasks_hfclkstart().write_value(1);
29 while clock.events_hfclkstarted.read().bits() != 1 {} 26 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
30 27
31 // Create the driver, from the HAL. 28 // Create the driver, from the HAL.
32 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 29 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -39,13 +36,6 @@ async fn main(_spawner: Spawner) {
39 config.max_power = 100; 36 config.max_power = 100;
40 config.max_packet_size_0 = 64; 37 config.max_packet_size_0 = 64;
41 38
42 // Required for windows compatibility.
43 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
44 config.device_class = 0xEF;
45 config.device_sub_class = 0x02;
46 config.device_protocol = 0x01;
47 config.composite_with_iads = true;
48
49 // Create embassy-usb DeviceBuilder using the driver and config. 39 // Create embassy-usb DeviceBuilder using the driver and config.
50 // It needs some buffers for building the descriptors. 40 // It needs some buffers for building the descriptors.
51 let mut config_descriptor = [0; 256]; 41 let mut config_descriptor = [0; 256];
@@ -99,9 +89,7 @@ impl From<EndpointError> for Disconnected {
99 } 89 }
100} 90}
101 91
102async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( 92async fn echo<'d, V: VbusDetect + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, V>>) -> Result<(), Disconnected> {
103 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
104) -> Result<(), Disconnected> {
105 let mut buf = [0; 64]; 93 let mut buf = [0; 64];
106 loop { 94 loop {
107 let n = class.read_packet(&mut buf).await?; 95 let n = class.read_packet(&mut buf).await?;
diff --git a/examples/nrf52840/src/bin/usb_serial_multitask.rs b/examples/nrf52840/src/bin/usb_serial_multitask.rs
index 895cca8b9..67b2bccbb 100644
--- a/examples/nrf52840/src/bin/usb_serial_multitask.rs
+++ b/examples/nrf52840/src/bin/usb_serial_multitask.rs
@@ -1,12 +1,10 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::{info, panic, unwrap}; 4use defmt::{info, panic, unwrap};
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
9use embassy_nrf::usb::Driver; 6use embassy_nrf::usb::Driver;
7use embassy_nrf::usb::vbus_detect::HardwareVbusDetect;
10use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 8use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
11use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 9use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
12use embassy_usb::driver::EndpointError; 10use embassy_usb::driver::EndpointError;
@@ -16,10 +14,10 @@ use {defmt_rtt as _, panic_probe as _};
16 14
17bind_interrupts!(struct Irqs { 15bind_interrupts!(struct Irqs {
18 USBD => usb::InterruptHandler<peripherals::USBD>; 16 USBD => usb::InterruptHandler<peripherals::USBD>;
19 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 17 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
20}); 18});
21 19
22type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; 20type MyDriver = Driver<'static, HardwareVbusDetect>;
23 21
24#[embassy_executor::task] 22#[embassy_executor::task]
25async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { 23async fn usb_task(mut device: UsbDevice<'static, MyDriver>) {
@@ -39,11 +37,10 @@ async fn echo_task(mut class: CdcAcmClass<'static, MyDriver>) {
39#[embassy_executor::main] 37#[embassy_executor::main]
40async fn main(spawner: Spawner) { 38async fn main(spawner: Spawner) {
41 let p = embassy_nrf::init(Default::default()); 39 let p = embassy_nrf::init(Default::default());
42 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
43 40
44 info!("Enabling ext hfosc..."); 41 info!("Enabling ext hfosc...");
45 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 42 pac::CLOCK.tasks_hfclkstart().write_value(1);
46 while clock.events_hfclkstarted.read().bits() != 1 {} 43 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
47 44
48 // Create the driver, from the HAL. 45 // Create the driver, from the HAL.
49 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 46 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -56,13 +53,6 @@ async fn main(spawner: Spawner) {
56 config.max_power = 100; 53 config.max_power = 100;
57 config.max_packet_size_0 = 64; 54 config.max_packet_size_0 = 64;
58 55
59 // Required for windows compatibility.
60 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
61 config.device_class = 0xEF;
62 config.device_sub_class = 0x02;
63 config.device_protocol = 0x01;
64 config.composite_with_iads = true;
65
66 static STATE: StaticCell<State> = StaticCell::new(); 56 static STATE: StaticCell<State> = StaticCell::new();
67 let state = STATE.init(State::new()); 57 let state = STATE.init(State::new());
68 58
@@ -86,8 +76,8 @@ async fn main(spawner: Spawner) {
86 // Build the builder. 76 // Build the builder.
87 let usb = builder.build(); 77 let usb = builder.build();
88 78
89 unwrap!(spawner.spawn(usb_task(usb))); 79 spawner.spawn(unwrap!(usb_task(usb)));
90 unwrap!(spawner.spawn(echo_task(class))); 80 spawner.spawn(unwrap!(echo_task(class)));
91} 81}
92 82
93struct Disconnected {} 83struct Disconnected {}
diff --git a/examples/nrf52840/src/bin/usb_serial_winusb.rs b/examples/nrf52840/src/bin/usb_serial_winusb.rs
index c6675a3d3..cd4d5bca1 100644
--- a/examples/nrf52840/src/bin/usb_serial_winusb.rs
+++ b/examples/nrf52840/src/bin/usb_serial_winusb.rs
@@ -1,13 +1,11 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3 3
4use core::mem;
5
6use defmt::{info, panic}; 4use defmt::{info, panic};
7use embassy_executor::Spawner; 5use embassy_executor::Spawner;
8use embassy_futures::join::join; 6use embassy_futures::join::join;
7use embassy_nrf::usb::Driver;
9use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; 8use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect};
10use embassy_nrf::usb::{Driver, Instance};
11use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; 9use embassy_nrf::{bind_interrupts, pac, peripherals, usb};
12use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; 10use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
13use embassy_usb::driver::EndpointError; 11use embassy_usb::driver::EndpointError;
@@ -18,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _};
18 16
19bind_interrupts!(struct Irqs { 17bind_interrupts!(struct Irqs {
20 USBD => usb::InterruptHandler<peripherals::USBD>; 18 USBD => usb::InterruptHandler<peripherals::USBD>;
21 POWER_CLOCK => usb::vbus_detect::InterruptHandler; 19 CLOCK_POWER => usb::vbus_detect::InterruptHandler;
22}); 20});
23 21
24// This is a randomly generated GUID to allow clients on Windows to find our device 22// This is a randomly generated GUID to allow clients on Windows to find our device
@@ -27,11 +25,10 @@ const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321
27#[embassy_executor::main] 25#[embassy_executor::main]
28async fn main(_spawner: Spawner) { 26async fn main(_spawner: Spawner) {
29 let p = embassy_nrf::init(Default::default()); 27 let p = embassy_nrf::init(Default::default());
30 let clock: pac::CLOCK = unsafe { mem::transmute(()) };
31 28
32 info!("Enabling ext hfosc..."); 29 info!("Enabling ext hfosc...");
33 clock.tasks_hfclkstart.write(|w| unsafe { w.bits(1) }); 30 pac::CLOCK.tasks_hfclkstart().write_value(1);
34 while clock.events_hfclkstarted.read().bits() != 1 {} 31 while pac::CLOCK.events_hfclkstarted().read() != 1 {}
35 32
36 // Create the driver, from the HAL. 33 // Create the driver, from the HAL.
37 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs)); 34 let driver = Driver::new(p.USBD, Irqs, HardwareVbusDetect::new(Irqs));
@@ -44,13 +41,6 @@ async fn main(_spawner: Spawner) {
44 config.max_power = 100; 41 config.max_power = 100;
45 config.max_packet_size_0 = 64; 42 config.max_packet_size_0 = 64;
46 43
47 // Required for windows compatibility.
48 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
49 config.device_class = 0xEF;
50 config.device_sub_class = 0x02;
51 config.device_protocol = 0x01;
52 config.composite_with_iads = true;
53
54 // Create embassy-usb DeviceBuilder using the driver and config. 44 // Create embassy-usb DeviceBuilder using the driver and config.
55 // It needs some buffers for building the descriptors. 45 // It needs some buffers for building the descriptors.
56 let mut config_descriptor = [0; 256]; 46 let mut config_descriptor = [0; 256];
@@ -118,9 +108,7 @@ impl From<EndpointError> for Disconnected {
118 } 108 }
119} 109}
120 110
121async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( 111async fn echo<'d, V: VbusDetect + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, V>>) -> Result<(), Disconnected> {
122 class: &mut CdcAcmClass<'d, Driver<'d, T, P>>,
123) -> Result<(), Disconnected> {
124 let mut buf = [0; 64]; 112 let mut buf = [0; 64];
125 loop { 113 loop {
126 let n = class.read_packet(&mut buf).await?; 114 let n = class.read_packet(&mut buf).await?;
diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs
index ede88cc26..0d9ee3cf8 100644
--- a/examples/nrf52840/src/bin/wdt.rs
+++ b/examples/nrf52840/src/bin/wdt.rs
@@ -4,7 +4,7 @@
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_nrf::gpio::{Input, Pull}; 6use embassy_nrf::gpio::{Input, Pull};
7use embassy_nrf::wdt::{Config, Watchdog}; 7use embassy_nrf::wdt::{Config, HaltConfig, Watchdog};
8use {defmt_rtt as _, panic_probe as _}; 8use {defmt_rtt as _, panic_probe as _};
9 9
10#[embassy_executor::main] 10#[embassy_executor::main]
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 17
18 // This is needed for `probe-rs run` to be able to catch the panic message 18 // This is needed for `probe-rs run` to be able to catch the panic message
19 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. 19 // in the WDT interrupt. The core resets 2 ticks after firing the interrupt.
20 config.run_during_debug_halt = false; 20 config.action_during_debug_halt = HaltConfig::PAUSE;
21 21
22 let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) { 22 let (_wdt, [mut handle]) = match Watchdog::try_new(p.WDT, config) {
23 Ok(x) => x, 23 Ok(x) => x,
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index 00bd50081..2f9c06b56 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -3,8 +3,8 @@
3 3
4use defmt::{info, unwrap, warn}; 4use defmt::{info, unwrap, warn};
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_net::StackResources;
6use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
7use embassy_net::{Stack, StackResources};
8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; 8use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
9use embassy_nrf::rng::Rng; 9use embassy_nrf::rng::Rng;
10use embassy_nrf::spim::{self, Spim}; 10use embassy_nrf::spim::{self, Spim};
@@ -27,17 +27,15 @@ bind_interrupts!(struct Irqs {
27async fn wifi_task( 27async fn wifi_task(
28 runner: hosted::Runner< 28 runner: hosted::Runner<
29 'static, 29 'static,
30 ExclusiveDevice<Spim<'static, peripherals::SPI3>, Output<'static>, Delay>, 30 hosted::SpiInterface<ExclusiveDevice<Spim<'static>, Output<'static>, Delay>, Input<'static>>,
31 Input<'static>,
32 Output<'static>, 31 Output<'static>,
33 >, 32 >,
34) -> ! { 33) -> ! {
35 runner.run().await 34 runner.run().await
36} 35}
37
38#[embassy_executor::task] 36#[embassy_executor::task]
39async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! { 37async fn net_task(mut runner: embassy_net::Runner<'static, hosted::NetDriver<'static>>) -> ! {
40 stack.run().await 38 runner.run().await
41} 39}
42 40
43#[embassy_executor::main] 41#[embassy_executor::main]
@@ -60,17 +58,13 @@ async fn main(spawner: Spawner) {
60 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); 58 let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
61 let spi = ExclusiveDevice::new(spi, cs, Delay); 59 let spi = ExclusiveDevice::new(spi, cs, Delay);
62 60
61 let iface = hosted::SpiInterface::new(spi, handshake, ready);
62
63 static ESP_STATE: StaticCell<embassy_net_esp_hosted::State> = StaticCell::new(); 63 static ESP_STATE: StaticCell<embassy_net_esp_hosted::State> = StaticCell::new();
64 let (device, mut control, runner) = embassy_net_esp_hosted::new( 64 let (device, mut control, runner) =
65 ESP_STATE.init(embassy_net_esp_hosted::State::new()), 65 embassy_net_esp_hosted::new(ESP_STATE.init(embassy_net_esp_hosted::State::new()), iface, reset).await;
66 spi,
67 handshake,
68 ready,
69 reset,
70 )
71 .await;
72 66
73 unwrap!(spawner.spawn(wifi_task(runner))); 67 spawner.spawn(unwrap!(wifi_task(runner)));
74 68
75 unwrap!(control.init().await); 69 unwrap!(control.init().await);
76 unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await); 70 unwrap!(control.connect(WIFI_NETWORK, WIFI_PASSWORD).await);
@@ -89,16 +83,10 @@ async fn main(spawner: Spawner) {
89 let seed = u64::from_le_bytes(seed); 83 let seed = u64::from_le_bytes(seed);
90 84
91 // Init network stack 85 // Init network stack
92 static RESOURCES: StaticCell<StackResources<2>> = StaticCell::new(); 86 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
93 static STACK: StaticCell<Stack<hosted::NetDriver<'static>>> = StaticCell::new(); 87 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
94 let stack = &*STACK.init(Stack::new( 88
95 device, 89 spawner.spawn(unwrap!(net_task(runner)));
96 config,
97 RESOURCES.init(StackResources::<2>::new()),
98 seed,
99 ));
100
101 unwrap!(spawner.spawn(net_task(stack)));
102 90
103 // And now we can use it! 91 // And now we can use it!
104 92