diff options
| author | Dion Dokter <[email protected]> | 2025-11-20 13:22:38 +0100 |
|---|---|---|
| committer | Dion Dokter <[email protected]> | 2025-11-20 13:22:38 +0100 |
| commit | 4f2c36e447455e8d33607d586859d3d075cabf1d (patch) | |
| tree | 003cd822d688acd7c074dd229663b4648d100f71 /examples/nrf52840/src | |
| parent | 663732d85abbae400f2dbab2c411802a5b60e9b1 (diff) | |
| parent | 661874d11de7d93ed52e08e020a9d4c7ee11122d (diff) | |
Merge branch 'main' into u0-lcd
Diffstat (limited to 'examples/nrf52840/src')
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; | |||
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {defmt_rtt as _, panic_probe as _}; |
| 10 | 10 | ||
| 11 | bind_interrupts!(struct Irqs { | 11 | bind_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 | ||
| 4 | use defmt::unwrap; | 4 | use defmt::unwrap; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive, Pin}; | 6 | use embassy_nrf::Peri; |
| 7 | use embassy_nrf::gpio::{AnyPin, Level, Output, OutputDrive}; | ||
| 7 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | 8 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; |
| 8 | use embassy_sync::channel::{Channel, Receiver, Sender}; | 9 | use embassy_sync::channel::{Channel, Receiver, Sender}; |
| 9 | use embassy_time::Timer; | 10 | use 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] |
| 31 | async fn recv_task(led: AnyPin, receiver: Receiver<'static, NoopRawMutex, LedState, 1>) { | 32 | async 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 | |||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_nrf::egu::{Egu, TriggerNumber}; | ||
| 9 | use embassy_nrf::gpio::{Level, OutputDrive, Pull}; | ||
| 10 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity, OutputChannel, OutputChannelPolarity}; | ||
| 11 | use embassy_nrf::peripherals::{PPI_CH0, PPI_CH1, PPI_CH2}; | ||
| 12 | use embassy_nrf::ppi::Ppi; | ||
| 13 | use embassy_time::{Duration, Timer}; | ||
| 14 | use {defmt_rtt as _, panic_probe as _}; | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::StackResources; | ||
| 6 | use embassy_net::tcp::TcpSocket; | 7 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | ||
| 8 | use embassy_net_enc28j60::Enc28j60; | 8 | use embassy_net_enc28j60::Enc28j60; |
| 9 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | 9 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; |
| 10 | use embassy_nrf::rng::Rng; | 10 | use embassy_nrf::rng::Rng; |
| @@ -23,11 +23,12 @@ bind_interrupts!(struct Irqs { | |||
| 23 | 23 | ||
| 24 | #[embassy_executor::task] | 24 | #[embassy_executor::task] |
| 25 | async fn net_task( | 25 | async 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] |
| 37 | async fn main(spawner: Spawner) { | 37 | async 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 | ||
| 4 | use defmt::info; | 4 | use defmt::info; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::gpio::{Input, Pull}; | 6 | use embassy_nrf::gpio::Pull; |
| 7 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; | 7 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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 | ||
| 6 | use defmt::{error, info}; | 6 | use defmt::{error, info}; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_nrf::i2s::{self, Channels, Config, MasterClock, MultiBuffering, Sample as _, SampleWidth, I2S}; | 8 | use embassy_nrf::i2s::{self, Channels, Config, I2S, MasterClock, MultiBuffering, Sample as _, SampleWidth}; |
| 9 | use embassy_nrf::{bind_interrupts, peripherals}; | 9 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| @@ -102,11 +102,7 @@ impl SineOsc { | |||
| 102 | 102 | ||
| 103 | #[inline] | 103 | #[inline] |
| 104 | fn abs(value: f32) -> f32 { | 104 | fn 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 | ||
| 4 | use defmt::{debug, error, info}; | 4 | use defmt::{debug, error, info}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | 6 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; |
| 7 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 7 | use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; |
| 8 | use embassy_nrf::{bind_interrupts, peripherals}; | 8 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 9 | use {defmt_rtt as _, panic_probe as _}; | 9 | use {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 | ||
| 6 | use defmt::{error, info}; | 6 | use defmt::{error, info}; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, MasterClock, Sample as _, SampleWidth, I2S}; | 8 | use embassy_nrf::i2s::{self, Channels, Config, DoubleBuffering, I2S, MasterClock, Sample as _, SampleWidth}; |
| 9 | use embassy_nrf::{bind_interrupts, peripherals}; | 9 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| @@ -140,11 +140,7 @@ impl SineOsc { | |||
| 140 | 140 | ||
| 141 | #[inline] | 141 | #[inline] |
| 142 | fn abs(value: f32) -> f32 { | 142 | fn 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 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_nrf::config::{Config, HfclkSource}; | ||
| 6 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 7 | use embassy_nrf::radio::ieee802154::{self, Packet}; | ||
| 8 | use embassy_nrf::{peripherals, radio}; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | embassy_nrf::bind_interrupts!(struct Irqs { | ||
| 13 | RADIO => radio::InterruptHandler<peripherals::RADIO>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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 | |||
| 4 | use embassy_executor::Spawner; | ||
| 5 | use embassy_nrf::config::{Config, HfclkSource}; | ||
| 6 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 7 | use embassy_nrf::radio::ieee802154::{self, Packet}; | ||
| 8 | use embassy_nrf::{peripherals, radio}; | ||
| 9 | use embassy_time::Timer; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | embassy_nrf::bind_interrupts!(struct Irqs { | ||
| 13 | RADIO => radio::InterruptHandler<peripherals::RADIO>; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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(); | |||
| 112 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); | 112 | static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new(); |
| 113 | 113 | ||
| 114 | #[interrupt] | 114 | #[interrupt] |
| 115 | unsafe fn SWI1_EGU1() { | 115 | unsafe fn EGU1_SWI1() { |
| 116 | EXECUTOR_HIGH.on_interrupt() | 116 | unsafe { EXECUTOR_HIGH.on_interrupt() } |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | #[interrupt] | 119 | #[interrupt] |
| 120 | unsafe fn SWI0_EGU0() { | 120 | unsafe 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] |
| 31 | async fn main(spawner: Spawner) { | 31 | async 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 | |||
| 4 | use defmt::{todo, *}; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_nrf::config::HfclkSource; | ||
| 7 | use embassy_nrf::nfct::{Config as NfcConfig, NfcId, NfcT}; | ||
| 8 | use embassy_nrf::{bind_interrupts, nfct}; | ||
| 9 | use iso14443_4::{Card, IsoDep}; | ||
| 10 | use {defmt_rtt as _, embassy_nrf as _, panic_probe as _}; | ||
| 11 | |||
| 12 | bind_interrupts!(struct Irqs { | ||
| 13 | NFCT => nfct::InterruptHandler; | ||
| 14 | }); | ||
| 15 | |||
| 16 | #[embassy_executor::main] | ||
| 17 | async 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)] | ||
| 121 | struct 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)] | ||
| 131 | struct ApduParseError; | ||
| 132 | |||
| 133 | impl<'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 | |||
| 158 | mod 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 | |||
| 212 | mod 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] |
| 22 | async fn main(_p: Spawner) { | 22 | async 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 | ||
| 6 | use defmt::info; | 6 | use defmt::info; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | 8 | use embassy_nrf::gpio::{Level, OutputDrive, Pull}; |
| 9 | use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; | 9 | use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; |
| 10 | use embassy_nrf::ppi::Ppi; | 10 | use embassy_nrf::ppi::Ppi; |
| 11 | use gpiote::{OutputChannel, OutputChannelPolarity}; | 11 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 6 | use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; |
| 7 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| @@ -71,7 +71,7 @@ static DUTY: [u16; 1024] = [ | |||
| 71 | #[embassy_executor::main] | 71 | #[embassy_executor::main] |
| 72 | async fn main(_spawner: Spawner) { | 72 | async 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 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_nrf::gpio::{Input, Pull}; | 8 | use embassy_nrf::gpio::Pull; |
| 9 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; | 9 | use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; |
| 10 | use embassy_nrf::ppi::Ppi; | 10 | use embassy_nrf::ppi::Ppi; |
| 11 | use embassy_nrf::pwm::{Config, Prescaler, SequenceConfig, SequencePwm, SingleSequenceMode, SingleSequencer}; | 11 | use 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 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::pwm::{Prescaler, SimplePwm}; | 6 | use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; |
| 7 | use embassy_time::Timer; | 7 | use embassy_time::Timer; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| 10 | #[embassy_executor::main] | 10 | #[embassy_executor::main] |
| 11 | async fn main(_spawner: Spawner) { | 11 | async 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 | ||
| 6 | use cortex_m_rt::entry; | 6 | use cortex_m_rt::entry; |
| 7 | use defmt::{info, unwrap}; | 7 | use defmt::{info, unwrap}; |
| 8 | use embassy_executor::raw::TaskStorage; | ||
| 9 | use embassy_executor::Executor; | 8 | use embassy_executor::Executor; |
| 9 | use embassy_executor::raw::TaskStorage; | ||
| 10 | use embassy_time::Timer; | 10 | use embassy_time::Timer; |
| 11 | use static_cell::StaticCell; | 11 | use static_cell::StaticCell; |
| 12 | use {defmt_rtt as _, panic_probe as _}; | 12 | use {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 | ||
| 50 | unsafe fn make_static<T>(t: &T) -> &'static T { | 50 | unsafe 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 | |||
| 4 | use core::cell::RefCell; | ||
| 5 | |||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_nrf::gpio::{Level, Output, OutputDrive}; | ||
| 8 | use embassy_nrf::interrupt; | ||
| 9 | use embassy_nrf::rtc::Rtc; | ||
| 10 | use embassy_sync::blocking_mutex::Mutex; | ||
| 11 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | ||
| 12 | use portable_atomic::AtomicU64; | ||
| 13 | use {defmt_rtt as _, panic_probe as _}; | ||
| 14 | |||
| 15 | // 64 bit counter which will never overflow. | ||
| 16 | static TICK_COUNTER: AtomicU64 = AtomicU64::new(0); | ||
| 17 | static RTC: Mutex<CriticalSectionRawMutex, RefCell<Option<Rtc<'static>>>> = Mutex::new(RefCell::new(None)); | ||
| 18 | |||
| 19 | #[embassy_executor::main] | ||
| 20 | async 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] | ||
| 45 | fn 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 { | |||
| 16 | async fn main(_p: Spawner) { | 16 | async 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 { | |||
| 18 | async fn main(_p: Spawner) { | 18 | async 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 { | |||
| 14 | async fn my_task(spawner: Spawner, n: u32) { | 14 | async 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] |
| 21 | async fn main(spawner: Spawner) { | 21 | async 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 _}; | |||
| 10 | async fn my_task(n: u32) { | 10 | async 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] |
| 17 | async fn main(spawner: Spawner) { | 18 | async 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 | |||
| 4 | use core::net::Ipv6Addr; | ||
| 5 | |||
| 6 | use defmt::{info, unwrap, warn}; | ||
| 7 | use embassy_executor::Spawner; | ||
| 8 | use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket}; | ||
| 9 | use embassy_net::{IpAddress, IpEndpoint, IpListenEndpoint, Ipv6Cidr, StackResources, StaticConfigV6}; | ||
| 10 | use embassy_nrf::config::{Config, HfclkSource}; | ||
| 11 | use embassy_nrf::rng::Rng; | ||
| 12 | use embassy_nrf::{bind_interrupts, embassy_net_802154_driver as net, peripherals, radio}; | ||
| 13 | use embassy_time::Delay; | ||
| 14 | use embedded_hal_async::delay::DelayNs; | ||
| 15 | use static_cell::StaticCell; | ||
| 16 | use {defmt_rtt as _, panic_probe as _}; | ||
| 17 | |||
| 18 | bind_interrupts!(struct Irqs { | ||
| 19 | RADIO => radio::InterruptHandler<peripherals::RADIO>; | ||
| 20 | RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>; | ||
| 21 | }); | ||
| 22 | |||
| 23 | #[embassy_executor::task] | ||
| 24 | async fn ieee802154_task(runner: net::Runner<'static>) -> ! { | ||
| 25 | runner.run().await | ||
| 26 | } | ||
| 27 | |||
| 28 | #[embassy_executor::task] | ||
| 29 | async fn net_task(mut runner: embassy_net::Runner<'static, net::Device<'static>>) -> ! { | ||
| 30 | runner.run().await | ||
| 31 | } | ||
| 32 | |||
| 33 | #[embassy_executor::main] | ||
| 34 | async 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}; | |||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| 10 | bind_interrupts!(struct Irqs { | 10 | bind_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] |
| 26 | async fn main(spawner: Spawner) { | 26 | async 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::*; | |||
| 9 | use embassy_executor::Spawner; | 9 | use embassy_executor::Spawner; |
| 10 | use embassy_nrf::twim::{self, Twim}; | 10 | use embassy_nrf::twim::{self, Twim}; |
| 11 | use embassy_nrf::{bind_interrupts, peripherals}; | 11 | use embassy_nrf::{bind_interrupts, peripherals}; |
| 12 | use static_cell::ConstStaticCell; | ||
| 12 | use {defmt_rtt as _, panic_probe as _}; | 13 | use {defmt_rtt as _, panic_probe as _}; |
| 13 | 14 | ||
| 14 | const ADDRESS: u8 = 0x50; | 15 | const ADDRESS: u8 = 0x50; |
| 15 | 16 | ||
| 16 | bind_interrupts!(struct Irqs { | 17 | bind_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 _}; | |||
| 19 | const ADDRESS: u8 = 0x50; | 19 | const ADDRESS: u8 = 0x50; |
| 20 | 20 | ||
| 21 | bind_interrupts!(struct Irqs { | 21 | bind_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}; | |||
| 10 | use {defmt_rtt as _, panic_probe as _}; | 10 | use {defmt_rtt as _, panic_probe as _}; |
| 11 | 11 | ||
| 12 | bind_interrupts!(struct Irqs { | 12 | bind_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}; | |||
| 7 | use {defmt_rtt as _, panic_probe as _}; | 7 | use {defmt_rtt as _, panic_probe as _}; |
| 8 | 8 | ||
| 9 | bind_interrupts!(struct Irqs { | 9 | bind_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}; | |||
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {defmt_rtt as _, panic_probe as _}; |
| 9 | 9 | ||
| 10 | bind_interrupts!(struct Irqs { | 10 | bind_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 _}; | |||
| 13 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); | 13 | static CHANNEL: Channel<ThreadModeRawMutex, [u8; 8], 1> = Channel::new(); |
| 14 | 14 | ||
| 15 | bind_interrupts!(struct Irqs { | 15 | bind_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] |
| 55 | async fn reader(mut rx: UarteRx<'static, UARTE0>) { | 55 | async 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 | ||
| 4 | use core::mem; | ||
| 5 | |||
| 6 | use defmt::*; | 4 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::StackResources; | ||
| 8 | use embassy_net::tcp::TcpSocket; | 7 | use embassy_net::tcp::TcpSocket; |
| 9 | use embassy_net::{Stack, StackResources}; | ||
| 10 | use embassy_nrf::rng::Rng; | 8 | use embassy_nrf::rng::Rng; |
| 11 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 12 | use embassy_nrf::usb::Driver; | 9 | use embassy_nrf::usb::Driver; |
| 10 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 13 | use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; | 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, rng, usb}; |
| 14 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; | 12 | use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState}; |
| 15 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; | 13 | use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; |
| @@ -20,11 +18,11 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 20 | 18 | ||
| 21 | bind_interrupts!(struct Irqs { | 19 | bind_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 | ||
| 27 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 25 | type MyDriver = Driver<'static, HardwareVbusDetect>; |
| 28 | 26 | ||
| 29 | const MTU: usize = 1514; | 27 | const 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] |
| 42 | async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! { | 40 | async 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] |
| 47 | async fn main(spawner: Spawner) { | 45 | async 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 | ||
| 4 | use core::mem; | 4 | use core::sync::atomic::{AtomicBool, AtomicU8, Ordering}; |
| 5 | use core::sync::atomic::{AtomicBool, Ordering}; | ||
| 6 | 5 | ||
| 7 | use defmt::*; | 6 | use defmt::*; |
| 8 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 9 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| 10 | use embassy_futures::select::{select, Either}; | 9 | use embassy_futures::select::{Either, select}; |
| 11 | use embassy_nrf::gpio::{Input, Pull}; | 10 | use embassy_nrf::gpio::{Input, Pull}; |
| 12 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 13 | use embassy_nrf::usb::Driver; | 11 | use embassy_nrf::usb::Driver; |
| 12 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 14 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 13 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 15 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; | 14 | use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; |
| 16 | use embassy_sync::signal::Signal; | 15 | use embassy_sync::signal::Signal; |
| 17 | use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State}; | 16 | use embassy_usb::class::hid::{ |
| 17 | HidBootProtocol, HidProtocolMode, HidReaderWriter, HidSubclass, ReportId, RequestHandler, State, | ||
| 18 | }; | ||
| 18 | use embassy_usb::control::OutResponse; | 19 | use embassy_usb::control::OutResponse; |
| 19 | use embassy_usb::{Builder, Config, Handler}; | 20 | use embassy_usb::{Builder, Config, Handler}; |
| 20 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; | 21 | use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor}; |
| @@ -22,19 +23,20 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 22 | 23 | ||
| 23 | bind_interrupts!(struct Irqs { | 24 | bind_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 | ||
| 28 | static SUSPENDED: AtomicBool = AtomicBool::new(false); | 29 | static SUSPENDED: AtomicBool = AtomicBool::new(false); |
| 29 | 30 | ||
| 31 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 32 | |||
| 30 | #[embassy_executor::main] | 33 | #[embassy_executor::main] |
| 31 | async fn main(_spawner: Spawner) { | 34 | async 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 | ||
| 4 | use core::mem; | 4 | use core::sync::atomic::{AtomicU8, Ordering}; |
| 5 | 5 | ||
| 6 | use defmt::*; | 6 | use defmt::*; |
| 7 | use embassy_executor::Spawner; | 7 | use embassy_executor::Spawner; |
| 8 | use embassy_futures::join::join; | 8 | use embassy_futures::join::join; |
| 9 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 10 | use embassy_nrf::usb::Driver; | 9 | use embassy_nrf::usb::Driver; |
| 10 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 12 | use embassy_time::Timer; | 12 | use embassy_time::Timer; |
| 13 | use embassy_usb::class::hid::{HidWriter, ReportId, RequestHandler, State}; | 13 | use embassy_usb::class::hid::{ |
| 14 | HidBootProtocol, HidProtocolMode, HidSubclass, HidWriter, ReportId, RequestHandler, State, | ||
| 15 | }; | ||
| 14 | use embassy_usb::control::OutResponse; | 16 | use embassy_usb::control::OutResponse; |
| 15 | use embassy_usb::{Builder, Config}; | 17 | use embassy_usb::{Builder, Config}; |
| 16 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; | 18 | use usbd_hid::descriptor::{MouseReport, SerializedDescriptor}; |
| @@ -18,17 +20,18 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 18 | 20 | ||
| 19 | bind_interrupts!(struct Irqs { | 21 | bind_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 | ||
| 26 | static HID_PROTOCOL_MODE: AtomicU8 = AtomicU8::new(HidProtocolMode::Boot as u8); | ||
| 27 | |||
| 24 | #[embassy_executor::main] | 28 | #[embassy_executor::main] |
| 25 | async fn main(_spawner: Spawner) { | 29 | async 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 | ||
| 4 | use core::mem; | ||
| 5 | |||
| 6 | use defmt::{info, panic}; | 4 | use defmt::{info, panic}; |
| 7 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 8 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_nrf::usb::Driver; | ||
| 9 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; | 8 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; |
| 10 | use embassy_nrf::usb::{Driver, Instance}; | ||
| 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 9 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| @@ -16,17 +14,16 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 16 | 14 | ||
| 17 | bind_interrupts!(struct Irqs { | 15 | bind_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] |
| 23 | async fn main(_spawner: Spawner) { | 21 | async 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 | ||
| 102 | async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( | 92 | async 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 | ||
| 4 | use core::mem; | ||
| 5 | |||
| 6 | use defmt::{info, panic, unwrap}; | 4 | use defmt::{info, panic, unwrap}; |
| 7 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 8 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 9 | use embassy_nrf::usb::Driver; | 6 | use embassy_nrf::usb::Driver; |
| 7 | use embassy_nrf::usb::vbus_detect::HardwareVbusDetect; | ||
| 10 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 8 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 11 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 9 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 12 | use embassy_usb::driver::EndpointError; | 10 | use embassy_usb::driver::EndpointError; |
| @@ -16,10 +14,10 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 16 | 14 | ||
| 17 | bind_interrupts!(struct Irqs { | 15 | bind_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 | type MyDriver = Driver<'static, peripherals::USBD, HardwareVbusDetect>; | 20 | type MyDriver = Driver<'static, HardwareVbusDetect>; |
| 23 | 21 | ||
| 24 | #[embassy_executor::task] | 22 | #[embassy_executor::task] |
| 25 | async fn usb_task(mut device: UsbDevice<'static, MyDriver>) { | 23 | async 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] |
| 40 | async fn main(spawner: Spawner) { | 38 | async 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 | ||
| 93 | struct Disconnected {} | 83 | struct 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 | ||
| 4 | use core::mem; | ||
| 5 | |||
| 6 | use defmt::{info, panic}; | 4 | use defmt::{info, panic}; |
| 7 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 8 | use embassy_futures::join::join; | 6 | use embassy_futures::join::join; |
| 7 | use embassy_nrf::usb::Driver; | ||
| 9 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; | 8 | use embassy_nrf::usb::vbus_detect::{HardwareVbusDetect, VbusDetect}; |
| 10 | use embassy_nrf::usb::{Driver, Instance}; | ||
| 11 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; | 9 | use embassy_nrf::{bind_interrupts, pac, peripherals, usb}; |
| 12 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; | 10 | use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; |
| 13 | use embassy_usb::driver::EndpointError; | 11 | use embassy_usb::driver::EndpointError; |
| @@ -18,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 18 | 16 | ||
| 19 | bind_interrupts!(struct Irqs { | 17 | bind_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] |
| 28 | async fn main(_spawner: Spawner) { | 26 | async 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 | ||
| 121 | async fn echo<'d, T: Instance + 'd, P: VbusDetect + 'd>( | 111 | async 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 @@ | |||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_nrf::gpio::{Input, Pull}; | 6 | use embassy_nrf::gpio::{Input, Pull}; |
| 7 | use embassy_nrf::wdt::{Config, Watchdog}; | 7 | use embassy_nrf::wdt::{Config, HaltConfig, Watchdog}; |
| 8 | use {defmt_rtt as _, panic_probe as _}; | 8 | use {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 | ||
| 4 | use defmt::{info, unwrap, warn}; | 4 | use defmt::{info, unwrap, warn}; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_net::StackResources; | ||
| 6 | use embassy_net::tcp::TcpSocket; | 7 | use embassy_net::tcp::TcpSocket; |
| 7 | use embassy_net::{Stack, StackResources}; | ||
| 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; | 8 | use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; |
| 9 | use embassy_nrf::rng::Rng; | 9 | use embassy_nrf::rng::Rng; |
| 10 | use embassy_nrf::spim::{self, Spim}; | 10 | use embassy_nrf::spim::{self, Spim}; |
| @@ -27,17 +27,15 @@ bind_interrupts!(struct Irqs { | |||
| 27 | async fn wifi_task( | 27 | async 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] |
| 39 | async fn net_task(stack: &'static Stack<hosted::NetDriver<'static>>) -> ! { | 37 | async 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 | ||
