From b2d8d7f009877ad288a563643f3e983eaecafc58 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:48:42 +0200 Subject: add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 267 +++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 examples/rp/src/bin/orchestrate_tasks.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs new file mode 100644 index 000000000..b9282e273 --- /dev/null +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -0,0 +1,267 @@ +//! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system. +//! +//! We demonstrate how to: +//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. +//! - use a signal to terminate a task. +//! - use command channels to send commands to another task. +//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple channels. +//! +//! There are more patterns to orchestrate tasks, this is just one example. +//! +//! We will use these tasks to generate example "state information": +//! - a task that generates random numbers in intervals of 60s +//! - a task that generates random numbers in intervals of 30s +//! - a task that generates random numbers in intervals of 90s +//! - a task that notifies about being attached/disattached from usb power +//! - a task that measures vsys voltage in intervals of 30s + +#![no_std] +#![no_main] + +use assign_resources::assign_resources; +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::select::{select, Either}; +use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; +use embassy_rp::bind_interrupts; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Pull}; +use embassy_rp::peripherals; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::{channel, signal}; +use embassy_time::{Duration, Timer}; +use rand::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks. +// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software +// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins. +// For this example it will not matter much, the concept of what we are showing remains valid. +assign_resources! { + vsys: Vsys { + adc: ADC, + pin_29: PIN_29, + }, + vbus: Vbus { + pin_24: PIN_24, + }, +} + +bind_interrupts!(struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; +}); + +/// This is the type of Events that we will send from the worker tasks to the orchestrating task. +enum Events { + UsbPowered(bool), + VsysVoltage(f32), + FirstRandomSeed(u32), + SecondRandomSeed(u32), + ThirdRandomSeed(u32), +} + +/// This is the type of Commands that we will send from the orchestrating task to the worker tasks. +/// Note that we are lazy here and only have one command, you might want to have more. +enum Commands { + /// This command will stop the appropriate worker task + Stop, +} + +/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex. +#[derive(Default, Debug, Clone, Format)] +struct State { + usb_powered: bool, + vsys_voltage: f32, + first_random_seed: u32, + second_random_seed: u32, + third_random_seed: u32, + times_we_got_first_random_seed: u8, + maximum_times_we_want_first_random_seed: u8, +} + +impl State { + fn new() -> Self { + Self { + usb_powered: false, + vsys_voltage: 0.0, + first_random_seed: 0, + second_random_seed: 0, + third_random_seed: 0, + times_we_got_first_random_seed: 0, + maximum_times_we_want_first_random_seed: 3, + } + } +} + +/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events. +/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we +/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for +/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots +/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting. +/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options. +static EVENT_CHANNEL: channel::Channel = channel::Channel::new(); + +/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. +static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); + +// And now we can put all this into use + +/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the +/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running. +#[embassy_executor::main] +async fn main(spawner: Spawner) { + // initialize the peripherals + let p = embassy_rp::init(Default::default()); + // split the resources, for convenience - see above + let r = split_resources! {p}; + + // spawn the tasks + spawner.spawn(orchestrate(spawner)).unwrap(); + spawner.spawn(random_30s(spawner)).unwrap(); + spawner.spawn(random_60s(spawner)).unwrap(); + spawner.spawn(random_90s(spawner)).unwrap(); + spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); + spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); +} + +/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. +#[embassy_executor::task] +async fn orchestrate(_spawner: Spawner) { + let mut state = State::new(); + + // we need to have a receiver for the events + let receiver = EVENT_CHANNEL.receiver(); + + loop { + // we await on the receiver, this will block until a new event is available + // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event + // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html + // The task random_30s does a select, if you want to have a look at that. + // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame. + // We keep it simple here. + let event = receiver.receive().await; + + // react to the events + match event { + Events::UsbPowered(usb_powered) => { + // update the state and/or react to the event here + state.usb_powered = usb_powered; + info!("Usb powered: {}", usb_powered); + } + Events::VsysVoltage(voltage) => { + // update the state and/or react to the event here + state.vsys_voltage = voltage; + info!("Vsys voltage: {}", voltage); + } + Events::FirstRandomSeed(seed) => { + // update the state and/or react to the event here + state.first_random_seed = seed; + // here we change some meta state, we count how many times we got the first random seed + state.times_we_got_first_random_seed += 1; + info!( + "First random seed: {}, and that was iteration {} of receiving this.", + seed, &state.times_we_got_first_random_seed + ); + } + Events::SecondRandomSeed(seed) => { + // update the state and/or react to the event here + state.second_random_seed = seed; + info!("Second random seed: {}", seed); + } + Events::ThirdRandomSeed(seed) => { + // update the state and/or react to the event here + state.third_random_seed = seed; + info!("Third random seed: {}", seed); + } + } + // we now have an altered state + // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here + // for now we just keep it simple + info!("State: {:?}", &state); + + // here we react to the state, in this case here we want to stop the first random seed task after we got it a defined number of times + if state.times_we_got_first_random_seed == state.maximum_times_we_want_first_random_seed { + info!("Stopping the first random signal task"); + // we send a command to the task + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + } + } +} + +/// This task will generate random numbers in intervals of 30s +/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. +#[embassy_executor::task] +async fn random_30s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + // we either await on the timer or the signal, whichever comes first. + let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await; + match futures { + Either::First(_) => { + // we received are operating on the timer + info!("30s are up, generating random number"); + let random_number = rng.next_u32(); + sender.send(Events::FirstRandomSeed(random_number)).await; + } + Either::Second(_) => { + // we received the signal to stop + info!("Received signal to stop, goodbye!"); + break; + } + } + } +} + +/// This task will generate random numbers in intervals of 60s +#[embassy_executor::task] +async fn random_60s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + Timer::after(Duration::from_secs(60)).await; + let random_number = rng.next_u32(); + sender.send(Events::SecondRandomSeed(random_number)).await; + } +} + +/// This task will generate random numbers in intervals of 90s +#[embassy_executor::task] +async fn random_90s(_spawner: Spawner) { + let mut rng = RoscRng; + let sender = EVENT_CHANNEL.sender(); + loop { + Timer::after(Duration::from_secs(90)).await; + let random_number = rng.next_u32(); + sender.send(Events::ThirdRandomSeed(random_number)).await; + } +} + +/// This task will notify if we are connected to usb power +#[embassy_executor::task] +pub async fn usb_power(_spawner: Spawner, r: Vbus) { + let mut vbus_in = Input::new(r.pin_24, Pull::None); + let sender = EVENT_CHANNEL.sender(); + loop { + sender.send(Events::UsbPowered(vbus_in.is_high())).await; + vbus_in.wait_for_any_edge().await; + } +} + +/// This task will measure the vsys voltage in intervals of 30s +#[embassy_executor::task] +pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) { + let mut adc = Adc::new(r.adc, Irqs, Config::default()); + let vsys_in = r.pin_29; + let mut channel = Channel::new_pin(vsys_in, Pull::None); + let sender = EVENT_CHANNEL.sender(); + loop { + // read the adc value + let adc_value = adc.read(&mut channel).await.unwrap(); + // convert the adc value to voltage. + // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc + let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0; + sender.send(Events::VsysVoltage(voltage)).await; + Timer::after(Duration::from_secs(30)).await; + } +} -- cgit From 97125e53cdf425a146c6552a25164cdfd6075fe7 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:54:02 +0200 Subject: add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index b9282e273..1ef6b5fb6 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -23,10 +23,9 @@ use defmt::*; use embassy_executor::Spawner; use embassy_futures::select::{select, Either}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; -use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::peripherals; +use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::{channel, signal}; use embassy_time::{Duration, Timer}; -- cgit From 5d46b694ca60ee69d83eb2bd53f592b2c5b03d28 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 27 Jul 2024 14:57:46 +0200 Subject: add example to rp: orchestrate multiple tasks --- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 1ef6b5fb6..b3c37de4c 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -4,7 +4,7 @@ //! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. //! - use a signal to terminate a task. //! - use command channels to send commands to another task. -//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple channels. +//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures. //! //! There are more patterns to orchestrate tasks, this is just one example. //! -- cgit From e05e5d33f0ab832b2ea1c48674c99b41581118be Mon Sep 17 00:00:00 2001 From: rafael Date: Sun, 28 Jul 2024 00:19:54 +0200 Subject: review comments --- examples/rp/src/bin/orchestrate_tasks.rs | 66 ++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index b3c37de4c..0e21d5833 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -14,6 +14,7 @@ //! - a task that generates random numbers in intervals of 90s //! - a task that notifies about being attached/disattached from usb power //! - a task that measures vsys voltage in intervals of 30s +//! - a task that consumes the state information and reacts to it #![no_std] #![no_main] @@ -57,6 +58,7 @@ enum Events { FirstRandomSeed(u32), SecondRandomSeed(u32), ThirdRandomSeed(u32), + ResetFirstRandomSeed, } /// This is the type of Commands that we will send from the orchestrating task to the worker tasks. @@ -103,6 +105,11 @@ static EVENT_CHANNEL: channel::Channel = ch /// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); +/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although +/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice +/// and depends on your use case. +static CONSUMER_CHANNEL: channel::Channel = channel::Channel::new(); + // And now we can put all this into use /// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the @@ -116,11 +123,11 @@ async fn main(spawner: Spawner) { // spawn the tasks spawner.spawn(orchestrate(spawner)).unwrap(); - spawner.spawn(random_30s(spawner)).unwrap(); spawner.spawn(random_60s(spawner)).unwrap(); spawner.spawn(random_90s(spawner)).unwrap(); spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); + spawner.spawn(consumer(spawner)).unwrap(); } /// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. @@ -131,6 +138,9 @@ async fn orchestrate(_spawner: Spawner) { // we need to have a receiver for the events let receiver = EVENT_CHANNEL.receiver(); + // and we need a sender for the consumer task + let state_sender = CONSUMER_CHANNEL.sender(); + loop { // we await on the receiver, this will block until a new event is available // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event @@ -172,23 +182,65 @@ async fn orchestrate(_spawner: Spawner) { state.third_random_seed = seed; info!("Third random seed: {}", seed); } + Events::ResetFirstRandomSeed => { + // update the state and/or react to the event here + state.times_we_got_first_random_seed = 0; + state.first_random_seed = 0; + info!("Resetting the first random seed counter"); + } } // we now have an altered state // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here // for now we just keep it simple - info!("State: {:?}", &state); - // here we react to the state, in this case here we want to stop the first random seed task after we got it a defined number of times - if state.times_we_got_first_random_seed == state.maximum_times_we_want_first_random_seed { - info!("Stopping the first random signal task"); - // we send a command to the task - STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + // we send the state to the consumer task + // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example + // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the + // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed. + // We keep it simple here. + state_sender.send(state.clone()).await; + } +} + +/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex +/// and we could have multiple consumer tasks, each reacting to different parts of the state. +#[embassy_executor::task] +async fn consumer(spawner: Spawner) { + // we need to have a receiver for the state + let receiver = CONSUMER_CHANNEL.receiver(); + let sender = EVENT_CHANNEL.sender(); + loop { + // we await on the receiver, this will block until a new state is available + let state = receiver.receive().await; + // react to the state, in this case here we just log it + info!("The consumer has reveived this state: {:?}", &state); + + // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system + match state.times_we_got_first_random_seed { + max if max == state.maximum_times_we_want_first_random_seed => { + info!("Stopping the first random signal task"); + // we send a command to the task + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + // we notify the orchestrator that we have sent the command + sender.send(Events::ResetFirstRandomSeed).await; + } + 0 => { + // we start the task, which presents us with an interesting problem, because we may return here before the task has started + // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully + info!("Starting the first random signal task"); + match spawner.spawn(random_30s(spawner)) { + Ok(_) => info!("Successfully spawned random_30s task"), + Err(e) => info!("Failed to spawn random_30s task: {:?}", e), + } + } + _ => {} } } } /// This task will generate random numbers in intervals of 30s /// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. +/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically. #[embassy_executor::task] async fn random_30s(_spawner: Spawner) { let mut rng = RoscRng; -- cgit From d4ab9fc247731e5f8ede4bb60a8c3c63136e1e6d Mon Sep 17 00:00:00 2001 From: James Bowes Date: Mon, 26 Aug 2024 10:33:13 -0300 Subject: chore: Remove unused keyboard code from rp mouse example The usb mouse example included code copied from the keyboard example to set up a button, which is not used in the mouse example. Remove it, to make the example clearer. --- examples/rp/src/bin/usb_hid_mouse.rs | 7 ------- 1 file changed, 7 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs index cce344fb0..5ee650910 100644 --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -8,7 +8,6 @@ use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; -use embassy_rp::gpio::{Input, Pull}; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; use embassy_time::Timer; @@ -75,12 +74,6 @@ async fn main(_spawner: Spawner) { // Run the USB device. let usb_fut = usb.run(); - // Set up the signal pin that will be used to trigger the keyboard. - let mut signal_pin = Input::new(p.PIN_16, Pull::None); - - // Enable the schmitt trigger to slightly debounce. - signal_pin.set_schmitt(true); - let (reader, mut writer) = hid.split(); // Do stuff with the class! -- cgit From 9347571fea243719826ff21b250bc0dff7f51fa5 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 26 Aug 2024 20:28:30 +0200 Subject: rp: add example code to flash bluetooth fw (#3290) --- examples/rp/src/bin/bluetooth.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs index 901521b60..7524e7929 100644 --- a/examples/rp/src/bin/bluetooth.rs +++ b/examples/rp/src/bin/bluetooth.rs @@ -43,8 +43,10 @@ async fn main(spawner: Spawner) { // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; + //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) }; let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); -- cgit From b9a1aaea5b89bd5689796bdfa4227353ee8a452b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 9 Sep 2024 01:09:15 +0200 Subject: cyw43: add support for WPA3 and more extensive security options. --- examples/rp/src/bin/wifi_tcp_server.rs | 7 +++++-- examples/rp/src/bin/wifi_webrequest.rs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 61eeb82f7..b2950d98a 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -7,6 +7,7 @@ use core::str::from_utf8; +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; @@ -95,8 +96,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - //control.join_open(WIFI_NETWORK).await; - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 889371241..b43be8905 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -7,6 +7,7 @@ use core::str::from_utf8; +use cyw43::JoinOptions; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; @@ -98,8 +99,10 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(net_task(stack))); loop { - //match control.join_open(WIFI_NETWORK).await { // for open networks - match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await { + match control + .join(WIFI_NETWORK, JoinOptions::new(WIFI_PASSWORD.as_bytes())) + .await + { Ok(_) => break, Err(err) => { info!("join failed with status={}", err.status); -- cgit From be0d9775e3bcc3c1bd1448e357d7c6cd67b68991 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 11 Sep 2024 22:06:26 +0200 Subject: net: refactor to simplify lifetimes/generics. --- examples/rp/src/bin/ethernet_w5500_multisocket.rs | 19 +++++++++---------- examples/rp/src/bin/ethernet_w5500_tcp_client.rs | 13 ++++++------- examples/rp/src/bin/ethernet_w5500_tcp_server.rs | 13 ++++++------- examples/rp/src/bin/ethernet_w5500_udp.rs | 13 ++++++------- examples/rp/src/bin/usb_ethernet.rs | 11 +++++------ examples/rp/src/bin/wifi_ap_tcp_server.rs | 18 ++++++------------ examples/rp/src/bin/wifi_scan.rs | 5 ++--- examples/rp/src/bin/wifi_tcp_server.rs | 18 ++++++------------ examples/rp/src/bin/wifi_webrequest.rs | 18 ++++++------------ 9 files changed, 52 insertions(+), 76 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index aaa035a72..12003adbe 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -36,8 +36,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -71,17 +71,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -89,12 +88,12 @@ async fn main(spawner: Spawner) { info!("IP address: {:?}", local_addr); // Create two sockets listening to the same port, to handle simultaneous connections - unwrap!(spawner.spawn(listen_task(&stack, 0, 1234))); - unwrap!(spawner.spawn(listen_task(&stack, 1, 1234))); + unwrap!(spawner.spawn(listen_task(stack, 0, 1234))); + unwrap!(spawner.spawn(listen_task(stack, 1, 1234))); } #[embassy_executor::task(pool_size = 2)] -async fn listen_task(stack: &'static Stack>, id: u8, port: u16) { +async fn listen_task(stack: Stack<'static>, id: u8, port: u16) { let mut rx_buffer = [0; 4096]; let mut tx_buffer = [0; 4096]; let mut buf = [0; 4096]; @@ -131,7 +130,7 @@ async fn listen_task(stack: &'static Stack>, id: u8, port: u16) } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 8e96a114c..d66a43a88 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -38,8 +38,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -74,17 +74,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -119,7 +118,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 40736bf3c..97d9bd4c9 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -37,8 +37,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -73,17 +73,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -128,7 +127,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index c79f01538..b1b5f9758 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -36,8 +36,8 @@ async fn ethernet_task( } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -71,17 +71,16 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( + let (stack, runner) = embassy_net::new( device, embassy_net::Config::dhcpv4(Default::default()), RESOURCES.init(StackResources::new()), seed, - )); + ); // Launch network task - unwrap!(spawner.spawn(net_task(&stack))); + unwrap!(spawner.spawn(net_task(runner))); info!("Waiting for DHCP..."); let cfg = wait_for_config(stack).await; @@ -108,7 +107,7 @@ async fn main(spawner: Spawner) { } } -async fn wait_for_config(stack: &'static Stack>) -> embassy_net::StaticConfigV4 { +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { loop { if let Some(config) = stack.config_v4() { return config.clone(); diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 03c510f37..9a15125d4 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Stack, StackResources}; +use embassy_net::StackResources; use embassy_rp::clocks::RoscRng; use embassy_rp::peripherals::USB; use embassy_rp::usb::{Driver, InterruptHandler}; @@ -40,8 +40,8 @@ async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! { } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static, MTU>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -108,11 +108,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new(device, config, RESOURCES.init(StackResources::new()), seed)); + let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed); - unwrap!(spawner.spawn(net_task(stack))); + unwrap!(spawner.spawn(net_task(runner))); // And now we can use it! diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 00f404a9b..4c9651433 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -11,7 +11,7 @@ use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -33,8 +33,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -80,16 +80,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); - - unwrap!(spawner.spawn(net_task(stack))); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); + + unwrap!(spawner.spawn(net_task(runner))); //control.start_ap_open("cyw43", 5).await; control.start_ap_wpa2("cyw43", "password", 5).await; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index ab3529112..434f0074c 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -10,7 +10,6 @@ use core::str; use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; -use embassy_net::Stack; use embassy_rp::bind_interrupts; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; @@ -28,8 +27,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index b2950d98a..7bf546e01 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -12,7 +12,7 @@ use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -37,8 +37,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -84,16 +84,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); - - unwrap!(spawner.spawn(net_task(stack))); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); + + unwrap!(spawner.spawn(net_task(runner))); loop { match control diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index b43be8905..1ae909917 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -13,7 +13,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; use embassy_net::tcp::client::{TcpClient, TcpClientState}; -use embassy_net::{Config, Stack, StackResources}; +use embassy_net::{Config, StackResources}; use embassy_rp::bind_interrupts; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Level, Output}; @@ -40,8 +40,8 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat } #[embassy_executor::task] -async fn net_task(stack: &'static Stack>) -> ! { - stack.run().await +async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { + runner.run().await } #[embassy_executor::main] @@ -87,16 +87,10 @@ async fn main(spawner: Spawner) { let seed = rng.next_u64(); // Init network stack - static STACK: StaticCell>> = StaticCell::new(); static RESOURCES: StaticCell> = StaticCell::new(); - let stack = &*STACK.init(Stack::new( - net_device, - config, - RESOURCES.init(StackResources::new()), - seed, - )); - - unwrap!(spawner.spawn(net_task(stack))); + let (stack, runner) = embassy_net::new(net_device, config, RESOURCES.init(StackResources::new()), seed); + + unwrap!(spawner.spawn(net_task(runner))); loop { match control -- cgit From 0bfc98a3e526075ad14517589e4879d14f50ad12 Mon Sep 17 00:00:00 2001 From: kalkyl Date: Tue, 17 Sep 2024 19:41:58 +0200 Subject: rp: Add PIO example for one-wire temperature sensor --- examples/rp/src/bin/pio_onewire.rs | 155 +++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 examples/rp/src/bin/pio_onewire.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs new file mode 100644 index 000000000..5076101ec --- /dev/null +++ b/examples/rp/src/bin/pio_onewire.rs @@ -0,0 +1,155 @@ +//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. + +#![no_std] +#![no_main] +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + PIO0_IRQ_0 => InterruptHandler; +}); + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut pio = Pio::new(p.PIO0, Irqs); + let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); + + loop { + sensor.start().await; // Start a new measurement + Timer::after_secs(1).await; // Allow 1s for the measurement to finish + match sensor.temperature().await { + Ok(temp) => info!("temp = {:?} deg C", temp), + _ => error!("sensor error"), + } + Timer::after_secs(1).await; + } +} + +/// DS18B20 temperature sensor driver +pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { + sm: StateMachine<'d, PIO, SM>, +} + +impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { + /// Create a new instance the driver + pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { + let prg = pio_proc::pio_asm!( + r#" + .wrap_target + again: + pull block + mov x, osr + jmp !x, read + write: + set pindirs, 1 + set pins, 0 + loop1: + jmp x--,loop1 + set pindirs, 0 [31] + wait 1 pin 0 [31] + pull block + mov x, osr + bytes1: + pull block + set y, 7 + set pindirs, 1 + bit1: + set pins, 0 [1] + out pins,1 [31] + set pins, 1 [20] + jmp y--,bit1 + jmp x--,bytes1 + set pindirs, 0 [31] + jmp again + read: + pull block + mov x, osr + bytes2: + set y, 7 + bit2: + set pindirs, 1 + set pins, 0 [1] + set pindirs, 0 [5] + in pins,1 [10] + jmp y--,bit2 + jmp x--,bytes2 + .wrap + "#, + ); + + let pin = common.make_pio_pin(pin); + let mut cfg = Config::default(); + cfg.use_program(&common.load_program(&prg.program), &[]); + cfg.set_out_pins(&[&pin]); + cfg.set_in_pins(&[&pin]); + cfg.set_set_pins(&[&pin]); + cfg.shift_in = ShiftConfig { + auto_fill: true, + direction: ShiftDirection::Right, + threshold: 8, + }; + cfg.clock_divider = 255_u8.into(); + sm.set_config(&cfg); + sm.set_enable(true); + Self { sm } + } + + /// Write bytes over the wire + async fn write_bytes(&mut self, bytes: &[u8]) { + self.sm.tx().wait_push(250).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes { + self.sm.tx().wait_push(*b as u32).await; + } + } + + /// Read bytes from the wire + async fn read_bytes(&mut self, bytes: &mut [u8]) { + self.sm.tx().wait_push(0).await; + self.sm.tx().wait_push(bytes.len() as u32 - 1).await; + for b in bytes.iter_mut() { + *b = (self.sm.rx().wait_pull().await >> 24) as u8; + } + } + + /// Calculate CRC8 of the data + fn crc8(data: &[u8]) -> u8 { + let mut temp; + let mut data_byte; + let mut crc = 0; + for b in data { + data_byte = *b; + for _ in 0..8 { + temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; + } + data_byte >>= 1; + } + } + crc + } + + /// Start a new measurement. Allow at least 1000ms before getting `temperature`. + pub async fn start(&mut self) { + self.write_bytes(&[0xCC, 0x44]).await; + } + + /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. + pub async fn temperature(&mut self) -> Result { + self.write_bytes(&[0xCC, 0xBE]).await; + let mut data = [0; 9]; + self.read_bytes(&mut data).await; + match Self::crc8(&data) == 0 { + true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), + false => Err(()), + } + } +} -- cgit From ce701c3e8ef5f3cd354b74c1a06b6d77a9e812c6 Mon Sep 17 00:00:00 2001 From: Paul Fornage <36117326+paulwrath1223@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:35:59 -0700 Subject: Fixed overflow on `pio_stepper.rs` --- examples/rp/src/bin/pio_stepper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 4952f4fbd..6ee45a414 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -154,7 +154,7 @@ async fn main(_spawner: Spawner) { stepper.step(1000).await; info!("CCW full steps, drop after 1 sec"); - if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(i32::MIN)).await { + if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)).await { info!("Time's up!"); Timer::after(Duration::from_secs(1)).await; } -- cgit From 57c1fbf3089e2a2dc9fe5b7d1f1e094596566395 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 10:04:35 -0400 Subject: Move pio programs into embassy-rp --- examples/rp/src/bin/pio_hd44780.rs | 201 ++++----------------------- examples/rp/src/bin/pio_i2s.rs | 71 +++------- examples/rp/src/bin/pio_onewire.rs | 98 ++----------- examples/rp/src/bin/pio_pwm.rs | 90 +----------- examples/rp/src/bin/pio_rotary_encoder.rs | 85 +++++------- examples/rp/src/bin/pio_servo.rs | 96 ++----------- examples/rp/src/bin/pio_stepper.rs | 135 ++---------------- examples/rp/src/bin/pio_uart.rs | 222 +++--------------------------- examples/rp/src/bin/pio_ws2812.rs | 105 +------------- 9 files changed, 131 insertions(+), 972 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs index 6c02630e0..164e6f8d3 100644 --- a/examples/rp/src/bin/pio_hd44780.rs +++ b/examples/rp/src/bin/pio_hd44780.rs @@ -7,13 +7,11 @@ use core::fmt::Write; use embassy_executor::Spawner; -use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::hd44780::{PioHD44780, PioHD44780CommandSequenceProgram, PioHD44780CommandWordProgram}; use embassy_rp::pwm::{self, Pwm}; -use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef}; use embassy_time::{Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; @@ -43,8 +41,27 @@ async fn main(_spawner: Spawner) { c }); - let mut hd = HD44780::new( - p.PIO0, Irqs, p.DMA_CH3, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, p.PIN_4, p.PIN_5, p.PIN_6, + let Pio { + mut common, sm0, irq0, .. + } = Pio::new(p.PIO0, Irqs); + + let word_prg = PioHD44780CommandWordProgram::new(&mut common); + let seq_prg = PioHD44780CommandSequenceProgram::new(&mut common); + + let mut hd = PioHD44780::new( + &mut common, + sm0, + irq0, + p.DMA_CH3, + p.PIN_0, + p.PIN_1, + p.PIN_2, + p.PIN_3, + p.PIN_4, + p.PIN_5, + p.PIN_6, + &word_prg, + &seq_prg, ) .await; @@ -68,173 +85,3 @@ async fn main(_spawner: Spawner) { Timer::after_secs(1).await; } } - -pub struct HD44780<'l> { - dma: PeripheralRef<'l, AnyChannel>, - sm: StateMachine<'l, PIO0, 0>, - - buf: [u8; 40], -} - -impl<'l> HD44780<'l> { - pub async fn new( - pio: impl Peripheral

+ 'l, - irq: Irqs, - dma: impl Peripheral

+ 'l, - rs: impl PioPin, - rw: impl PioPin, - e: impl PioPin, - db4: impl PioPin, - db5: impl PioPin, - db6: impl PioPin, - db7: impl PioPin, - ) -> HD44780<'l> { - into_ref!(dma); - - let Pio { - mut common, - mut irq0, - mut sm0, - .. - } = Pio::new(pio, irq); - - // takes command words ( <0:4>) - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - .origin 20 - - loop: - out x, 24 - delay: - jmp x--, delay - out pins, 4 side 1 - out null, 4 side 0 - jmp !osre, loop - irq 0 - "#, - ); - - let rs = common.make_pio_pin(rs); - let rw = common.make_pio_pin(rw); - let e = common.make_pio_pin(e); - let db4 = common.make_pio_pin(db4); - let db5 = common.make_pio_pin(db5); - let db6 = common.make_pio_pin(db6); - let db7 = common.make_pio_pin(db7); - - sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&e]); - cfg.clock_divider = 125u8.into(); - cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); - cfg.shift_out = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Left, - threshold: 32, - }; - cfg.fifo_join = FifoJoin::TxOnly; - sm0.set_config(&cfg); - - sm0.set_enable(true); - // init to 8 bit thrice - sm0.tx().push((50000 << 8) | 0x30); - sm0.tx().push((5000 << 8) | 0x30); - sm0.tx().push((200 << 8) | 0x30); - // init 4 bit - sm0.tx().push((200 << 8) | 0x20); - // set font and lines - sm0.tx().push((50 << 8) | 0x20); - sm0.tx().push(0b1100_0000); - - irq0.wait().await; - sm0.set_enable(false); - - // takes command sequences ( , data...) - // many side sets are only there to free up a delay bit! - let prg = pio_proc::pio_asm!( - r#" - .origin 27 - .side_set 1 - - .wrap_target - pull side 0 - out x 1 side 0 ; !rs - out y 7 side 0 ; #data - 1 - - ; rs/rw to e: >= 60ns - ; e high time: >= 500ns - ; e low time: >= 500ns - ; read data valid after e falling: ~5ns - ; write data hold after e falling: ~10ns - - loop: - pull side 0 - jmp !x data side 0 - command: - set pins 0b00 side 0 - jmp shift side 0 - data: - set pins 0b01 side 0 - shift: - out pins 4 side 1 [9] - nop side 0 [9] - out pins 4 side 1 [9] - mov osr null side 0 [7] - out pindirs 4 side 0 - set pins 0b10 side 0 - busy: - nop side 1 [9] - jmp pin more side 0 [9] - mov osr ~osr side 1 [9] - nop side 0 [4] - out pindirs 4 side 0 - jmp y-- loop side 0 - .wrap - more: - nop side 1 [9] - jmp busy side 0 [9] - "# - ); - - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[&e]); - cfg.clock_divider = 8u8.into(); // ~64ns/insn - cfg.set_jmp_pin(&db7); - cfg.set_set_pins(&[&rs, &rw]); - cfg.set_out_pins(&[&db4, &db5, &db6, &db7]); - cfg.shift_out.direction = ShiftDirection::Left; - cfg.fifo_join = FifoJoin::TxOnly; - sm0.set_config(&cfg); - - sm0.set_enable(true); - - // display on and cursor on and blinking, reset display - sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await; - - Self { - dma: dma.map_into(), - sm: sm0, - buf: [0x20; 40], - } - } - - pub async fn add_line(&mut self, s: &[u8]) { - // move cursor to 0:0, prepare 16 characters - self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]); - // move line 2 up - self.buf.copy_within(22..38, 3); - // move cursor to 1:0, prepare 16 characters - self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]); - // file line 2 with spaces - self.buf[22..38].fill(0x20); - // copy input line - let len = s.len().min(16); - self.buf[22..22 + len].copy_from_slice(&s[0..len]); - // set cursor to 1:15 - self.buf[38..].copy_from_slice(&[0x80, 0xcf]); - - self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await; - } -} diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index cf60e5b30..447100ddf 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -13,10 +13,10 @@ use core::mem; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Config, FifoJoin, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; -use fixed::traits::ToFixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -25,61 +25,32 @@ bind_interrupts!(struct Irqs { }); const SAMPLE_RATE: u32 = 48_000; +const BIT_DEPTH: u32 = 16; +const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { let mut p = embassy_rp::init(Default::default()); // Setup pio state machine for i2s output - let mut pio = Pio::new(p.PIO0, Irqs); - - #[rustfmt::skip] - let pio_program = pio_proc::pio_asm!( - ".side_set 2", - " set x, 14 side 0b01", // side 0bWB - W = Word Clock, B = Bit Clock - "left_data:", - " out pins, 1 side 0b00", - " jmp x-- left_data side 0b01", - " out pins 1 side 0b10", - " set x, 14 side 0b11", - "right_data:", - " out pins 1 side 0b10", - " jmp x-- right_data side 0b11", - " out pins 1 side 0b00", - ); + let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); let bit_clock_pin = p.PIN_18; let left_right_clock_pin = p.PIN_19; let data_pin = p.PIN_20; - let data_pin = pio.common.make_pio_pin(data_pin); - let bit_clock_pin = pio.common.make_pio_pin(bit_clock_pin); - let left_right_clock_pin = pio.common.make_pio_pin(left_right_clock_pin); - - let cfg = { - let mut cfg = Config::default(); - cfg.use_program( - &pio.common.load_program(&pio_program.program), - &[&bit_clock_pin, &left_right_clock_pin], - ); - cfg.set_out_pins(&[&data_pin]); - const BIT_DEPTH: u32 = 16; - const CHANNELS: u32 = 2; - let clock_frequency = SAMPLE_RATE * BIT_DEPTH * CHANNELS; - cfg.clock_divider = (125_000_000. / clock_frequency as f64 / 2.).to_fixed(); - cfg.shift_out = ShiftConfig { - threshold: 32, - direction: ShiftDirection::Left, - auto_fill: true, - }; - // join fifos to have twice the time to start the next dma transfer - cfg.fifo_join = FifoJoin::TxOnly; - cfg - }; - pio.sm0.set_config(&cfg); - pio.sm0.set_pin_dirs( - embassy_rp::pio::Direction::Out, - &[&data_pin, &left_right_clock_pin, &bit_clock_pin], + let program = PioI2sOutProgram::new(&mut common); + let mut i2s = PioI2sOut::new( + &mut common, + sm0, + p.DMA_CH0, + data_pin, + bit_clock_pin, + left_right_clock_pin, + SAMPLE_RATE, + BIT_DEPTH, + CHANNELS, + &program, ); // create two audio buffers (back and front) which will take turns being @@ -90,17 +61,13 @@ async fn main(_spawner: Spawner) { let (mut back_buffer, mut front_buffer) = dma_buffer.split_at_mut(BUFFER_SIZE); // start pio state machine - pio.sm0.set_enable(true); - let tx = pio.sm0.tx(); - let mut dma_ref = p.DMA_CH0.into_ref(); - let mut fade_value: i32 = 0; let mut phase: i32 = 0; loop { // trigger transfer of front buffer data to the pio fifo // but don't await the returned future, yet - let dma_future = tx.dma_push(dma_ref.reborrow(), front_buffer); + let dma_future = i2s.write(front_buffer); // fade in audio when bootsel is pressed let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 5076101ec..991510851 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs @@ -6,7 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{self, Common, Config, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine}; +use embassy_rp::pio::{self, InterruptHandler, Pio}; +use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -18,7 +19,11 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let mut pio = Pio::new(p.PIO0, Irqs); - let mut sensor = Ds18b20::new(&mut pio.common, pio.sm0, p.PIN_2); + + let prg = PioOneWireProgram::new(&mut pio.common); + let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); + + let mut sensor = Ds18b20::new(onewire); loop { sensor.start().await; // Start a new measurement @@ -33,89 +38,12 @@ async fn main(_spawner: Spawner) { /// DS18B20 temperature sensor driver pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { - sm: StateMachine<'d, PIO, SM>, + wire: PioOneWire<'d, PIO, SM>, } impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { - /// Create a new instance the driver - pub fn new(common: &mut Common<'d, PIO>, mut sm: StateMachine<'d, PIO, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - r#" - .wrap_target - again: - pull block - mov x, osr - jmp !x, read - write: - set pindirs, 1 - set pins, 0 - loop1: - jmp x--,loop1 - set pindirs, 0 [31] - wait 1 pin 0 [31] - pull block - mov x, osr - bytes1: - pull block - set y, 7 - set pindirs, 1 - bit1: - set pins, 0 [1] - out pins,1 [31] - set pins, 1 [20] - jmp y--,bit1 - jmp x--,bytes1 - set pindirs, 0 [31] - jmp again - read: - pull block - mov x, osr - bytes2: - set y, 7 - bit2: - set pindirs, 1 - set pins, 0 [1] - set pindirs, 0 [5] - in pins,1 [10] - jmp y--,bit2 - jmp x--,bytes2 - .wrap - "#, - ); - - let pin = common.make_pio_pin(pin); - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[]); - cfg.set_out_pins(&[&pin]); - cfg.set_in_pins(&[&pin]); - cfg.set_set_pins(&[&pin]); - cfg.shift_in = ShiftConfig { - auto_fill: true, - direction: ShiftDirection::Right, - threshold: 8, - }; - cfg.clock_divider = 255_u8.into(); - sm.set_config(&cfg); - sm.set_enable(true); - Self { sm } - } - - /// Write bytes over the wire - async fn write_bytes(&mut self, bytes: &[u8]) { - self.sm.tx().wait_push(250).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes { - self.sm.tx().wait_push(*b as u32).await; - } - } - - /// Read bytes from the wire - async fn read_bytes(&mut self, bytes: &mut [u8]) { - self.sm.tx().wait_push(0).await; - self.sm.tx().wait_push(bytes.len() as u32 - 1).await; - for b in bytes.iter_mut() { - *b = (self.sm.rx().wait_pull().await >> 24) as u8; - } + pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { + Self { wire } } /// Calculate CRC8 of the data @@ -139,14 +67,14 @@ impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { /// Start a new measurement. Allow at least 1000ms before getting `temperature`. pub async fn start(&mut self) { - self.write_bytes(&[0xCC, 0x44]).await; + self.wire.write_bytes(&[0xCC, 0x44]).await; } /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. pub async fn temperature(&mut self) -> Result { - self.write_bytes(&[0xCC, 0xBE]).await; + self.wire.write_bytes(&[0xCC, 0xBE]).await; let mut data = [0; 9]; - self.read_bytes(&mut data).await; + self.wire.read_bytes(&mut data).await; match Self::crc8(&data) == 0 { true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), false => Err(()), diff --git a/examples/rp/src/bin/pio_pwm.rs b/examples/rp/src/bin/pio_pwm.rs index 23d63d435..7eabb2289 100644 --- a/examples/rp/src/bin/pio_pwm.rs +++ b/examples/rp/src/bin/pio_pwm.rs @@ -5,12 +5,11 @@ use core::time::Duration; use embassy_executor::Spawner; -use embassy_rp::gpio::Level; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; const REFRESH_INTERVAL: u64 = 20000; @@ -19,93 +18,14 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); // Note that PIN_25 is the led pin on the Pico - let mut pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_25); + let prg = PioPwmProgram::new(&mut common); + let mut pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_25, &prg); pwm_pio.set_period(Duration::from_micros(REFRESH_INTERVAL)); pwm_pio.start(); diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index 58bdadbc0..a7ecc8d0e 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -5,70 +5,32 @@ use defmt::info; use embassy_executor::Spawner; -use embassy_rp::gpio::Pull; use embassy_rp::peripherals::PIO0; -use embassy_rp::{bind_interrupts, pio}; -use fixed::traits::ToFixed; -use pio::{Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{ + bind_interrupts, + pio::{InterruptHandler, Pio}, + pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, +}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioEncoder<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioEncoder<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - pin_a: impl PioPin, - pin_b: impl PioPin, - ) -> Self { - let mut pin_a = pio.make_pio_pin(pin_a); - let mut pin_b = pio.make_pio_pin(pin_b); - pin_a.set_pull(Pull::Up); - pin_b.set_pull(Pull::Up); - sm.set_pin_dirs(pio::Direction::In, &[&pin_a, &pin_b]); - - let prg = pio_proc::pio_asm!("wait 1 pin 1", "wait 0 pin 1", "in pins, 2", "push",); - - let mut cfg = Config::default(); - cfg.set_in_pins(&[&pin_a, &pin_b]); - cfg.fifo_join = FifoJoin::RxOnly; - cfg.shift_in.direction = ShiftDirection::Left; - cfg.clock_divider = 10_000.to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { sm } - } - - pub async fn read(&mut self) -> Direction { - loop { - match self.sm.rx().wait_pull().await { - 0 => return Direction::CounterClockwise, - 1 => return Direction::Clockwise, - _ => {} - } - } +#[embassy_executor::task] +async fn encoder_0(mut encoder: PioEncoder<'static, PIO0, 0>) { + let mut count = 0; + loop { + info!("Count: {}", count); + count += match encoder.read().await { + Direction::Clockwise => 1, + Direction::CounterClockwise => -1, + }; } } -pub enum Direction { - Clockwise, - CounterClockwise, -} - -#[embassy_executor::main] -async fn main(_spawner: Spawner) { - let p = embassy_rp::init(Default::default()); - let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - - let mut encoder = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5); - +#[embassy_executor::task] +async fn encoder_1(mut encoder: PioEncoder<'static, PIO0, 1>) { let mut count = 0; loop { info!("Count: {}", count); @@ -78,3 +40,18 @@ async fn main(_spawner: Spawner) { }; } } + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let Pio { + mut common, sm0, sm1, .. + } = Pio::new(p.PIO0, Irqs); + + let prg = PioEncoderProgram::new(&mut common); + let encoder0 = PioEncoder::new(&mut common, sm0, p.PIN_4, p.PIN_5, &prg); + let encoder1 = PioEncoder::new(&mut common, sm1, p.PIN_6, p.PIN_7, &prg); + + spawner.must_spawn(encoder_0(encoder0)); + spawner.must_spawn(encoder_1(encoder1)); +} diff --git a/examples/rp/src/bin/pio_servo.rs b/examples/rp/src/bin/pio_servo.rs index a79540479..c52ee7492 100644 --- a/examples/rp/src/bin/pio_servo.rs +++ b/examples/rp/src/bin/pio_servo.rs @@ -5,12 +5,11 @@ use core::time::Duration; use embassy_executor::Spawner; -use embassy_rp::gpio::Level; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Pio, PioPin, StateMachine}; -use embassy_rp::{bind_interrupts, clocks}; +use embassy_rp::pio::{Instance, InterruptHandler, Pio}; +use embassy_rp::pio_programs::pwm::{PioPwm, PioPwmProgram}; use embassy_time::Timer; -use pio::InstructionOperands; use {defmt_rtt as _, panic_probe as _}; const DEFAULT_MIN_PULSE_WIDTH: u64 = 1000; // uncalibrated default, the shortest duty cycle sent to a servo @@ -22,88 +21,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub fn to_pio_cycles(duration: Duration) -> u32 { - (clocks::clk_sys_freq() / 1_000_000) / 3 * duration.as_micros() as u32 // parentheses are required to prevent overflow -} - -pub struct PwmPio<'d, T: Instance, const SM: usize> { - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PwmPio<'d, T, SM> { - pub fn new(pio: &mut Common<'d, T>, mut sm: StateMachine<'d, T, SM>, pin: impl PioPin) -> Self { - let prg = pio_proc::pio_asm!( - ".side_set 1 opt" - "pull noblock side 0" - "mov x, osr" - "mov y, isr" - "countloop:" - "jmp x!=y noset" - "jmp skip side 1" - "noset:" - "nop" - "skip:" - "jmp y-- countloop" - ); - - pio.load_program(&prg.program); - let pin = pio.make_pio_pin(pin); - sm.set_pins(Level::High, &[&pin]); - sm.set_pin_dirs(Direction::Out, &[&pin]); - - let mut cfg = Config::default(); - cfg.use_program(&pio.load_program(&prg.program), &[&pin]); - - sm.set_config(&cfg); - - Self { sm } - } - - pub fn start(&mut self) { - self.sm.set_enable(true); - } - - pub fn stop(&mut self) { - self.sm.set_enable(false); - } - - pub fn set_period(&mut self, duration: Duration) { - let is_enabled = self.sm.is_enabled(); - while !self.sm.tx().empty() {} // Make sure that the queue is empty - self.sm.set_enable(false); - self.sm.tx().push(to_pio_cycles(duration)); - unsafe { - self.sm.exec_instr( - InstructionOperands::PULL { - if_empty: false, - block: false, - } - .encode(), - ); - self.sm.exec_instr( - InstructionOperands::OUT { - destination: ::pio::OutDestination::ISR, - bit_count: 32, - } - .encode(), - ); - }; - if is_enabled { - self.sm.set_enable(true) // Enable if previously enabled - } - } - - pub fn set_level(&mut self, level: u32) { - self.sm.tx().push(level); - } - - pub fn write(&mut self, duration: Duration) { - self.set_level(to_pio_cycles(duration)); - } -} - pub struct ServoBuilder<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, period: Duration, min_pulse_width: Duration, max_pulse_width: Duration, @@ -111,7 +30,7 @@ pub struct ServoBuilder<'d, T: Instance, const SM: usize> { } impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { - pub fn new(pwm: PwmPio<'d, T, SM>) -> Self { + pub fn new(pwm: PioPwm<'d, T, SM>) -> Self { Self { pwm, period: Duration::from_micros(REFRESH_INTERVAL), @@ -153,7 +72,7 @@ impl<'d, T: Instance, const SM: usize> ServoBuilder<'d, T, SM> { } pub struct Servo<'d, T: Instance, const SM: usize> { - pwm: PwmPio<'d, T, SM>, + pwm: PioPwm<'d, T, SM>, min_pulse_width: Duration, max_pulse_width: Duration, max_degree_rotation: u64, @@ -190,7 +109,8 @@ async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs); - let pwm_pio = PwmPio::new(&mut common, sm0, p.PIN_1); + let prg = PioPwmProgram::new(&mut common); + let pwm_pio = PioPwm::new(&mut common, sm0, p.PIN_1, &prg); let mut servo = ServoBuilder::new(pwm_pio) .set_max_degree_rotation(120) // Example of adjusting values for MG996R servo .set_min_pulse_width(Duration::from_micros(350)) // This value was detemined by a rough experiment. diff --git a/examples/rp/src/bin/pio_stepper.rs b/examples/rp/src/bin/pio_stepper.rs index 6ee45a414..3862c248b 100644 --- a/examples/rp/src/bin/pio_stepper.rs +++ b/examples/rp/src/bin/pio_stepper.rs @@ -3,143 +3,20 @@ #![no_std] #![no_main] -use core::mem::{self, MaybeUninit}; use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{Common, Config, Direction, Instance, InterruptHandler, Irq, Pio, PioPin, StateMachine}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::stepper::{PioStepper, PioStepperProgram}; use embassy_time::{with_timeout, Duration, Timer}; -use fixed::traits::ToFixed; -use fixed::types::extra::U8; -use fixed::FixedU32; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct PioStepper<'d, T: Instance, const SM: usize> { - irq: Irq<'d, T, SM>, - sm: StateMachine<'d, T, SM>, -} - -impl<'d, T: Instance, const SM: usize> PioStepper<'d, T, SM> { - pub fn new( - pio: &mut Common<'d, T>, - mut sm: StateMachine<'d, T, SM>, - irq: Irq<'d, T, SM>, - pin0: impl PioPin, - pin1: impl PioPin, - pin2: impl PioPin, - pin3: impl PioPin, - ) -> Self { - let prg = pio_proc::pio_asm!( - "pull block", - "mov x, osr", - "pull block", - "mov y, osr", - "jmp !x end", - "loop:", - "jmp !osre step", - "mov osr, y", - "step:", - "out pins, 4 [31]" - "jmp x-- loop", - "end:", - "irq 0 rel" - ); - let pin0 = pio.make_pio_pin(pin0); - let pin1 = pio.make_pio_pin(pin1); - let pin2 = pio.make_pio_pin(pin2); - let pin3 = pio.make_pio_pin(pin3); - sm.set_pin_dirs(Direction::Out, &[&pin0, &pin1, &pin2, &pin3]); - let mut cfg = Config::default(); - cfg.set_out_pins(&[&pin0, &pin1, &pin2, &pin3]); - cfg.clock_divider = (125_000_000 / (100 * 136)).to_fixed(); - cfg.use_program(&pio.load_program(&prg.program), &[]); - sm.set_config(&cfg); - sm.set_enable(true); - Self { irq, sm } - } - - // Set pulse frequency - pub fn set_frequency(&mut self, freq: u32) { - let clock_divider: FixedU32 = (125_000_000 / (freq * 136)).to_fixed(); - assert!(clock_divider <= 65536, "clkdiv must be <= 65536"); - assert!(clock_divider >= 1, "clkdiv must be >= 1"); - self.sm.set_clock_divider(clock_divider); - self.sm.clkdiv_restart(); - } - - // Full step, one phase - pub async fn step(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1000_0100_0010_0001_1000_0100_0010_0001).await - } else { - self.run(-steps, 0b0001_0010_0100_1000_0001_0010_0100_1000).await - } - } - - // Full step, two phase - pub async fn step2(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1100_0110_0011_1001_1100_0110_0011).await - } else { - self.run(-steps, 0b0011_0110_1100_1001_0011_0110_1100_1001).await - } - } - - // Half step - pub async fn step_half(&mut self, steps: i32) { - if steps > 0 { - self.run(steps, 0b1001_1000_1100_0100_0110_0010_0011_0001).await - } else { - self.run(-steps, 0b0001_0011_0010_0110_0100_1100_1000_1001).await - } - } - - async fn run(&mut self, steps: i32, pattern: u32) { - self.sm.tx().wait_push(steps as u32).await; - self.sm.tx().wait_push(pattern).await; - let drop = OnDrop::new(|| { - self.sm.clear_fifos(); - unsafe { - self.sm.exec_instr( - pio::InstructionOperands::JMP { - address: 0, - condition: pio::JmpCondition::Always, - } - .encode(), - ); - } - }); - self.irq.wait().await; - drop.defuse(); - } -} - -struct OnDrop { - f: MaybeUninit, -} - -impl OnDrop { - pub fn new(f: F) -> Self { - Self { f: MaybeUninit::new(f) } - } - - pub fn defuse(self) { - mem::forget(self) - } -} - -impl Drop for OnDrop { - fn drop(&mut self) { - unsafe { self.f.as_ptr().read()() } - } -} - #[embassy_executor::main] async fn main(_spawner: Spawner) { let p = embassy_rp::init(Default::default()); @@ -147,14 +24,18 @@ async fn main(_spawner: Spawner) { mut common, irq0, sm0, .. } = Pio::new(p.PIO0, Irqs); - let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7); + let prg = PioStepperProgram::new(&mut common); + let mut stepper = PioStepper::new(&mut common, sm0, irq0, p.PIN_4, p.PIN_5, p.PIN_6, p.PIN_7, &prg); stepper.set_frequency(120); loop { info!("CW full steps"); stepper.step(1000).await; info!("CCW full steps, drop after 1 sec"); - if let Err(_) = with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)).await { + if with_timeout(Duration::from_secs(1), stepper.step(-i32::MAX)) + .await + .is_err() + { info!("Time's up!"); Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index 53b696309..b9e01b0ac 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -15,7 +15,8 @@ use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio::InterruptHandler as PioInterruptHandler; +use embassy_rp::pio; +use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; @@ -25,13 +26,11 @@ use embassy_usb::{Builder, Config}; use embedded_io_async::{Read, Write}; use {defmt_rtt as _, panic_probe as _}; -use crate::uart::PioUart; -use crate::uart_rx::PioUartRx; -use crate::uart_tx::PioUartTx; +//use crate::uart::PioUart; bind_interrupts!(struct Irqs { USBCTRL_IRQ => InterruptHandler; - PIO0_IRQ_0 => PioInterruptHandler; + PIO0_IRQ_0 => pio::InterruptHandler; }); #[embassy_executor::main] @@ -85,8 +84,15 @@ async fn main(_spawner: Spawner) { let usb_fut = usb.run(); // PIO UART setup - let uart = PioUart::new(9600, p.PIO0, p.PIN_4, p.PIN_5); - let (mut uart_tx, mut uart_rx) = uart.split(); + let pio::Pio { + mut common, sm0, sm1, .. + } = pio::Pio::new(p.PIO0, Irqs); + + let tx_program = PioUartTxProgram::new(&mut common); + let mut uart_tx = PioUartTx::new(9600, &mut common, sm0, p.PIN_4, &tx_program); + + let rx_program = PioUartRxProgram::new(&mut common); + let mut uart_rx = PioUartRx::new(9600, &mut common, sm1, p.PIN_5, &rx_program); // Pipe setup let mut usb_pipe: Pipe = Pipe::new(); @@ -163,8 +169,8 @@ async fn usb_write<'d, T: Instance + 'd>( } /// Read from the UART and write it to the USB TX pipe -async fn uart_read( - uart_rx: &mut PioUartRx<'_>, +async fn uart_read( + uart_rx: &mut PioUartRx<'_, PIO, SM>, usb_pipe_writer: &mut embassy_sync::pipe::Writer<'_, NoopRawMutex, 20>, ) -> ! { let mut buf = [0; 64]; @@ -180,8 +186,8 @@ async fn uart_read( } /// Read from the UART TX pipe and write it to the UART -async fn uart_write( - uart_tx: &mut PioUartTx<'_>, +async fn uart_write( + uart_tx: &mut PioUartTx<'_, PIO, SM>, uart_pipe_reader: &mut embassy_sync::pipe::Reader<'_, NoopRawMutex, 20>, ) -> ! { let mut buf = [0; 64]; @@ -192,197 +198,3 @@ async fn uart_write( let _ = uart_tx.write(&data).await; } } - -mod uart { - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Pio, PioPin}; - use embassy_rp::Peripheral; - - use crate::uart_rx::PioUartRx; - use crate::uart_tx::PioUartTx; - use crate::Irqs; - - pub struct PioUart<'a> { - tx: PioUartTx<'a>, - rx: PioUartRx<'a>, - } - - impl<'a> PioUart<'a> { - pub fn new( - baud: u64, - pio: impl Peripheral

+ 'a, - tx_pin: impl PioPin, - rx_pin: impl PioPin, - ) -> PioUart<'a> { - let Pio { - mut common, sm0, sm1, .. - } = Pio::new(pio, Irqs); - - let tx = PioUartTx::new(&mut common, sm0, tx_pin, baud); - let rx = PioUartRx::new(&mut common, sm1, rx_pin, baud); - - PioUart { tx, rx } - } - - pub fn split(self) -> (PioUartTx<'a>, PioUartRx<'a>) { - (self.tx, self.rx) - } - } -} - -mod uart_tx { - use core::convert::Infallible; - - use embassy_rp::gpio::Level; - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; - use embedded_io_async::{ErrorType, Write}; - use fixed::traits::ToFixed; - use fixed_macro::types::U56F8; - - pub struct PioUartTx<'a> { - sm_tx: StateMachine<'a, PIO0, 0>, - } - - impl<'a> PioUartTx<'a> { - pub fn new( - common: &mut Common<'a, PIO0>, - mut sm_tx: StateMachine<'a, PIO0, 0>, - tx_pin: impl PioPin, - baud: u64, - ) -> Self { - let prg = pio_proc::pio_asm!( - r#" - .side_set 1 opt - - ; An 8n1 UART transmit program. - ; OUT pin 0 and side-set pin 0 are both mapped to UART TX pin. - - pull side 1 [7] ; Assert stop bit, or stall with line in idle state - set x, 7 side 0 [7] ; Preload bit counter, assert start bit for 8 clocks - bitloop: ; This loop will run 8 times (8n1 UART) - out pins, 1 ; Shift 1 bit from OSR to the first OUT pin - jmp x-- bitloop [6] ; Each loop iteration is 8 cycles. - "# - ); - let tx_pin = common.make_pio_pin(tx_pin); - sm_tx.set_pins(Level::High, &[&tx_pin]); - sm_tx.set_pin_dirs(Direction::Out, &[&tx_pin]); - - let mut cfg = Config::default(); - - cfg.set_out_pins(&[&tx_pin]); - cfg.use_program(&common.load_program(&prg.program), &[&tx_pin]); - cfg.shift_out.auto_fill = false; - cfg.shift_out.direction = ShiftDirection::Right; - cfg.fifo_join = FifoJoin::TxOnly; - cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed(); - sm_tx.set_config(&cfg); - sm_tx.set_enable(true); - - Self { sm_tx } - } - - pub async fn write_u8(&mut self, data: u8) { - self.sm_tx.tx().wait_push(data as u32).await; - } - } - - impl ErrorType for PioUartTx<'_> { - type Error = Infallible; - } - - impl Write for PioUartTx<'_> { - async fn write(&mut self, buf: &[u8]) -> Result { - for byte in buf { - self.write_u8(*byte).await; - } - Ok(buf.len()) - } - } -} - -mod uart_rx { - use core::convert::Infallible; - - use embassy_rp::gpio::Level; - use embassy_rp::peripherals::PIO0; - use embassy_rp::pio::{Common, Config, Direction, FifoJoin, PioPin, ShiftDirection, StateMachine}; - use embedded_io_async::{ErrorType, Read}; - use fixed::traits::ToFixed; - use fixed_macro::types::U56F8; - - pub struct PioUartRx<'a> { - sm_rx: StateMachine<'a, PIO0, 1>, - } - - impl<'a> PioUartRx<'a> { - pub fn new( - common: &mut Common<'a, PIO0>, - mut sm_rx: StateMachine<'a, PIO0, 1>, - rx_pin: impl PioPin, - baud: u64, - ) -> Self { - let prg = pio_proc::pio_asm!( - r#" - ; Slightly more fleshed-out 8n1 UART receiver which handles framing errors and - ; break conditions more gracefully. - ; IN pin 0 and JMP pin are both mapped to the GPIO used as UART RX. - - start: - wait 0 pin 0 ; Stall until start bit is asserted - set x, 7 [10] ; Preload bit counter, then delay until halfway through - rx_bitloop: ; the first data bit (12 cycles incl wait, set). - in pins, 1 ; Shift data bit into ISR - jmp x-- rx_bitloop [6] ; Loop 8 times, each loop iteration is 8 cycles - jmp pin good_rx_stop ; Check stop bit (should be high) - - irq 4 rel ; Either a framing error or a break. Set a sticky flag, - wait 1 pin 0 ; and wait for line to return to idle state. - jmp start ; Don't push data if we didn't see good framing. - - good_rx_stop: ; No delay before returning to start; a little slack is - in null 24 - push ; important in case the TX clock is slightly too fast. - "# - ); - let mut cfg = Config::default(); - cfg.use_program(&common.load_program(&prg.program), &[]); - - let rx_pin = common.make_pio_pin(rx_pin); - sm_rx.set_pins(Level::High, &[&rx_pin]); - cfg.set_in_pins(&[&rx_pin]); - cfg.set_jmp_pin(&rx_pin); - sm_rx.set_pin_dirs(Direction::In, &[&rx_pin]); - - cfg.clock_divider = (U56F8!(125_000_000) / (8 * baud)).to_fixed(); - cfg.shift_in.auto_fill = false; - cfg.shift_in.direction = ShiftDirection::Right; - cfg.shift_in.threshold = 32; - cfg.fifo_join = FifoJoin::RxOnly; - sm_rx.set_config(&cfg); - sm_rx.set_enable(true); - - Self { sm_rx } - } - - pub async fn read_u8(&mut self) -> u8 { - self.sm_rx.rx().wait_pull().await as u8 - } - } - - impl ErrorType for PioUartRx<'_> { - type Error = Infallible; - } - - impl Read for PioUartRx<'_> { - async fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - while i < buf.len() { - buf[i] = self.read_u8().await; - i += 1; - } - Ok(i) - } - } -} diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs index ac145933c..d1fcfc471 100644 --- a/examples/rp/src/bin/pio_ws2812.rs +++ b/examples/rp/src/bin/pio_ws2812.rs @@ -6,15 +6,11 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::dma::{AnyChannel, Channel}; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{ - Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine, -}; -use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef}; -use embassy_time::{Duration, Ticker, Timer}; -use fixed::types::U24F8; -use fixed_macro::fixed; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::ws2812::{PioWs2812, PioWs2812Program}; +use embassy_time::{Duration, Ticker}; use smart_leds::RGB8; use {defmt_rtt as _, panic_probe as _}; @@ -22,96 +18,6 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> { - dma: PeripheralRef<'d, AnyChannel>, - sm: StateMachine<'d, P, S>, -} - -impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> { - pub fn new( - pio: &mut Common<'d, P>, - mut sm: StateMachine<'d, P, S>, - dma: impl Peripheral

+ 'd, - pin: impl PioPin, - ) -> Self { - into_ref!(dma); - - // Setup sm0 - - // prepare the PIO program - let side_set = pio::SideSet::new(false, 1, false); - let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set); - - const T1: u8 = 2; // start bit - const T2: u8 = 5; // data bit - const T3: u8 = 3; // stop bit - const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32; - - let mut wrap_target = a.label(); - let mut wrap_source = a.label(); - let mut do_zero = a.label(); - a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0); - a.bind(&mut wrap_target); - // Do stop bit - a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0); - // Do start bit - a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1); - // Do data bit = 1 - a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1); - a.bind(&mut do_zero); - // Do data bit = 0 - a.nop_with_delay_and_side_set(T2 - 1, 0); - a.bind(&mut wrap_source); - - let prg = a.assemble_with_wrap(wrap_source, wrap_target); - let mut cfg = Config::default(); - - // Pin config - let out_pin = pio.make_pio_pin(pin); - cfg.set_out_pins(&[&out_pin]); - cfg.set_set_pins(&[&out_pin]); - - cfg.use_program(&pio.load_program(&prg), &[&out_pin]); - - // Clock config, measured in kHz to avoid overflows - // TODO CLOCK_FREQ should come from embassy_rp - let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000); - let ws2812_freq = fixed!(800: U24F8); - let bit_freq = ws2812_freq * CYCLES_PER_BIT; - cfg.clock_divider = clock_freq / bit_freq; - - // FIFO config - cfg.fifo_join = FifoJoin::TxOnly; - cfg.shift_out = ShiftConfig { - auto_fill: true, - threshold: 24, - direction: ShiftDirection::Left, - }; - - sm.set_config(&cfg); - sm.set_enable(true); - - Self { - dma: dma.map_into(), - sm, - } - } - - pub async fn write(&mut self, colors: &[RGB8; N]) { - // Precompute the word bytes from the colors - let mut words = [0u32; N]; - for i in 0..N { - let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8); - words[i] = word; - } - - // DMA transfer - self.sm.tx().dma_push(self.dma.reborrow(), &words).await; - - Timer::after_micros(55).await; - } -} - /// Input a value 0 to 255 to get a color value /// The colours are a transition r - g - b - back to r. fn wheel(mut wheel_pos: u8) -> RGB8 { @@ -142,7 +48,8 @@ async fn main(_spawner: Spawner) { // Common neopixel pins: // Thing plus: 8 // Adafruit Feather: 16; Adafruit Feather+RFM95: 4 - let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16); + let program = PioWs2812Program::new(&mut common); + let mut ws2812 = PioWs2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16, &program); // Loop forever making RGB values and pushing them out to the WS2812. let mut ticker = Ticker::every(Duration::from_millis(10)); -- cgit From e47c031b671555f3fffe6b128cbb9d3f8bfec534 Mon Sep 17 00:00:00 2001 From: Caleb Jamison Date: Wed, 9 Oct 2024 11:47:04 -0400 Subject: fmt examples too --- examples/rp/src/bin/pio_rotary_encoder.rs | 8 +++----- examples/rp/src/bin/pio_uart.rs | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_rotary_encoder.rs b/examples/rp/src/bin/pio_rotary_encoder.rs index a7ecc8d0e..2750f61ae 100644 --- a/examples/rp/src/bin/pio_rotary_encoder.rs +++ b/examples/rp/src/bin/pio_rotary_encoder.rs @@ -5,12 +5,10 @@ use defmt::info; use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::{ - bind_interrupts, - pio::{InterruptHandler, Pio}, - pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}, -}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::rotary_encoder::{Direction, PioEncoder, PioEncoderProgram}; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index b9e01b0ac..aaf2a524f 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -13,11 +13,10 @@ use defmt::{info, panic, trace}; use embassy_executor::Spawner; use embassy_futures::join::{join, join3}; -use embassy_rp::bind_interrupts; use embassy_rp::peripherals::{PIO0, USB}; -use embassy_rp::pio; use embassy_rp::pio_programs::uart::{PioUartRx, PioUartRxProgram, PioUartTx, PioUartTxProgram}; use embassy_rp::usb::{Driver, Instance, InterruptHandler}; +use embassy_rp::{bind_interrupts, pio}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::pipe::Pipe; use embassy_usb::class::cdc_acm::{CdcAcmClass, Receiver, Sender, State}; -- cgit From 8dfc9ba1a3e3f69aedf5bce748783fb6a8f5e92e Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 21:14:49 +0200 Subject: also add to the rp pwm example --- examples/rp/src/bin/pwm.rs | 52 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 6 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 26e233260..862a7da22 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -1,24 +1,36 @@ //! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip. //! -//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin. +//! We demonstrate two ways of using PWM: +//! 1. Via config +//! 2. Via setting a duty cycle #![no_std] #![no_main] use defmt::*; use embassy_executor::Spawner; -use embassy_rp::pwm::{Config, Pwm}; +use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] -async fn main(_spawner: Spawner) { +async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); + spawner.spawn(pwm_set_config(p.PWM_SLICE4, p.PIN_25)).unwrap(); + spawner.spawn(pwm_set_dutycycle(p.PWM_SLICE2, p.PIN_4)).unwrap(); +} - let mut c: Config = Default::default(); - c.top = 0x8000; +/// Demonstrate PWM by modifying & applying the config +/// +/// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant) +/// you must use another slice & pin and an appropriate resistor. +#[embassy_executor::task] +async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { + let mut c = Config::default(); + c.top = 32_768; c.compare_b = 8; - let mut pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, c.clone()); + let mut pwm = Pwm::new_output_b(slice4, pin25, c.clone()); loop { info!("current LED duty cycle: {}/32768", c.compare_b); @@ -27,3 +39,31 @@ async fn main(_spawner: Spawner) { pwm.set_config(&c); } } + +/// Demonstrate PWM by setting duty cycle +/// +/// Using GP4 in Slice2, make sure to use an appropriate resistor. +#[embassy_executor::task] +async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { + let mut c = Config::default(); + c.top = 32_768; + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); + + loop { + // 100% duty cycle, fully on + pwm.set_duty_cycle_fully_on().unwrap(); + Timer::after_secs(1).await; + + // 66% duty cycle. Expressed as simple percentage. + pwm.set_duty_cycle_percent(66).unwrap(); + Timer::after_secs(1).await; + + // 25% duty cycle. Expressed as 32768/4 = 8192. + pwm.set_duty_cycle(8_192).unwrap(); + Timer::after_secs(1).await; + + // 0% duty cycle, fully off. + pwm.set_duty_cycle_fully_off().unwrap(); + Timer::after_secs(1).await; + } +} -- cgit From 14e69309ebe25a76f67c38411c7a80a4d83da5ed Mon Sep 17 00:00:00 2001 From: rafael Date: Mon, 21 Oct 2024 22:42:18 +0200 Subject: add pwm frequency to examples --- examples/rp/src/bin/pwm.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 862a7da22..791b88b5b 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -45,8 +45,14 @@ async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { /// Using GP4 in Slice2, make sure to use an appropriate resistor. #[embassy_executor::task] async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { + // If we aim for a specific frequency, here is how we can calculate the top value. + // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. + // Every such wraparound is one PWM cycle. So here is how we get 25KHz: let mut c = Config::default(); - c.top = 32_768; + let pwm_freq = 25_000; // Hz, our desired frequency + let clock_freq = embassy_rp::clocks::clk_sys_freq(); + c.top = (clock_freq / pwm_freq) as u16 - 1; + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { @@ -59,7 +65,7 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { Timer::after_secs(1).await; // 25% duty cycle. Expressed as 32768/4 = 8192. - pwm.set_duty_cycle(8_192).unwrap(); + pwm.set_duty_cycle(c.top / 4).unwrap(); Timer::after_secs(1).await; // 0% duty cycle, fully off. -- cgit From 66822f1000f542cac767be77345cb527956ada04 Mon Sep 17 00:00:00 2001 From: Brad Gibson Date: Tue, 22 Oct 2024 05:29:11 -0700 Subject: update path to cyw43 firmware in `wifi_blinky.rs` comments --- examples/rp/src/bin/wifi_blinky.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 04a61bbd5..0107a2326 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -33,8 +33,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs download 43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 - // probe-rs download 43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download ../../cyw43-firmware/43439A0.bin --binary-format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download ../../cyw43-firmware/43439A0_clm.bin --binary-format bin --chip RP2040 --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 230321) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; -- cgit From 66205fdd859b4c8607d0b6be9e4fcb27e8096493 Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Sun, 27 Oct 2024 09:50:57 +0100 Subject: update spi_display example for rp --- examples/rp/src/bin/spi_display.rs | 165 ++++--------------------------------- 1 file changed, 15 insertions(+), 150 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs index e937b9d0a..dd114a4ae 100644 --- a/examples/rp/src/bin/spi_display.rs +++ b/examples/rp/src/bin/spi_display.rs @@ -9,11 +9,12 @@ use core::cell::RefCell; use defmt::*; +use display_interface_spi::SPIInterface; use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::spi; -use embassy_rp::spi::{Blocking, Spi}; +use embassy_rp::spi::Spi; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::Mutex; use embassy_time::Delay; @@ -24,10 +25,11 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use embedded_graphics::text::Text; -use st7789::{Orientation, ST7789}; +use mipidsi::models::ST7789; +use mipidsi::options::{Orientation, Rotation}; +use mipidsi::Builder; use {defmt_rtt as _, panic_probe as _}; -use crate::my_display_interface::SPIDeviceInterface; use crate::touch::Touch; const DISPLAY_FREQ: u32 = 64_000_000; @@ -58,7 +60,7 @@ async fn main(_spawner: Spawner) { touch_config.phase = spi::Phase::CaptureOnSecondTransition; touch_config.polarity = spi::Polarity::IdleHigh; - let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); + let spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone()); let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); @@ -74,17 +76,15 @@ async fn main(_spawner: Spawner) { let _bl = Output::new(bl, Level::High); // display interface abstraction from SPI and DC - let di = SPIDeviceInterface::new(display_spi, dcx); - - // create driver - let mut display = ST7789::new(di, rst, 240, 320); - - // initialize - display.init(&mut Delay).unwrap(); - - // set default orientation - display.set_orientation(Orientation::Landscape).unwrap(); - + let di = SPIInterface::new(display_spi, dcx); + + // Define the display from the display interface and initialize it + let mut display = Builder::new(ST7789, di) + .display_size(240, 320) + .reset_pin(rst) + .orientation(Orientation::new().rotate(Rotation::Deg90)) + .init(&mut Delay) + .unwrap(); display.clear(Rgb565::BLACK).unwrap(); let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), 86); @@ -175,138 +175,3 @@ mod touch { } } } - -mod my_display_interface { - use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; - use embedded_hal_1::digital::OutputPin; - use embedded_hal_1::spi::SpiDevice; - - /// SPI display interface. - /// - /// This combines the SPI peripheral and a data/command pin - pub struct SPIDeviceInterface { - spi: SPI, - dc: DC, - } - - impl SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - /// Create new SPI interface for communciation with a display driver - pub fn new(spi: SPI, dc: DC) -> Self { - Self { spi, dc } - } - } - - impl WriteOnlyDataCommand for SPIDeviceInterface - where - SPI: SpiDevice, - DC: OutputPin, - { - fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_low().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - - fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { - // 1 = data, 0 = command - self.dc.set_high().map_err(|_| DisplayError::DCError)?; - - send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?; - Ok(()) - } - } - - fn send_u8(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { - match words { - DataFormat::U8(slice) => spi.write(slice), - DataFormat::U16(slice) => { - use byte_slice_cast::*; - spi.write(slice.as_byte_slice()) - } - DataFormat::U16LE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_le(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U16BE(slice) => { - use byte_slice_cast::*; - for v in slice.as_mut() { - *v = v.to_be(); - } - spi.write(slice.as_byte_slice()) - } - DataFormat::U8Iter(iter) => { - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.into_iter() { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf)?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i])?; - } - - Ok(()) - } - DataFormat::U16LEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 32]; - let mut i = 0; - - for v in iter.map(u16::to_le) { - buf[i] = v; - i += 1; - - if i == buf.len() { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - DataFormat::U16BEIter(iter) => { - use byte_slice_cast::*; - let mut buf = [0; 64]; - let mut i = 0; - let len = buf.len(); - - for v in iter.map(u16::to_be) { - buf[i] = v; - i += 1; - - if i == len { - spi.write(&buf.as_byte_slice())?; - i = 0; - } - } - - if i > 0 { - spi.write(&buf[..i].as_byte_slice())?; - } - - Ok(()) - } - _ => unimplemented!(), - } - } -} -- cgit From 333d8584812c0ea3e1f9262922befbd3fe709775 Mon Sep 17 00:00:00 2001 From: Bjorn <75190918+BjornTheProgrammer@users.noreply.github.com> Date: Thu, 31 Oct 2024 22:51:03 -0700 Subject: Added ReceiverHandler to logger --- examples/rp/src/bin/usb_serial_with_handler.rs | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 examples/rp/src/bin/usb_serial_with_handler.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/usb_serial_with_handler.rs b/examples/rp/src/bin/usb_serial_with_handler.rs new file mode 100644 index 000000000..a9e65be70 --- /dev/null +++ b/examples/rp/src/bin/usb_serial_with_handler.rs @@ -0,0 +1,64 @@ +//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip. +//! +//! This creates the possibility to send log::info/warn/error/debug! to USB serial port. + +#![no_std] +#![no_main] + +use core::str; + +use embassy_executor::Spawner; +use embassy_rp::bind_interrupts; +use embassy_rp::peripherals::USB; +use embassy_rp::rom_data::reset_to_usb_boot; +use embassy_rp::usb::{Driver, InterruptHandler}; +use embassy_time::Timer; +use embassy_usb_logger::ReceiverHandler; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + USBCTRL_IRQ => InterruptHandler; +}); + +struct Handler; + +impl ReceiverHandler for Handler { + async fn handle_data(&self, data: &[u8]) { + if let Ok(data) = str::from_utf8(data) { + let data = data.trim(); + + // If you are using elf2uf2-term with the '-t' flag, then when closing the serial monitor, + // this will automatically put the pico into boot mode + if data == "q" || data == "elf2uf2-term" { + reset_to_usb_boot(0, 0); // Restart the chip + } else if data.eq_ignore_ascii_case("hello") { + log::info!("World!"); + } else { + log::info!("Recieved: {:?}", data); + } + } + } + + fn new() -> Self { + Self + } +} + +#[embassy_executor::task] +async fn logger_task(driver: Driver<'static, USB>) { + embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver, Handler); +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let driver = Driver::new(p.USB, Irqs); + spawner.spawn(logger_task(driver)).unwrap(); + + let mut counter = 0; + loop { + counter += 1; + log::info!("Tick {}", counter); + Timer::after_secs(1).await; + } +} -- cgit From fb004fb6e2bd1fe23c50bf0faccd9d4a8061e986 Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Sun, 27 Oct 2024 10:23:18 +0100 Subject: add second example fo SPI display on RP --- examples/rp/src/bin/spi_gc9a01.rs | 126 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 examples/rp/src/bin/spi_gc9a01.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs new file mode 100644 index 000000000..d1cf23e16 --- /dev/null +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -0,0 +1,126 @@ +//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip. +//! +//! Example written for a display using the GC9A01 chip. Possibly the Waveshare RP2040-LCD-1.28 +//! (https://www.waveshare.com/wiki/RP2040-LCD-1.28) + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use defmt::*; +use display_interface_spi::SPIInterface; +use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig; +use embassy_executor::Spawner; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Level, Output}; +use embassy_rp::spi; +use embassy_rp::spi::{Blocking, Spi}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::blocking_mutex::Mutex; +use embassy_time::{Delay, Duration, Timer}; +use embedded_graphics::image::{Image, ImageRawLE}; +use embedded_graphics::pixelcolor::Rgb565; +use embedded_graphics::prelude::*; +use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; +use mipidsi::models::GC9A01; +use mipidsi::options::{ColorOrder, ColorInversion}; +use mipidsi::Builder; +use rand_core::RngCore; +use {defmt_rtt as _, panic_probe as _}; + +const DISPLAY_FREQ: u32 = 64_000_000; +const LCD_X_RES: i32 = 240; +const LCD_Y_RES: i32 = 240; +const FERRIS_WIDTH: u32 = 86; +const FERRIS_HEIGHT: u32 = 64; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rng = RoscRng; + + info!("Hello World!"); + + let bl = p.PIN_25; + let rst = p.PIN_12; + let display_cs = p.PIN_9; + let dcx = p.PIN_8; + let mosi = p.PIN_11; + let clk = p.PIN_10; + + // create SPI + let mut display_config = spi::Config::default(); + display_config.frequency = DISPLAY_FREQ; + display_config.phase = spi::Phase::CaptureOnSecondTransition; + display_config.polarity = spi::Polarity::IdleHigh; + + let spi: Spi<'_, _, Blocking> = Spi::new_blocking_txonly(p.SPI1, clk, mosi, display_config.clone()); + let spi_bus: Mutex = Mutex::new(RefCell::new(spi)); + + let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config); + let dcx = Output::new(dcx, Level::Low); + let rst = Output::new(rst, Level::Low); + // dcx: 0 = command, 1 = data + + // Enable LCD backlight + let _bl = Output::new(bl, Level::High); + + // display interface abstraction from SPI and DC + let di = SPIInterface::new(display_spi, dcx); + + // Define the display from the display interface and initialize it + let mut display = Builder::new(GC9A01, di) + .display_size(240, 240) + .reset_pin(rst) + .color_order(ColorOrder::Bgr) + .invert_colors(ColorInversion::Inverted) + .init(&mut Delay) + .unwrap(); + display.clear(Rgb565::BLACK).unwrap(); + + let raw_image_data = ImageRawLE::new(include_bytes!("../../assets/ferris.raw"), FERRIS_WIDTH); + let mut ferris = Image::new(&raw_image_data, Point::zero()); + + let r = rng.next_u32(); + let mut delta = Point { + x: ((r % 10) + 5) as i32, + y: (((r >> 8) % 10) + 5) as i32, + }; + loop { + // Move Ferris + let bb = ferris.bounding_box(); + let tl = bb.top_left; + let br = bb.bottom_right().unwrap(); + if tl.x < 0 || br.x > LCD_X_RES { + delta.x = -delta.x; + } + if tl.y < 0 || br.y > LCD_Y_RES { + delta.y = -delta.y; + } + + // Erase ghosting + let style = PrimitiveStyleBuilder::new().fill_color(Rgb565::BLACK).build(); + let mut off = Point { x: 0, y: 0 }; + if delta.x < 0 { + off.x = FERRIS_WIDTH as i32; + } + Rectangle::new(tl + off, Size::new(delta.x as u32, FERRIS_HEIGHT)) + .into_styled(style) + .draw(&mut display) + .unwrap(); + off = Point { x: 0, y: 0 }; + if delta.y < 0 { + off.y = FERRIS_HEIGHT as i32; + } + Rectangle::new(tl + off, Size::new(FERRIS_WIDTH, delta.y as u32)) + .into_styled(style) + .draw(&mut display) + .unwrap(); + // Translate Ferris + ferris.translate_mut(delta); + // Display the image + ferris.draw(&mut display).unwrap(); + Timer::after(Duration::from_millis(50)).await; + } +} -- cgit From 9d21e3a1ae2bc22b5577032423aa3dac1ee09a3a Mon Sep 17 00:00:00 2001 From: Georges Palauqui Date: Tue, 5 Nov 2024 19:40:49 +0100 Subject: fix fmt --- examples/rp/src/bin/spi_gc9a01.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs index d1cf23e16..30afc253d 100644 --- a/examples/rp/src/bin/spi_gc9a01.rs +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -24,7 +24,7 @@ use embedded_graphics::pixelcolor::Rgb565; use embedded_graphics::prelude::*; use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use mipidsi::models::GC9A01; -use mipidsi::options::{ColorOrder, ColorInversion}; +use mipidsi::options::{ColorInversion, ColorOrder}; use mipidsi::Builder; use rand_core::RngCore; use {defmt_rtt as _, panic_probe as _}; -- cgit From 75382336164c8284196eb1fad057050ba735a72d Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 9 Nov 2024 17:19:06 +0100 Subject: correct rp pwm dutycycle examples: desired frequency --- examples/rp/src/bin/pwm.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 791b88b5b..06b9313f2 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -48,11 +48,15 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: + let desired_freq_hz = 25_000; + let clock_freq_hz = embassy_rp::clocks::clk_sys_freq(); + let divider = 16u8; + let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1; + let mut c = Config::default(); - let pwm_freq = 25_000; // Hz, our desired frequency - let clock_freq = embassy_rp::clocks::clk_sys_freq(); - c.top = (clock_freq / pwm_freq) as u16 - 1; - + c.top = period; + c.divider = divider.into(); + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { -- cgit From ccf2e0c528a85518e9d64456d9dfde9e951ef613 Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 9 Nov 2024 17:37:24 +0100 Subject: formatting --- examples/rp/src/bin/pwm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 06b9313f2..cf6531994 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -48,15 +48,15 @@ async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: - let desired_freq_hz = 25_000; + let desired_freq_hz = 25_000; let clock_freq_hz = embassy_rp::clocks::clk_sys_freq(); let divider = 16u8; let period = (clock_freq_hz / (desired_freq_hz * divider as u32)) as u16 - 1; - + let mut c = Config::default(); c.top = period; c.divider = divider.into(); - + let mut pwm = Pwm::new_output_a(slice2, pin4, c.clone()); loop { -- cgit From ed10b9de7b0292a23036d3144146cff8137caf4f Mon Sep 17 00:00:00 2001 From: rafael Date: Sat, 9 Nov 2024 17:39:21 +0100 Subject: formatting --- examples/rp/src/bin/pwm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index cf6531994..2f5f94870 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -9,7 +9,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::peripherals::{PIN_4, PIN_25, PWM_SLICE2, PWM_SLICE4}; +use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -- cgit From 0138bc5dd8d0c49c86b01668b0af8a2e8dca699c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 3 Dec 2024 00:31:36 +0100 Subject: examples/rp: update sdmmc. --- examples/rp/src/bin/spi_sdmmc.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs index 4cbc82f7b..a60850d0f 100644 --- a/examples/rp/src/bin/spi_sdmmc.rs +++ b/examples/rp/src/bin/spi_sdmmc.rs @@ -7,7 +7,6 @@ #![no_main] use defmt::*; -use embassy_embedded_hal::SetConfig; use embassy_executor::Spawner; use embassy_rp::spi::Spi; use embassy_rp::{gpio, spi}; @@ -51,7 +50,7 @@ async fn main(_spawner: Spawner) { // Now that the card is initialized, the SPI clock can go faster let mut config = spi::Config::default(); config.frequency = 16_000_000; - sdcard.spi(|dev| dev.bus_mut().set_config(&config)).ok(); + sdcard.spi(|dev| dev.bus_mut().set_config(&config)); // Now let's look for volumes (also known as partitions) on our block device. // To do this we need a Volume Manager. It will take ownership of the block device. -- cgit From 52ac74982d412a80409858e9b10479812d71cb82 Mon Sep 17 00:00:00 2001 From: Michael de Silva Date: Thu, 30 May 2024 23:41:07 +0530 Subject: Remove code that isn't used by the example --- examples/rp/src/bin/wifi_scan.rs | 5 ----- 1 file changed, 5 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 434f0074c..2ef899080 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -26,11 +26,6 @@ async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'stat runner.run().await } -#[embassy_executor::task] -async fn net_task(mut runner: embassy_net::Runner<'static, cyw43::NetDriver<'static>>) -> ! { - runner.run().await -} - #[embassy_executor::main] async fn main(spawner: Spawner) { info!("Hello World!"); -- cgit From 1c485f18a2ee6147bf4cfd66789dc8e0c6e1466c Mon Sep 17 00:00:00 2001 From: Dániel Buga Date: Wed, 18 Dec 2024 16:09:57 +0100 Subject: Remove bluetooth example and trouble dependencies --- examples/rp/src/bin/bluetooth.rs | 150 --------------------------------------- 1 file changed, 150 deletions(-) delete mode 100644 examples/rp/src/bin/bluetooth.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs deleted file mode 100644 index 7524e7929..000000000 --- a/examples/rp/src/bin/bluetooth.rs +++ /dev/null @@ -1,150 +0,0 @@ -//! This example test the RP Pico W on board LED. -//! -//! It does not work with the RP Pico board. See blinky.rs. - -#![no_std] -#![no_main] - -use bt_hci::controller::ExternalController; -use cyw43_pio::PioSpi; -use defmt::*; -use embassy_executor::Spawner; -use embassy_futures::join::join3; -use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{Level, Output}; -use embassy_rp::peripherals::{DMA_CH0, PIO0}; -use embassy_rp::pio::{InterruptHandler, Pio}; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use embassy_time::{Duration, Timer}; -use static_cell::StaticCell; -use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE}; -use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid}; -use trouble_host::gatt::GattEvent; -use trouble_host::{Address, BleHost, BleHostResources, PacketQos}; -use {defmt_rtt as _, embassy_time as _, panic_probe as _}; - -bind_interrupts!(struct Irqs { - PIO0_IRQ_0 => InterruptHandler; -}); - -#[embassy_executor::task] -async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { - runner.run().await -} - -#[embassy_executor::main] -async fn main(spawner: Spawner) { - let p = embassy_rp::init(Default::default()); - let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); - let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); - let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin"); - - // To make flashing faster for development, you may want to flash the firmwares independently - // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 - // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 - // probe-rs download 43439A0_btfw.bin --format bin --chip RP2040 --base-address 0x10141400 - //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; - //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; - //let btfw = unsafe { core::slice::from_raw_parts(0x10141400 as *const u8, 6164) }; - - let pwr = Output::new(p.PIN_23, Level::Low); - let cs = Output::new(p.PIN_25, Level::High); - let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); - - static STATE: StaticCell = StaticCell::new(); - let state = STATE.init(cyw43::State::new()); - let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await; - unwrap!(spawner.spawn(cyw43_task(runner))); - control.init(clm).await; - - let controller: ExternalController<_, 10> = ExternalController::new(bt_device); - static HOST_RESOURCES: StaticCell> = StaticCell::new(); - let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None)); - - let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources); - - ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff])); - let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new(); - - // Generic Access Service (mandatory) - let id = b"Pico W Bluetooth"; - let appearance = [0x80, 0x07]; - let mut bat_level = [0; 1]; - let handle = { - let mut svc = table.add_service(Service::new(0x1800)); - let _ = svc.add_characteristic_ro(0x2a00, id); - let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]); - svc.build(); - - // Generic attribute service (mandatory) - table.add_service(Service::new(0x1801)); - - // Battery service - let mut svc = table.add_service(Service::new(0x180f)); - - svc.add_characteristic( - 0x2a19, - &[CharacteristicProp::Read, CharacteristicProp::Notify], - &mut bat_level, - ) - .build() - }; - - let mut adv_data = [0; 31]; - AdStructure::encode_slice( - &[ - AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), - AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]), - AdStructure::CompleteLocalName(b"Pico W Bluetooth"), - ], - &mut adv_data[..], - ) - .unwrap(); - - let server = ble.gatt_server(&table); - - info!("Starting advertising and GATT service"); - let _ = join3( - ble.run(), - async { - loop { - match server.next().await { - Ok(GattEvent::Write { handle, connection: _ }) => { - let _ = table.get(handle, |value| { - info!("Write event. Value written: {:?}", value); - }); - } - Ok(GattEvent::Read { .. }) => { - info!("Read event"); - } - Err(e) => { - error!("Error processing GATT events: {:?}", e); - } - } - } - }, - async { - let mut advertiser = ble - .advertise( - &Default::default(), - Advertisement::ConnectableScannableUndirected { - adv_data: &adv_data[..], - scan_data: &[], - }, - ) - .await - .unwrap(); - let conn = advertiser.accept().await.unwrap(); - // Keep connection alive - let mut tick: u8 = 0; - loop { - Timer::after(Duration::from_secs(10)).await; - tick += 1; - server.notify(handle, &conn, &[tick]).await.unwrap(); - } - }, - ) - .await; -} -- cgit From a3d35216d4649fbadd3e78fe240b736258b7befe Mon Sep 17 00:00:00 2001 From: Eekle <96976531+Eekle@users.noreply.github.com> Date: Tue, 24 Dec 2024 13:23:08 +0100 Subject: Remove manual settings of `composite_with_iads=true` --- examples/rp/src/bin/pio_uart.rs | 7 ------- examples/rp/src/bin/usb_ethernet.rs | 6 ------ examples/rp/src/bin/usb_midi.rs | 7 ------- examples/rp/src/bin/usb_raw.rs | 7 ------- examples/rp/src/bin/usb_raw_bulk.rs | 7 ------- examples/rp/src/bin/usb_serial.rs | 7 ------- examples/rp/src/bin/usb_serial_with_logger.rs | 7 ------- 7 files changed, 48 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_uart.rs b/examples/rp/src/bin/pio_uart.rs index aaf2a524f..485c65204 100644 --- a/examples/rp/src/bin/pio_uart.rs +++ b/examples/rp/src/bin/pio_uart.rs @@ -49,13 +49,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 9a15125d4..2add20bc6 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -60,12 +60,6 @@ async fn main(spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for Windows support. - config.composite_with_iads = true; - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - // Create embassy-usb DeviceBuilder using the driver and config. static CONFIG_DESC: StaticCell<[u8; 256]> = StaticCell::new(); static BOS_DESC: StaticCell<[u8; 256]> = StaticCell::new(); diff --git a/examples/rp/src/bin/usb_midi.rs b/examples/rp/src/bin/usb_midi.rs index 11db1b2e1..3b7910f8b 100644 --- a/examples/rp/src/bin/usb_midi.rs +++ b/examples/rp/src/bin/usb_midi.rs @@ -37,13 +37,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_raw.rs b/examples/rp/src/bin/usb_raw.rs index 97e7e0244..5974c04c0 100644 --- a/examples/rp/src/bin/usb_raw.rs +++ b/examples/rp/src/bin/usb_raw.rs @@ -84,13 +84,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // // Required for windows compatibility. - // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_raw_bulk.rs b/examples/rp/src/bin/usb_raw_bulk.rs index 331c3da4c..103269791 100644 --- a/examples/rp/src/bin/usb_raw_bulk.rs +++ b/examples/rp/src/bin/usb_raw_bulk.rs @@ -62,13 +62,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // // Required for windows compatibility. - // // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs index 4a802994a..5e3f0f378 100644 --- a/examples/rp/src/bin/usb_serial.rs +++ b/examples/rp/src/bin/usb_serial.rs @@ -37,13 +37,6 @@ async fn main(spawner: Spawner) { config.serial_number = Some("12345678"); config.max_power = 100; config.max_packet_size_0 = 64; - - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; config }; diff --git a/examples/rp/src/bin/usb_serial_with_logger.rs b/examples/rp/src/bin/usb_serial_with_logger.rs index f9cfdef94..ea13a1e27 100644 --- a/examples/rp/src/bin/usb_serial_with_logger.rs +++ b/examples/rp/src/bin/usb_serial_with_logger.rs @@ -37,13 +37,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xEF; - config.device_sub_class = 0x02; - config.device_protocol = 0x01; - config.composite_with_iads = true; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; -- cgit From 8243a8a3892dc499be560a0bf2134e641b856760 Mon Sep 17 00:00:00 2001 From: Bailey Townsend Date: Sat, 28 Dec 2024 00:07:14 -0600 Subject: Added new param to examples and created a pico plus 2 w example --- examples/rp/src/bin/wifi_ap_tcp_server.rs | 13 +++++++++++-- examples/rp/src/bin/wifi_blinky.rs | 13 +++++++++++-- examples/rp/src/bin/wifi_scan.rs | 13 +++++++++++-- examples/rp/src/bin/wifi_tcp_server.rs | 13 +++++++++++-- examples/rp/src/bin/wifi_webrequest.rs | 13 +++++++++++-- 5 files changed, 55 insertions(+), 10 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 4c9651433..e97ddb4c1 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -7,7 +7,7 @@ use core::str::from_utf8; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; @@ -57,7 +57,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 0107a2326..6e91ce167 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -5,7 +5,7 @@ #![no_std] #![no_main] -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; @@ -41,7 +41,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 2ef899080..fe9c363d9 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -7,7 +7,7 @@ use core::str; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; @@ -45,7 +45,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 7bf546e01..14dbf4552 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; @@ -61,7 +61,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 1ae909917..f1b398b65 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -8,7 +8,7 @@ use core::str::from_utf8; use cyw43::JoinOptions; -use cyw43_pio::PioSpi; +use cyw43_pio::{PioSpi, DEFAULT_CLOCK_DIVIDER}; use defmt::*; use embassy_executor::Spawner; use embassy_net::dns::DnsSocket; @@ -63,7 +63,16 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); let mut pio = Pio::new(p.PIO0, Irqs); - let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); + let spi = PioSpi::new( + &mut pio.common, + pio.sm0, + DEFAULT_CLOCK_DIVIDER, + pio.irq0, + cs, + p.PIN_24, + p.PIN_29, + p.DMA_CH0, + ); static STATE: StaticCell = StaticCell::new(); let state = STATE.init(cyw43::State::new()); -- cgit From e6001e66f8b21483a707d0015f9d278556759a7c Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 31 Dec 2024 15:54:42 +0100 Subject: Improve orchestrate_tasks example with shared state and better documentation Add mutex-protected shared system state Improve task coordination and signaling Add more documentation --- examples/rp/src/bin/orchestrate_tasks.rs | 312 +++++++++++++++---------------- 1 file changed, 156 insertions(+), 156 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 0e21d5833..6f209da95 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -1,20 +1,18 @@ //! This example demonstrates some approaches to communicate between tasks in order to orchestrate the state of the system. //! -//! We demonstrate how to: -//! - use a channel to send messages between tasks, in this case here in order to have one task control the state of the system. -//! - use a signal to terminate a task. -//! - use command channels to send commands to another task. -//! - use different ways to receive messages, from a straightforwar awaiting on one channel to a more complex awaiting on multiple futures. +//! The system consists of several tasks: +//! - Three tasks that generate random numbers at different intervals (simulating i.e. sensor readings) +//! - A task that monitors USB power connection (hardware event handling) +//! - A task that reads system voltage (ADC sampling) +//! - A consumer task that processes all this information //! -//! There are more patterns to orchestrate tasks, this is just one example. +//! The system maintains state in a single place, wrapped in a Mutex. //! -//! We will use these tasks to generate example "state information": -//! - a task that generates random numbers in intervals of 60s -//! - a task that generates random numbers in intervals of 30s -//! - a task that generates random numbers in intervals of 90s -//! - a task that notifies about being attached/disattached from usb power -//! - a task that measures vsys voltage in intervals of 30s -//! - a task that consumes the state information and reacts to it +//! We demonstrate how to: +//! - use a mutex to maintain shared state between tasks +//! - use a channel to send events between tasks +//! - use an orchestrator task to coordinate tasks and handle state transitions +//! - use signals to notify about state changes and terminate tasks #![no_std] #![no_main] @@ -28,15 +26,12 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::{channel, signal}; +use embassy_sync::{channel, mutex::Mutex, signal}; use embassy_time::{Duration, Timer}; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; -// This is just some preparation, see example `assign_resources.rs` for more information on this. We prep the rresources that we will be using in different tasks. -// **Note**: This will not work with a board that has a wifi chip, because the wifi chip uses pins 24 and 29 for its own purposes. A way around this in software -// is not trivial, at least if you intend to use wifi, too. Workaround is to wire from vsys and vbus pins to appropriate pins on the board through a voltage divider. Then use those pins. -// For this example it will not matter much, the concept of what we are showing remains valid. +// Hardware resource assignment. See other examples for different ways of doing this. assign_resources! { vsys: Vsys { adc: ADC, @@ -47,228 +42,233 @@ assign_resources! { }, } +// Interrupt binding - required for hardware peripherals like ADC bind_interrupts!(struct Irqs { ADC_IRQ_FIFO => InterruptHandler; }); -/// This is the type of Events that we will send from the worker tasks to the orchestrating task. +/// Events that worker tasks send to the orchestrator enum Events { - UsbPowered(bool), - VsysVoltage(f32), - FirstRandomSeed(u32), - SecondRandomSeed(u32), - ThirdRandomSeed(u32), - ResetFirstRandomSeed, + UsbPowered(bool), // USB connection state changed + VsysVoltage(f32), // New voltage reading + FirstRandomSeed(u32), // Random number from 30s timer + SecondRandomSeed(u32), // Random number from 60s timer + ThirdRandomSeed(u32), // Random number from 90s timer + ResetFirstRandomSeed, // Signal to reset the first counter } -/// This is the type of Commands that we will send from the orchestrating task to the worker tasks. -/// Note that we are lazy here and only have one command, you might want to have more. +/// Commands that can control task behavior. +/// Currently only used to stop tasks, but could be extended for other controls. enum Commands { - /// This command will stop the appropriate worker task + /// Signals a task to stop execution Stop, } -/// This is the state of the system, we will use this to orchestrate the system. This is a simple example, in a real world application this would be more complex. -#[derive(Default, Debug, Clone, Format)] +/// The central state of our system, shared between tasks. +#[derive(Clone, Format)] struct State { usb_powered: bool, vsys_voltage: f32, first_random_seed: u32, second_random_seed: u32, third_random_seed: u32, + first_random_seed_task_running: bool, times_we_got_first_random_seed: u8, maximum_times_we_want_first_random_seed: u8, } +/// A formatted view of the system status, used for logging. Used for the below `get_system_summary` fn. +#[derive(Format)] +struct SystemStatus { + power_source: &'static str, + voltage: f32, +} + impl State { - fn new() -> Self { + const fn new() -> Self { Self { usb_powered: false, vsys_voltage: 0.0, first_random_seed: 0, second_random_seed: 0, third_random_seed: 0, + first_random_seed_task_running: false, times_we_got_first_random_seed: 0, maximum_times_we_want_first_random_seed: 3, } } + + /// Returns a formatted summary of power state and voltage. + /// Shows how to create methods that work with shared state. + fn get_system_summary(&self) -> SystemStatus { + SystemStatus { + power_source: if self.usb_powered { + "USB powered" + } else { + "Battery powered" + }, + voltage: self.vsys_voltage, + } + } } -/// Channel for the events that we want the orchestrator to react to, all state events are of the type Enum Events. -/// We use a channel with an arbitrary size of 10, the precise size of the queue depends on your use case. This depends on how many events we -/// expect to be generated in a given time frame and how fast the orchestrator can react to them. And then if we rather want the senders to wait for -/// new slots in the queue or if we want the orchestrator to have a backlog of events to process. In this case here we expect to always be enough slots -/// in the queue, so the worker tasks can in all nominal cases send their events and continue with their work without waiting. -/// For the events we - in this case here - do not want to loose any events, so a channel is a good choice. See embassy_sync docs for other options. +/// The shared state protected by a mutex +static SYSTEM_STATE: Mutex = Mutex::new(State::new()); + +/// Channel for events from worker tasks to the orchestrator static EVENT_CHANNEL: channel::Channel = channel::Channel::new(); -/// Signal for stopping the first random signal task. We use a signal here, because we need no queue. It is suffiient to have one signal active. +/// Signal used to stop the first random number task static STOP_FIRST_RANDOM_SIGNAL: signal::Signal = signal::Signal::new(); -/// Channel for the state that we want the consumer task to react to. We use a channel here, because we want to have a queue of state changes, although -/// we want the queue to be of size 1, because we want to finish rwacting to the state change before the next one comes in. This is just a design choice -/// and depends on your use case. -static CONSUMER_CHANNEL: channel::Channel = channel::Channel::new(); - -// And now we can put all this into use +/// Signal for notifying about state changes +static STATE_CHANGED: signal::Signal = signal::Signal::new(); -/// This is the main task, that will not do very much besides spawning the other tasks. This is a design choice, you could do the -/// orchestrating here. This is to show that we do not need a main loop here, the system will run indefinitely as long as at least one task is running. #[embassy_executor::main] async fn main(spawner: Spawner) { - // initialize the peripherals let p = embassy_rp::init(Default::default()); - // split the resources, for convenience - see above let r = split_resources! {p}; - // spawn the tasks spawner.spawn(orchestrate(spawner)).unwrap(); spawner.spawn(random_60s(spawner)).unwrap(); spawner.spawn(random_90s(spawner)).unwrap(); + // `random_30s` is not spawned here, butin the orchestrate task depending on state spawner.spawn(usb_power(spawner, r.vbus)).unwrap(); spawner.spawn(vsys_voltage(spawner, r.vsys)).unwrap(); spawner.spawn(consumer(spawner)).unwrap(); } -/// This is the task handling the system state and orchestrating the other tasks. WEe can regard this as the "main loop" of the system. +/// Main task that processes all events and updates system state. #[embassy_executor::task] -async fn orchestrate(_spawner: Spawner) { - let mut state = State::new(); - - // we need to have a receiver for the events +async fn orchestrate(spawner: Spawner) { let receiver = EVENT_CHANNEL.receiver(); - // and we need a sender for the consumer task - let state_sender = CONSUMER_CHANNEL.sender(); - loop { - // we await on the receiver, this will block until a new event is available - // as an alternative to this, we could also await on multiple channels, this would block until at least one of the channels has an event - // see the embassy_futures docs: https://docs.embassy.dev/embassy-futures/git/default/select/index.html - // The task random_30s does a select, if you want to have a look at that. - // Another reason to use select may also be that we want to have a timeout, so we can react to the absence of events within a time frame. - // We keep it simple here. + // Do nothing until we receive any event let event = receiver.receive().await; - // react to the events - match event { - Events::UsbPowered(usb_powered) => { - // update the state and/or react to the event here - state.usb_powered = usb_powered; - info!("Usb powered: {}", usb_powered); - } - Events::VsysVoltage(voltage) => { - // update the state and/or react to the event here - state.vsys_voltage = voltage; - info!("Vsys voltage: {}", voltage); - } - Events::FirstRandomSeed(seed) => { - // update the state and/or react to the event here - state.first_random_seed = seed; - // here we change some meta state, we count how many times we got the first random seed - state.times_we_got_first_random_seed += 1; - info!( - "First random seed: {}, and that was iteration {} of receiving this.", - seed, &state.times_we_got_first_random_seed - ); - } - Events::SecondRandomSeed(seed) => { - // update the state and/or react to the event here - state.second_random_seed = seed; - info!("Second random seed: {}", seed); - } - Events::ThirdRandomSeed(seed) => { - // update the state and/or react to the event here - state.third_random_seed = seed; - info!("Third random seed: {}", seed); + // Scope in which we want to lock the system state. As an alternative we could also call `drop` on the state + { + let mut state = SYSTEM_STATE.lock().await; + + match event { + Events::UsbPowered(usb_powered) => { + state.usb_powered = usb_powered; + info!("Usb powered: {}", usb_powered); + info!("System summary: {}", state.get_system_summary()); + } + Events::VsysVoltage(voltage) => { + state.vsys_voltage = voltage; + info!("Vsys voltage: {}", voltage); + } + Events::FirstRandomSeed(seed) => { + state.first_random_seed = seed; + state.times_we_got_first_random_seed += 1; + info!( + "First random seed: {}, and that was iteration {} of receiving this.", + seed, &state.times_we_got_first_random_seed + ); + } + Events::SecondRandomSeed(seed) => { + state.second_random_seed = seed; + info!("Second random seed: {}", seed); + } + Events::ThirdRandomSeed(seed) => { + state.third_random_seed = seed; + info!("Third random seed: {}", seed); + } + Events::ResetFirstRandomSeed => { + state.times_we_got_first_random_seed = 0; + state.first_random_seed = 0; + info!("Resetting the first random seed counter"); + } } - Events::ResetFirstRandomSeed => { - // update the state and/or react to the event here - state.times_we_got_first_random_seed = 0; - state.first_random_seed = 0; - info!("Resetting the first random seed counter"); + + // Handle task orchestration based on state + // Just placed as an example here, could be hooked into the event system, puton a timer, ... + match state.times_we_got_first_random_seed { + max if max == state.maximum_times_we_want_first_random_seed => { + info!("Stopping the first random signal task"); + STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); + EVENT_CHANNEL.sender().send(Events::ResetFirstRandomSeed).await; + } + 0 => { + let respawn_first_random_seed_task = !state.first_random_seed_task_running; + // Deliberately dropping the Mutex lock here to release it before a lengthy operation + drop(state); + if respawn_first_random_seed_task { + info!("(Re)-Starting the first random signal task"); + spawner.spawn(random_30s(spawner)).unwrap(); + } + } + _ => {} } } - // we now have an altered state - // there is a crate for detecting field changes on crates.io (https://crates.io/crates/fieldset) that might be useful here - // for now we just keep it simple - - // we send the state to the consumer task - // since the channel has a size of 1, this will block until the consumer task has received the state, which is what we want here in this example - // **Note:** It is bad design to send too much data between tasks, with no clear definition of what "too much" is. In this example we send the - // whole state, in a real world application you might want to send only the data, that is relevant to the consumer task AND only when it has changed. - // We keep it simple here. - state_sender.send(state.clone()).await; + + STATE_CHANGED.signal(()); } } -/// This task will consume the state information and react to it. This is a simple example, in a real world application this would be more complex -/// and we could have multiple consumer tasks, each reacting to different parts of the state. +/// Task that monitors state changes and logs system status. #[embassy_executor::task] -async fn consumer(spawner: Spawner) { - // we need to have a receiver for the state - let receiver = CONSUMER_CHANNEL.receiver(); - let sender = EVENT_CHANNEL.sender(); +async fn consumer(_spawner: Spawner) { loop { - // we await on the receiver, this will block until a new state is available - let state = receiver.receive().await; - // react to the state, in this case here we just log it - info!("The consumer has reveived this state: {:?}", &state); - - // here we react to the state, in this case here we want to start or stop the first random signal task depending on the state of the system - match state.times_we_got_first_random_seed { - max if max == state.maximum_times_we_want_first_random_seed => { - info!("Stopping the first random signal task"); - // we send a command to the task - STOP_FIRST_RANDOM_SIGNAL.signal(Commands::Stop); - // we notify the orchestrator that we have sent the command - sender.send(Events::ResetFirstRandomSeed).await; - } - 0 => { - // we start the task, which presents us with an interesting problem, because we may return here before the task has started - // here we just try and log if the task has started, in a real world application you might want to handle this more gracefully - info!("Starting the first random signal task"); - match spawner.spawn(random_30s(spawner)) { - Ok(_) => info!("Successfully spawned random_30s task"), - Err(e) => info!("Failed to spawn random_30s task: {:?}", e), - } - } - _ => {} - } + // Wait for state change notification + STATE_CHANGED.wait().await; + + let state = SYSTEM_STATE.lock().await; + info!( + "State update - {} | Seeds - First: {} (count: {}/{}, running: {}), Second: {}, Third: {}", + state.get_system_summary(), + state.first_random_seed, + state.times_we_got_first_random_seed, + state.maximum_times_we_want_first_random_seed, + state.first_random_seed_task_running, + state.second_random_seed, + state.third_random_seed + ); } } -/// This task will generate random numbers in intervals of 30s -/// The task will terminate after it has received a command signal to stop, see the orchestrate task for that. -/// Note that we are not spawning this task from main, as we will show how such a task can be spawned and closed dynamically. +/// Task that generates random numbers every 30 seconds until stopped. +/// Shows how to handle both timer events and stop signals. +/// As an example of some routine we want to be on or off depending on other needs. #[embassy_executor::task] async fn random_30s(_spawner: Spawner) { + { + let mut state = SYSTEM_STATE.lock().await; + state.first_random_seed_task_running = true; + } + let mut rng = RoscRng; let sender = EVENT_CHANNEL.sender(); + loop { - // we either await on the timer or the signal, whichever comes first. - let futures = select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await; - match futures { + // Wait for either 30s timer or stop signal (like select() in Go) + match select(Timer::after(Duration::from_secs(30)), STOP_FIRST_RANDOM_SIGNAL.wait()).await { Either::First(_) => { - // we received are operating on the timer info!("30s are up, generating random number"); let random_number = rng.next_u32(); sender.send(Events::FirstRandomSeed(random_number)).await; } Either::Second(_) => { - // we received the signal to stop info!("Received signal to stop, goodbye!"); + + let mut state = SYSTEM_STATE.lock().await; + state.first_random_seed_task_running = false; + break; } } } } -/// This task will generate random numbers in intervals of 60s +/// Task that generates random numbers every 60 seconds. As an example of some routine. #[embassy_executor::task] async fn random_60s(_spawner: Spawner) { let mut rng = RoscRng; let sender = EVENT_CHANNEL.sender(); + loop { Timer::after(Duration::from_secs(60)).await; let random_number = rng.next_u32(); @@ -276,11 +276,12 @@ async fn random_60s(_spawner: Spawner) { } } -/// This task will generate random numbers in intervals of 90s +/// Task that generates random numbers every 90 seconds. . As an example of some routine. #[embassy_executor::task] async fn random_90s(_spawner: Spawner) { let mut rng = RoscRng; let sender = EVENT_CHANNEL.sender(); + loop { Timer::after(Duration::from_secs(90)).await; let random_number = rng.next_u32(); @@ -288,31 +289,30 @@ async fn random_90s(_spawner: Spawner) { } } -/// This task will notify if we are connected to usb power +/// Task that monitors USB power connection. As an example of some Interrupt somewhere. #[embassy_executor::task] pub async fn usb_power(_spawner: Spawner, r: Vbus) { let mut vbus_in = Input::new(r.pin_24, Pull::None); let sender = EVENT_CHANNEL.sender(); + loop { sender.send(Events::UsbPowered(vbus_in.is_high())).await; vbus_in.wait_for_any_edge().await; } } -/// This task will measure the vsys voltage in intervals of 30s +/// Task that reads system voltage through ADC. As an example of some continuous sensor reading. #[embassy_executor::task] pub async fn vsys_voltage(_spawner: Spawner, r: Vsys) { let mut adc = Adc::new(r.adc, Irqs, Config::default()); let vsys_in = r.pin_29; let mut channel = Channel::new_pin(vsys_in, Pull::None); let sender = EVENT_CHANNEL.sender(); + loop { - // read the adc value + Timer::after(Duration::from_secs(30)).await; let adc_value = adc.read(&mut channel).await.unwrap(); - // convert the adc value to voltage. - // 3.3 is the reference voltage, 3.0 is the factor for the inbuilt voltage divider and 4096 is the resolution of the adc let voltage = (adc_value as f32) * 3.3 * 3.0 / 4096.0; sender.send(Events::VsysVoltage(voltage)).await; - Timer::after(Duration::from_secs(30)).await; } } -- cgit From 6efd6a457f938a65aea85b671a79214fe5e79b96 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 31 Dec 2024 15:58:57 +0100 Subject: fmt --- examples/rp/src/bin/orchestrate_tasks.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 6f209da95..31f10d8db 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -26,7 +26,8 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; -use embassy_sync::{channel, mutex::Mutex, signal}; +use embassy_sync::{channel, signal}; ++use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; -- cgit From 463a3346de74ce354bf5bb55b67eb77e7c5ace73 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 31 Dec 2024 16:01:09 +0100 Subject: fmt --- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 31f10d8db..7ff004860 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -26,8 +26,8 @@ use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; use embassy_rp::{bind_interrupts, peripherals}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; -+use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; -- cgit From 3aca6150251a6bab6592a1c3173324e3c6eb9416 Mon Sep 17 00:00:00 2001 From: lonesometraveler Date: Thu, 2 Jan 2025 10:28:29 -0500 Subject: Fix broken link to WIZnet W5500-EVB-Pico --- examples/rp/src/bin/ethernet_w5500_multisocket.rs | 2 +- examples/rp/src/bin/ethernet_w5500_tcp_client.rs | 2 +- examples/rp/src/bin/ethernet_w5500_tcp_server.rs | 2 +- examples/rp/src/bin/ethernet_w5500_udp.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index 12003adbe..2bea9fc9d 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -1,6 +1,6 @@ //! This example shows how you can allow multiple simultaneous TCP connections, by having multiple sockets listening on the same port. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index d66a43a88..78d1b0b83 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -1,6 +1,6 @@ //! This example implements a TCP client that attempts to connect to a host on port 1234 and send it some data once per second. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 97d9bd4c9..25a38c714 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -1,7 +1,7 @@ //! This example implements a TCP echo server on port 1234 and using DHCP. //! Send it some data, you should see it echoed back and printed in the console. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index b1b5f9758..683e29222 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -1,6 +1,6 @@ //! This example implements a UDP server listening on port 1234 and echoing back the data. //! -//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board. +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. #![no_std] #![no_main] -- cgit From 66c5fe0a757e679541334c82a3fa0f7701b6f44d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 6 Feb 2025 00:02:52 +0100 Subject: examples/rp: remove unneeded sio spinlock stuck bug workarounds. This is now workarounded by embassy-rp itself. --- examples/rp/src/bin/interrupt.rs | 1 - examples/rp/src/bin/spi_sdmmc.rs | 1 - 2 files changed, 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs index 5b9d7027e..787cdc112 100644 --- a/examples/rp/src/bin/interrupt.rs +++ b/examples/rp/src/bin/interrupt.rs @@ -32,7 +32,6 @@ static ADC_VALUES: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { - embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); let adc = Adc::new_blocking(p.ADC, Default::default()); diff --git a/examples/rp/src/bin/spi_sdmmc.rs b/examples/rp/src/bin/spi_sdmmc.rs index a60850d0f..4e3c2f199 100644 --- a/examples/rp/src/bin/spi_sdmmc.rs +++ b/examples/rp/src/bin/spi_sdmmc.rs @@ -32,7 +32,6 @@ impl embedded_sdmmc::TimeSource for DummyTimesource { #[embassy_executor::main] async fn main(_spawner: Spawner) { - embassy_rp::pac::SIO.spinlock(31).write_value(1); let p = embassy_rp::init(Default::default()); // SPI clock needs to be running at <= 400kHz during initialization -- cgit From 38b5f8bd0afd9669e638b8d83210427d2d372a96 Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 01:07:25 -0500 Subject: examples/rp: add examples using ICMP sockets and the ping utility --- examples/rp/src/bin/ethernet_w5500_icmp.rs | 143 ++++++++++++++++++++++++ examples/rp/src/bin/ethernet_w5500_icmp_ping.rs | 135 ++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 examples/rp/src/bin/ethernet_w5500_icmp.rs create mode 100644 examples/rp/src/bin/ethernet_w5500_icmp_ping.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs new file mode 100644 index 000000000..a07cdf88d --- /dev/null +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -0,0 +1,143 @@ +//! This example implements an echo (ping) with an ICMP Socket and using defmt to report the results. +//! +//! Although there is a better way to execute pings using the child module ping of the icmp module, +//! this example allows for other icmp messages like `Destination unreachable` to be sent aswell. +//! +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::yield_now; +use embassy_net::icmp::{ChecksumCapabilities, IcmpEndpoint, IcmpSocket, Icmpv4Packet, Icmpv4Repr, PacketMetadata}; +use embassy_net::{Stack, StackResources}; +use embassy_net_wiznet::chip::W5500; +use embassy_net_wiznet::*; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Level, Output, Pull}; +use embassy_rp::peripherals::SPI0; +use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; +use embassy_time::{Delay, Instant, Timer}; +use embedded_hal_bus::spi::ExclusiveDevice; +use rand::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +type ExclusiveSpiDevice = ExclusiveDevice, Output<'static>, Delay>; + +#[embassy_executor::task] +async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rng = RoscRng; + + let mut spi_cfg = SpiConfig::default(); + spi_cfg.frequency = 50_000_000; + let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18); + let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); + let cs = Output::new(p.PIN_17, Level::High); + let w5500_int = Input::new(p.PIN_21, Pull::Up); + let w5500_reset = Output::new(p.PIN_20, Level::High); + + let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); + let (device, runner) = embassy_net_wiznet::new( + mac_addr, + state, + ExclusiveDevice::new(spi, cs, Delay), + w5500_int, + w5500_reset, + ) + .await + .unwrap(); + unwrap!(spawner.spawn(ethernet_task(runner))); + + // Generate random seed + let seed = rng.next_u64(); + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + let (stack, runner) = embassy_net::new( + device, + embassy_net::Config::dhcpv4(Default::default()), + RESOURCES.init(StackResources::new()), + seed, + ); + + // Launch network task + unwrap!(spawner.spawn(net_task(runner))); + + info!("Waiting for DHCP..."); + let cfg = wait_for_config(stack).await; + let local_addr = cfg.address.address(); + info!("IP address: {:?}", local_addr); + + // Then we can use it! + let mut rx_buffer = [0; 256]; + let mut tx_buffer = [0; 256]; + let mut rx_meta = [PacketMetadata::EMPTY]; + let mut tx_meta = [PacketMetadata::EMPTY]; + + // Identifier used for the ICMP socket + let ident = 42; + + // Create and bind the socket + let mut socket = IcmpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); + socket.bind(IcmpEndpoint::Ident(ident)).unwrap(); + + // Create the repr for the packet + let icmp_repr = Icmpv4Repr::EchoRequest { + ident, + seq_no: 0, + data: b"Hello, icmp!", + }; + + // Send the packet and store the starting instant to mesure latency later + let start = socket + .send_to_with( + icmp_repr.buffer_len(), + cfg.gateway.unwrap(), + |buf| { + // Create and populate the packet buffer allocated by `send_to_with` + let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); + icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); + Instant::now() // Return the instant where the packet was sent + }, + ) + .await + .unwrap(); + + // Recieve and log the data of the reply + socket + .recv_with(|(buf, addr)| { + let packet = Icmpv4Packet::new_checked(buf).unwrap(); + info!("Recieved {:?} from {} in {}ms", packet.data(), addr, start.elapsed().as_millis()); + }) + .await + .unwrap(); + + loop { + Timer::after_secs(10).await; + } +} + +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { + loop { + if let Some(config) = stack.config_v4() { + return config.clone(); + } + yield_now().await; + } +} diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs new file mode 100644 index 000000000..0d83e3831 --- /dev/null +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -0,0 +1,135 @@ +//! This example implements a LAN ping scan with the ping utilities in the icmp module of embassy-net. +//! +//! Example written for the [`WIZnet W5500-EVB-Pico`](https://docs.wiznet.io/Product/iEthernet/W5500/w5500-evb-pico) board. + +#![no_std] +#![no_main] + +use core::net::Ipv4Addr; +use core::ops::Not; +use core::str::FromStr; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_futures::yield_now; +use embassy_net::icmp::ping::{PingManager, PingParams}; +use embassy_net::icmp::PacketMetadata; +use embassy_net::{Ipv4Cidr, Stack, StackResources}; +use embassy_net_wiznet::chip::W5500; +use embassy_net_wiznet::*; +use embassy_rp::clocks::RoscRng; +use embassy_rp::gpio::{Input, Level, Output, Pull}; +use embassy_rp::peripherals::SPI0; +use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; +use embassy_time::{Delay, Duration}; +use embedded_hal_bus::spi::ExclusiveDevice; +use rand::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +type ExclusiveSpiDevice = ExclusiveDevice, Output<'static>, Delay>; + +#[embassy_executor::task] +async fn ethernet_task(runner: Runner<'static, W5500, ExclusiveSpiDevice, Input<'static>, Output<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! { + runner.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_rp::init(Default::default()); + let mut rng = RoscRng; + + let mut spi_cfg = SpiConfig::default(); + spi_cfg.frequency = 50_000_000; + let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18); + let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg); + let cs = Output::new(p.PIN_17, Level::High); + let w5500_int = Input::new(p.PIN_21, Pull::Up); + let w5500_reset = Output::new(p.PIN_20, Level::High); + + let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00]; + static STATE: StaticCell> = StaticCell::new(); + let state = STATE.init(State::<8, 8>::new()); + let (device, runner) = embassy_net_wiznet::new( + mac_addr, + state, + ExclusiveDevice::new(spi, cs, Delay), + w5500_int, + w5500_reset, + ) + .await + .unwrap(); + unwrap!(spawner.spawn(ethernet_task(runner))); + + // Generate random seed + let seed = rng.next_u64(); + + // Init network stack + static RESOURCES: StaticCell> = StaticCell::new(); + let (stack, runner) = embassy_net::new( + device, + embassy_net::Config::dhcpv4(Default::default()), + RESOURCES.init(StackResources::new()), + seed, + ); + + // Launch network task + unwrap!(spawner.spawn(net_task(runner))); + + info!("Waiting for DHCP..."); + let cfg = wait_for_config(stack).await; + let local_addr = cfg.address.address(); + info!("IP address: {:?}", local_addr); + let gateway = cfg.gateway.unwrap(); + let mask = cfg.address.netmask(); + let lower_bound = (gateway.to_bits() & mask.to_bits()) + 1; + let upper_bound = gateway.to_bits() | mask.to_bits().not(); + let addr_range = lower_bound..=upper_bound; + + // Then we can use it! + let mut rx_buffer = [0; 256]; + let mut tx_buffer = [0; 256]; + let mut rx_meta = [PacketMetadata::EMPTY]; + let mut tx_meta = [PacketMetadata::EMPTY]; + + // Create the ping manager instance + let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); + let addr = "192.168.8.1"; // Address to ping to + // Create the PingParams with the target address + let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); + // (optional) Set custom properties of the ping + ping_params.set_payload(b"Hello, Ping!"); // custom payload + ping_params.set_count(1); // ping 1 times per ping call + ping_params.set_timeout(Duration::from_millis(500)); // wait .5 seconds instead of 4 + + info!("Online hosts in {}:", Ipv4Cidr::from_netmask(gateway, mask).unwrap()); + let mut total_online_hosts = 0u32; + for addr in addr_range { + let ip_addr = Ipv4Addr::from_bits(addr); + // Set the target address in the ping params + ping_params.set_target(ip_addr); + // Execute the ping with the given parameters and wait for the reply + match ping_manager.ping(&ping_params).await { + Ok(time) => { + info!("{} is online\n- latency: {}ms\n", ip_addr, time.as_millis()); + total_online_hosts += 1; + }, + _ => continue, + } + } + info!("Ping scan complete, total online hosts: {}", total_online_hosts); +} + +async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 { + loop { + if let Some(config) = stack.config_v4() { + return config.clone(); + } + yield_now().await; + } +} -- cgit From bdb1b812135b7cb22f65009242d5b61712e8e9d7 Mon Sep 17 00:00:00 2001 From: skkeye Date: Sun, 9 Feb 2025 02:11:15 -0500 Subject: fix: nightly fmt --- examples/rp/src/bin/ethernet_w5500_icmp.rs | 25 +++++++++++++------------ examples/rp/src/bin/ethernet_w5500_icmp_ping.rs | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index a07cdf88d..5f336b579 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -1,5 +1,5 @@ //! This example implements an echo (ping) with an ICMP Socket and using defmt to report the results. -//! +//! //! Although there is a better way to execute pings using the child module ping of the icmp module, //! this example allows for other icmp messages like `Destination unreachable` to be sent aswell. //! @@ -106,16 +106,12 @@ async fn main(spawner: Spawner) { // Send the packet and store the starting instant to mesure latency later let start = socket - .send_to_with( - icmp_repr.buffer_len(), - cfg.gateway.unwrap(), - |buf| { - // Create and populate the packet buffer allocated by `send_to_with` - let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); - icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); - Instant::now() // Return the instant where the packet was sent - }, - ) + .send_to_with(icmp_repr.buffer_len(), cfg.gateway.unwrap(), |buf| { + // Create and populate the packet buffer allocated by `send_to_with` + let mut icmp_packet = Icmpv4Packet::new_unchecked(buf); + icmp_repr.emit(&mut icmp_packet, &ChecksumCapabilities::default()); + Instant::now() // Return the instant where the packet was sent + }) .await .unwrap(); @@ -123,7 +119,12 @@ async fn main(spawner: Spawner) { socket .recv_with(|(buf, addr)| { let packet = Icmpv4Packet::new_checked(buf).unwrap(); - info!("Recieved {:?} from {} in {}ms", packet.data(), addr, start.elapsed().as_millis()); + info!( + "Recieved {:?} from {} in {}ms", + packet.data(), + addr, + start.elapsed().as_millis() + ); }) .await .unwrap(); diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs index 0d83e3831..0724311f9 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -100,7 +100,7 @@ async fn main(spawner: Spawner) { // Create the ping manager instance let mut ping_manager = PingManager::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer); let addr = "192.168.8.1"; // Address to ping to - // Create the PingParams with the target address + // Create the PingParams with the target address let mut ping_params = PingParams::new(Ipv4Addr::from_str(addr).unwrap()); // (optional) Set custom properties of the ping ping_params.set_payload(b"Hello, Ping!"); // custom payload @@ -118,7 +118,7 @@ async fn main(spawner: Spawner) { Ok(time) => { info!("{} is online\n- latency: {}ms\n", ip_addr, time.as_millis()); total_online_hosts += 1; - }, + } _ => continue, } } -- cgit From 9b178facc95bc5fdcf43dddd0a2904e65fda41d6 Mon Sep 17 00:00:00 2001 From: skkeye Date: Mon, 10 Feb 2025 00:58:17 -0500 Subject: fix: update example --- examples/rp/src/bin/ethernet_w5500_icmp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index 5f336b579..5c42b2dde 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -117,7 +117,7 @@ async fn main(spawner: Spawner) { // Recieve and log the data of the reply socket - .recv_with(|(buf, addr)| { + .recv_from_with(|(buf, addr)| { let packet = Icmpv4Packet::new_checked(buf).unwrap(); info!( "Recieved {:?} from {} in {}ms", -- cgit From 52dfefb63242ad49fd126470042411f464fe624d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 10 Feb 2025 00:03:49 +0100 Subject: rp/pio: update pio-rs crate, reexport it so users don't get version mismatches. --- examples/rp/src/bin/pio_async.rs | 7 ++++--- examples/rp/src/bin/pio_dma.rs | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index ee248591b..08c702347 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; @@ -19,7 +20,7 @@ fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setup sm0 // Send data serially to pin - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 16", "set pindirs, 1", ".wrap_target", @@ -53,7 +54,7 @@ fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setupm sm1 // Read 0b10101 repeatedly until ISR is full - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( // ".origin 8", "set x, 0x15", @@ -83,7 +84,7 @@ fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, // Setup sm2 // Repeatedly trigger IRQ 3 - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 0", ".wrap_target", "set x,10", diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index 02700269c..d00ed2142 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -6,6 +6,7 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; use embassy_rp::peripherals::PIO0; +use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; @@ -32,7 +33,7 @@ async fn main(_spawner: Spawner) { .. } = Pio::new(pio, Irqs); - let prg = pio_proc::pio_asm!( + let prg = pio_asm!( ".origin 0", "set pindirs,1", ".wrap_target", -- cgit From 24941212e8130cddef974aab865bce4c7e294c33 Mon Sep 17 00:00:00 2001 From: eden barby <> Date: Sat, 1 Mar 2025 17:23:04 +1000 Subject: Added access to the byte swap flag for RP2*** chips for the PIO state machine DMA calls. --- examples/rp/src/bin/pio_dma.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index d00ed2142..da6e47a1b 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -72,8 +72,8 @@ async fn main(_spawner: Spawner) { loop { let (rx, tx) = sm.rx_tx(); join( - tx.dma_push(dma_out_ref.reborrow(), &dout), - rx.dma_pull(dma_in_ref.reborrow(), &mut din), + tx.dma_push(dma_out_ref.reborrow(), &dout, false), + rx.dma_pull(dma_in_ref.reborrow(), &mut din, false), ) .await; for i in 0..din.len() { -- cgit From d41eeeae79388f219bf6a84e2f7bde9f6b532516 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 26 Mar 2025 16:01:37 +0100 Subject: Remove Peripheral trait, rename PeripheralRef->Peri. --- examples/rp/src/bin/adc_dma.rs | 4 ++-- examples/rp/src/bin/assign_resources.rs | 7 ++++++- examples/rp/src/bin/blinky_two_channels.rs | 4 ++-- examples/rp/src/bin/blinky_two_tasks.rs | 4 ++-- examples/rp/src/bin/orchestrate_tasks.rs | 2 +- examples/rp/src/bin/pio_async.rs | 8 ++++---- examples/rp/src/bin/pio_dma.rs | 6 +++--- examples/rp/src/bin/pio_i2s.rs | 7 ++++++- examples/rp/src/bin/pwm.rs | 5 +++-- examples/rp/src/bin/shared_bus.rs | 6 +++--- examples/rp/src/bin/zerocopy.rs | 9 ++++++--- 11 files changed, 38 insertions(+), 24 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/adc_dma.rs b/examples/rp/src/bin/adc_dma.rs index f755cf5bf..b42c13fde 100644 --- a/examples/rp/src/bin/adc_dma.rs +++ b/examples/rp/src/bin/adc_dma.rs @@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) { // Read 100 samples from a single channel let mut buf = [0_u16; BLOCK_SIZE]; let div = 479; // 100kHz sample rate (48Mhz / 100kHz - 1) - adc.read_many(&mut pin, &mut buf, div, &mut dma).await.unwrap(); + adc.read_many(&mut pin, &mut buf, div, dma.reborrow()).await.unwrap(); info!("single: {:?} ...etc", buf[..8]); // Read 100 samples from 4 channels interleaved let mut buf = [0_u16; { BLOCK_SIZE * NUM_CHANNELS }]; let div = 119; // 100kHz sample rate (48Mhz / 100kHz * 4ch - 1) - adc.read_many_multichannel(&mut pins, &mut buf, div, &mut dma) + adc.read_many_multichannel(&mut pins, &mut buf, div, dma.reborrow()) .await .unwrap(); info!("multi: {:?} ...etc", buf[..NUM_CHANNELS * 2]); diff --git a/examples/rp/src/bin/assign_resources.rs b/examples/rp/src/bin/assign_resources.rs index ff6eff4a2..341f54d22 100644 --- a/examples/rp/src/bin/assign_resources.rs +++ b/examples/rp/src/bin/assign_resources.rs @@ -16,6 +16,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{self, PIN_20, PIN_21}; +use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -38,7 +39,11 @@ async fn main(spawner: Spawner) { // 1) Assigning a resource to a task by passing parts of the peripherals. #[embassy_executor::task] -async fn double_blinky_manually_assigned(_spawner: Spawner, pin_20: PIN_20, pin_21: PIN_21) { +async fn double_blinky_manually_assigned( + _spawner: Spawner, + pin_20: Peri<'static, PIN_20>, + pin_21: Peri<'static, PIN_21>, +) { let mut led_20 = Output::new(pin_20, Level::Low); let mut led_21 = Output::new(pin_21, Level::High); diff --git a/examples/rp/src/bin/blinky_two_channels.rs b/examples/rp/src/bin/blinky_two_channels.rs index b2eec2a21..51e139e94 100644 --- a/examples/rp/src/bin/blinky_two_channels.rs +++ b/examples/rp/src/bin/blinky_two_channels.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::{Channel, Sender}; use embassy_time::{Duration, Ticker}; -use gpio::{AnyPin, Level, Output}; +use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; enum LedState { @@ -22,7 +22,7 @@ static CHANNEL: Channel = Channel::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); - let mut led = Output::new(AnyPin::from(p.PIN_25), Level::High); + let mut led = Output::new(p.PIN_25, Level::High); let dt = 100 * 1_000_000; let k = 1.003; diff --git a/examples/rp/src/bin/blinky_two_tasks.rs b/examples/rp/src/bin/blinky_two_tasks.rs index a57b513d6..67a9108c0 100644 --- a/examples/rp/src/bin/blinky_two_tasks.rs +++ b/examples/rp/src/bin/blinky_two_tasks.rs @@ -11,7 +11,7 @@ use embassy_rp::gpio; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Ticker}; -use gpio::{AnyPin, Level, Output}; +use gpio::{Level, Output}; use {defmt_rtt as _, panic_probe as _}; type LedType = Mutex>>; @@ -21,7 +21,7 @@ static LED: LedType = Mutex::new(None); async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); // set the content of the global LED reference to the real LED pin - let led = Output::new(AnyPin::from(p.PIN_25), Level::High); + let led = Output::new(p.PIN_25, Level::High); // inner scope is so that once the mutex is written to, the MutexGuard is dropped, thus the // Mutex is released { diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 7ff004860..5e2775793 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -24,7 +24,7 @@ use embassy_futures::select::{select, Either}; use embassy_rp::adc::{Adc, Channel, Config, InterruptHandler}; use embassy_rp::clocks::RoscRng; use embassy_rp::gpio::{Input, Pull}; -use embassy_rp::{bind_interrupts, peripherals}; +use embassy_rp::{bind_interrupts, peripherals, Peri}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs index 08c702347..bf6dbee69 100644 --- a/examples/rp/src/bin/pio_async.rs +++ b/examples/rp/src/bin/pio_async.rs @@ -4,10 +4,10 @@ #![no_main] use defmt::info; use embassy_executor::Spawner; -use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine}; +use embassy_rp::{bind_interrupts, Peri}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; @@ -16,7 +16,7 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) { +fn setup_pio_task_sm0<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 0>, pin: Peri<'d, impl PioPin>) { // Setup sm0 // Send data serially to pin @@ -50,7 +50,7 @@ async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) { } } -fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) { +fn setup_pio_task_sm1<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 1>) { // Setupm sm1 // Read 0b10101 repeatedly until ISR is full @@ -80,7 +80,7 @@ async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) { } } -fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) { +fn setup_pio_task_sm2<'d>(pio: &mut Common<'d, PIO0>, sm: &mut StateMachine<'d, PIO0, 2>) { // Setup sm2 // Repeatedly trigger IRQ 3 diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs index da6e47a1b..64d603ba4 100644 --- a/examples/rp/src/bin/pio_dma.rs +++ b/examples/rp/src/bin/pio_dma.rs @@ -5,10 +5,10 @@ use defmt::info; use embassy_executor::Spawner; use embassy_futures::join::join; +use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::program::pio_asm; use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection}; -use embassy_rp::{bind_interrupts, Peripheral}; use fixed::traits::ToFixed; use fixed_macro::types::U56F8; use {defmt_rtt as _, panic_probe as _}; @@ -62,8 +62,8 @@ async fn main(_spawner: Spawner) { sm.set_config(&cfg); sm.set_enable(true); - let mut dma_out_ref = p.DMA_CH0.into_ref(); - let mut dma_in_ref = p.DMA_CH1.into_ref(); + let mut dma_out_ref = p.DMA_CH0; + let mut dma_in_ref = p.DMA_CH1; let mut dout = [0x12345678u32; 29]; for i in 1..dout.len() { dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7; diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index 447100ddf..192c8f854 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -14,6 +14,7 @@ use core::mem; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; +use embassy_rp::bootsel::is_bootsel_pressed; use embassy_rp::peripherals::PIO0; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_rp::pio_programs::i2s::{PioI2sOut, PioI2sOutProgram}; @@ -70,7 +71,11 @@ async fn main(_spawner: Spawner) { let dma_future = i2s.write(front_buffer); // fade in audio when bootsel is pressed - let fade_target = if p.BOOTSEL.is_pressed() { i32::MAX } else { 0 }; + let fade_target = if is_bootsel_pressed(p.BOOTSEL.reborrow()) { + i32::MAX + } else { + 0 + }; // fill back buffer with fresh audio samples before awaiting the dma future for s in back_buffer.iter_mut() { diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs index 2f5f94870..04374323d 100644 --- a/examples/rp/src/bin/pwm.rs +++ b/examples/rp/src/bin/pwm.rs @@ -11,6 +11,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::peripherals::{PIN_25, PIN_4, PWM_SLICE2, PWM_SLICE4}; use embassy_rp::pwm::{Config, Pwm, SetDutyCycle}; +use embassy_rp::Peri; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; @@ -26,7 +27,7 @@ async fn main(spawner: Spawner) { /// Using the onboard led, if You are using a different Board than plain Pico2 (i.e. W variant) /// you must use another slice & pin and an appropriate resistor. #[embassy_executor::task] -async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { +async fn pwm_set_config(slice4: Peri<'static, PWM_SLICE4>, pin25: Peri<'static, PIN_25>) { let mut c = Config::default(); c.top = 32_768; c.compare_b = 8; @@ -44,7 +45,7 @@ async fn pwm_set_config(slice4: PWM_SLICE4, pin25: PIN_25) { /// /// Using GP4 in Slice2, make sure to use an appropriate resistor. #[embassy_executor::task] -async fn pwm_set_dutycycle(slice2: PWM_SLICE2, pin4: PIN_4) { +async fn pwm_set_dutycycle(slice2: Peri<'static, PWM_SLICE2>, pin4: Peri<'static, PIN_4>) { // If we aim for a specific frequency, here is how we can calculate the top value. // The top value sets the period of the PWM cycle, so a counter goes from 0 to top and then wraps around to 0. // Every such wraparound is one PWM cycle. So here is how we get 25KHz: diff --git a/examples/rp/src/bin/shared_bus.rs b/examples/rp/src/bin/shared_bus.rs index c6cb5d64c..9267dfccb 100644 --- a/examples/rp/src/bin/shared_bus.rs +++ b/examples/rp/src/bin/shared_bus.rs @@ -8,7 +8,7 @@ use embassy_embedded_hal::shared_bus::asynch::i2c::I2cDevice; use embassy_embedded_hal::shared_bus::asynch::spi::SpiDevice; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; -use embassy_rp::gpio::{AnyPin, Level, Output}; +use embassy_rp::gpio::{Level, Output}; use embassy_rp::i2c::{self, I2c, InterruptHandler}; use embassy_rp::peripherals::{I2C1, SPI1}; use embassy_rp::spi::{self, Spi}; @@ -45,8 +45,8 @@ async fn main(spawner: Spawner) { let spi_bus = SPI_BUS.init(Mutex::new(spi)); // Chip select pins for the SPI devices - let cs_a = Output::new(AnyPin::from(p.PIN_0), Level::High); - let cs_b = Output::new(AnyPin::from(p.PIN_1), Level::High); + let cs_a = Output::new(p.PIN_0, Level::High); + let cs_b = Output::new(p.PIN_1, Level::High); spawner.must_spawn(spi_task_a(spi_bus, cs_a)); spawner.must_spawn(spi_task_b(spi_bus, cs_b)); diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs index 39f03c8e4..d1fb0eb00 100644 --- a/examples/rp/src/bin/zerocopy.rs +++ b/examples/rp/src/bin/zerocopy.rs @@ -9,9 +9,9 @@ use core::sync::atomic::{AtomicU16, Ordering}; use defmt::*; use embassy_executor::Spawner; use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; -use embassy_rp::bind_interrupts; use embassy_rp::gpio::Pull; use embassy_rp::peripherals::DMA_CH0; +use embassy_rp::{bind_interrupts, Peri}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; use embassy_time::{Duration, Ticker, Timer}; @@ -31,7 +31,7 @@ static MAX: AtomicU16 = AtomicU16::new(0); struct AdcParts { adc: Adc<'static, Async>, pin: adc::Channel<'static>, - dma: DMA_CH0, + dma: Peri<'static, DMA_CH0>, } #[embassy_executor::main] @@ -70,7 +70,10 @@ async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut a let buf = sender.send().await; // Fill it with data - adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap(); + adc.adc + .read_many(&mut adc.pin, buf, 1, adc.dma.reborrow()) + .await + .unwrap(); // Notify the channel that the buffer is now ready to be received sender.send_done(); -- cgit From f1feedf19031d0c007628569add51ff89ae08447 Mon Sep 17 00:00:00 2001 From: Michael Gomez Date: Wed, 19 Mar 2025 20:44:16 -0700 Subject: BufferedUart initialization This change modifies UART initialization throughout Embassy to take pins before interrupts. Related to #1304. --- examples/rp/src/bin/uart_buffered_split.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index 468d2b61a..da7e94139 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs @@ -30,7 +30,7 @@ async fn main(spawner: Spawner) { let tx_buf = &mut TX_BUF.init([0; 16])[..]; static RX_BUF: StaticCell<[u8; 16]> = StaticCell::new(); let rx_buf = &mut RX_BUF.init([0; 16])[..]; - let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default()); + let uart = BufferedUart::new(uart, tx_pin, rx_pin, Irqs, tx_buf, rx_buf, Config::default()); let (mut tx, rx) = uart.split(); unwrap!(spawner.spawn(reader(rx))); -- cgit From 608fe44a43a527beef946c4e087008f549e3f3e5 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 11 Apr 2025 13:57:41 +0200 Subject: remove incompatible device classes and protocol from RP webusb example --- examples/rp/src/bin/usb_webusb.rs | 6 ------ 1 file changed, 6 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/usb_webusb.rs b/examples/rp/src/bin/usb_webusb.rs index e73938ac9..a5dc94d5b 100644 --- a/examples/rp/src/bin/usb_webusb.rs +++ b/examples/rp/src/bin/usb_webusb.rs @@ -51,12 +51,6 @@ async fn main(_spawner: Spawner) { config.max_power = 100; config.max_packet_size_0 = 64; - // Required for windows compatibility. - // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help - config.device_class = 0xff; - config.device_sub_class = 0x00; - config.device_protocol = 0x00; - // Create embassy-usb DeviceBuilder using the driver and config. // It needs some buffers for building the descriptors. let mut config_descriptor = [0; 256]; -- cgit From 642740b8cbff7099e452337c8fcb6fd78eb0567e Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sun, 13 Apr 2025 22:33:10 +0200 Subject: update WiFi credentials to placeholders --- examples/rp/src/bin/wifi_tcp_server.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 14dbf4552..7e3c663fe 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -28,8 +28,8 @@ bind_interrupts!(struct Irqs { PIO0_IRQ_0 => InterruptHandler; }); -const WIFI_NETWORK: &str = "LadronDeWifi"; -const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; +const WIFI_NETWORK: &str = "ssid"; // change to your network SSID +const WIFI_PASSWORD: &str = "pwd"; // change to your network password #[embassy_executor::task] async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { -- cgit From 6a6e4216522508450f51748f210a0db7277d4eee Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Tue, 15 Apr 2025 17:43:18 +0800 Subject: rp: i2c-slave example: fix twice-swapped sda/scl sda and scl were swapped twice. The code worked, but would be confusing trying to interface with pins externally. --- examples/rp/src/bin/i2c_slave.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/i2c_slave.rs b/examples/rp/src/bin/i2c_slave.rs index 9fffb4646..08f31001b 100644 --- a/examples/rp/src/bin/i2c_slave.rs +++ b/examples/rp/src/bin/i2c_slave.rs @@ -99,19 +99,19 @@ async fn main(spawner: Spawner) { let p = embassy_rp::init(Default::default()); info!("Hello World!"); - let d_sda = p.PIN_3; - let d_scl = p.PIN_2; + let d_sda = p.PIN_2; + let d_scl = p.PIN_3; let mut config = i2c_slave::Config::default(); config.addr = DEV_ADDR as u16; - let device = i2c_slave::I2cSlave::new(p.I2C1, d_sda, d_scl, Irqs, config); + let device = i2c_slave::I2cSlave::new(p.I2C1, d_scl, d_sda, Irqs, config); unwrap!(spawner.spawn(device_task(device))); - let c_sda = p.PIN_1; - let c_scl = p.PIN_0; + let c_sda = p.PIN_0; + let c_scl = p.PIN_1; let mut config = i2c::Config::default(); config.frequency = 1_000_000; - let controller = i2c::I2c::new_async(p.I2C0, c_sda, c_scl, Irqs, config); + let controller = i2c::I2c::new_async(p.I2C0, c_scl, c_sda, Irqs, config); unwrap!(spawner.spawn(controller_task(controller))); } -- cgit From cd27a8a06b0160d654ebed7b89ca473041710235 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 25 Apr 2025 00:43:46 +0200 Subject: Updated the pio onewire example --- examples/rp/src/bin/pio_onewire.rs | 102 +++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 49 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs index 991510851..379e2b8f9 100644 --- a/examples/rp/src/bin/pio_onewire.rs +++ b/examples/rp/src/bin/pio_onewire.rs @@ -1,4 +1,4 @@ -//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. +//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. #![no_std] #![no_main] @@ -6,9 +6,10 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::bind_interrupts; use embassy_rp::peripherals::PIO0; -use embassy_rp::pio::{self, InterruptHandler, Pio}; -use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; +use embassy_rp::pio::{InterruptHandler, Pio}; +use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch}; use embassy_time::Timer; +use heapless::Vec; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -21,63 +22,66 @@ async fn main(_spawner: Spawner) { let mut pio = Pio::new(p.PIO0, Irqs); let prg = PioOneWireProgram::new(&mut pio.common); - let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); + let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); - let mut sensor = Ds18b20::new(onewire); + info!("Starting onewire search"); - loop { - sensor.start().await; // Start a new measurement - Timer::after_secs(1).await; // Allow 1s for the measurement to finish - match sensor.temperature().await { - Ok(temp) => info!("temp = {:?} deg C", temp), - _ => error!("sensor error"), + let mut devices = Vec::::new(); + let mut search = PioOneWireSearch::new(); + for _ in 0..10 { + if !search.is_finished() { + if let Some(address) = search.next(&mut onewire).await { + if crc8(&address.to_le_bytes()) == 0 { + info!("Found addres: {:x}", address); + let _ = devices.push(address); + } else { + warn!("Found invalid address: {:x}", address); + } + } } - Timer::after_secs(1).await; } -} -/// DS18B20 temperature sensor driver -pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> { - wire: PioOneWire<'d, PIO, SM>, -} + info!("Search done, found {} devices", devices.len()); -impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { - pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { - Self { wire } - } + loop { + onewire.reset().await; + // Skip rom and trigger conversion, we can trigger all devices on the bus immediately + onewire.write_bytes(&[0xCC, 0x44]).await; - /// Calculate CRC8 of the data - fn crc8(data: &[u8]) -> u8 { - let mut temp; - let mut data_byte; - let mut crc = 0; - for b in data { - data_byte = *b; - for _ in 0..8 { - temp = (crc ^ data_byte) & 0x01; - crc >>= 1; - if temp != 0 { - crc ^= 0x8C; - } - data_byte >>= 1; + Timer::after_secs(1).await; // Allow 1s for the measurement to finish + + // Read all devices one by one + for device in &devices { + onewire.reset().await; + onewire.write_bytes(&[0x55]).await; // Match rom + onewire.write_bytes(&device.to_le_bytes()).await; + onewire.write_bytes(&[0xBE]).await; // Read scratchpad + + let mut data = [0; 9]; + onewire.read_bytes(&mut data).await; + if crc8(&data) == 0 { + let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.; + info!("Read device {:x}: {} deg C", device, temp); + } else { + warn!("Reading device {:x} failed", device); } } - crc - } - - /// Start a new measurement. Allow at least 1000ms before getting `temperature`. - pub async fn start(&mut self) { - self.wire.write_bytes(&[0xCC, 0x44]).await; + Timer::after_secs(1).await; } +} - /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. - pub async fn temperature(&mut self) -> Result { - self.wire.write_bytes(&[0xCC, 0xBE]).await; - let mut data = [0; 9]; - self.wire.read_bytes(&mut data).await; - match Self::crc8(&data) == 0 { - true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), - false => Err(()), +fn crc8(data: &[u8]) -> u8 { + let mut crc = 0; + for b in data { + let mut data_byte = *b; + for _ in 0..8 { + let temp = (crc ^ data_byte) & 0x01; + crc >>= 1; + if temp != 0 { + crc ^= 0x8C; + } + data_byte >>= 1; } } + crc } -- cgit From b0594d16f238f803a0192810833ae2b0c3941ec3 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sat, 26 Apr 2025 22:55:24 +0200 Subject: Add overclock example for RP2040 with 200 MHz clock configuration --- examples/rp/src/bin/overclock.rs | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 examples/rp/src/bin/overclock.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs new file mode 100644 index 000000000..429fff1ac --- /dev/null +++ b/examples/rp/src/bin/overclock.rs @@ -0,0 +1,60 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Level, Output}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +const COUNT_TO: i32 = 1_000_000; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + // Set up for clock frequency of 200 MHz + // We will need a clock config in the HAL config that supports this frequency + // The RP2040 can run at 200 MHz with a 12 MHz crystal + let config = Config::new(ClockConfig::crystal_freq(12_000_000, 200_000_000)); + + // Initialize the peripherals + let p = embassy_rp::init(config); + + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); + info!("System clock frequency: {} Hz", sys_freq); + + // LED to indicate the system is running + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + // Reset the counter at the start of measurement period + let mut counter = 0; + + // Turn LED on while counting + led.set_high(); + + let start = Instant::now(); + + // Count to COUNT_TO + // This is a busy loop that will take some time to complete + while counter < COUNT_TO { + counter += 1; + } + + let elapsed = start - Instant::now(); + + // Report the elapsed time + led.set_low(); + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + sys_freq / 1_000_000, + COUNT_TO, + elapsed.as_millis() + ); + + // Wait 2 seconds before starting the next measurement + Timer::after(Duration::from_secs(2)).await; + } +} -- cgit From 3a6dc910ffc66d4a30b89f299432b383271a719f Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 28 Apr 2025 22:54:15 +0200 Subject: first working draft --- examples/rp/src/bin/overclock.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 429fff1ac..db6c8f448 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -3,22 +3,18 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::clocks::{clk_sys_freq, ClockConfig, VoltageScale}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; use {defmt_rtt as _, panic_probe as _}; -const COUNT_TO: i32 = 1_000_000; +const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz - // We will need a clock config in the HAL config that supports this frequency - // The RP2040 can run at 200 MHz with a 12 MHz crystal - let config = Config::new(ClockConfig::crystal_freq(12_000_000, 200_000_000)); - - // Initialize the peripherals + let config = Config::new(ClockConfig::with_speed_mhz(200)); let p = embassy_rp::init(config); // Show CPU frequency for verification @@ -37,20 +33,19 @@ async fn main(_spawner: Spawner) -> ! { let start = Instant::now(); - // Count to COUNT_TO // This is a busy loop that will take some time to complete while counter < COUNT_TO { counter += 1; } - let elapsed = start - Instant::now(); + let elapsed = Instant::now() - start; // Report the elapsed time led.set_low(); info!( "At {}Mhz: Elapsed time to count to {}: {}ms", sys_freq / 1_000_000, - COUNT_TO, + counter, elapsed.as_millis() ); @@ -58,3 +53,14 @@ async fn main(_spawner: Spawner) -> ! { Timer::after(Duration::from_secs(2)).await; } } + +// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage(125, Some(VoltageScale::V1_10))); +// let config = Config::default(); +// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage_extended_delay( +// 200, // Standard 125MHz clock +// Some(VoltageScale::V1_15), // 1.15V voltage +// Some(1000), // 1000μs (1ms) stabilization delay - significantly longer than default +// )); +// Initialize the peripherals + +// let p = embassy_rp::init(Default::default()); //testing the bog standard -- cgit From 77e8bc9b28d6988b2703029679f290b351fc54a0 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Tue, 29 Apr 2025 22:49:05 +0200 Subject: refactoring to have higher and lower level api --- examples/rp/src/bin/overclock.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index db6c8f448..9027f1516 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -14,7 +14,18 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz - let config = Config::new(ClockConfig::with_speed_mhz(200)); + // This will set all the necessary defaults including slightly raised voltage + // See embassy_rp::clocks::ClockConfig for more options, including full manual control + let config = Config::new(ClockConfig::at_sys_frequency_mhz(200)); + + // Show the voltage scale and brownout-detection for verification + info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); + // info!( + // "Brownout detection: {}", + // Debug2Format(&config.clocks.brownout_detection) + // ); + + // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification -- cgit From 22b5f73811a7cc0dbca920e02b5d001d252d344c Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Thu, 1 May 2025 00:11:56 +0200 Subject: add manual overclock example, finalize API, cleanup --- examples/rp/src/bin/overclock.rs | 24 +++------- examples/rp/src/bin/overclock_manual.rs | 81 +++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 18 deletions(-) create mode 100644 examples/rp/src/bin/overclock_manual.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 9027f1516..e3ac77340 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -1,9 +1,13 @@ +//! # Overclocking the RP2040 to 200 MHz +//! +//! This example demonstrates how to configure the RP2040 to run at 200 MHz using a higher level API. + #![no_std] #![no_main] use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig, VoltageScale}; +use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -15,15 +19,10 @@ const COUNT_TO: i64 = 10_000_000; async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz // This will set all the necessary defaults including slightly raised voltage - // See embassy_rp::clocks::ClockConfig for more options, including full manual control let config = Config::new(ClockConfig::at_sys_frequency_mhz(200)); - // Show the voltage scale and brownout-detection for verification + // Show the voltage scale for verification info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); - // info!( - // "Brownout detection: {}", - // Debug2Format(&config.clocks.brownout_detection) - // ); // Initialize the peripherals let p = embassy_rp::init(config); @@ -64,14 +63,3 @@ async fn main(_spawner: Spawner) -> ! { Timer::after(Duration::from_secs(2)).await; } } - -// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage(125, Some(VoltageScale::V1_10))); -// let config = Config::default(); -// let config = Config::new(ClockConfig::with_speed_mhz_test_voltage_extended_delay( -// 200, // Standard 125MHz clock -// Some(VoltageScale::V1_15), // 1.15V voltage -// Some(1000), // 1000μs (1ms) stabilization delay - significantly longer than default -// )); -// Initialize the peripherals - -// let p = embassy_rp::init(Default::default()); //testing the bog standard diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs new file mode 100644 index 000000000..ad6abf0e7 --- /dev/null +++ b/examples/rp/src/bin/overclock_manual.rs @@ -0,0 +1,81 @@ +//! # Overclocking the RP2040 to 200 MHz manually +//! +//! This example demonstrates how to manually configure the RP2040 to run at 200 MHz. + +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_rp::clocks; +use embassy_rp::clocks::{ClockConfig, PllConfig, VoltageScale}; +use embassy_rp::config::Config; +use embassy_rp::gpio::{Level, Output}; +use embassy_time::{Duration, Instant, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +const COUNT_TO: i64 = 10_000_000; + +/// Configure the RP2040 for 200 MHz operation by manually specifying +/// all the required parameters instead of using higher-level APIs. +fn configure_manual_overclock() -> Config { + // Set the PLL configuration manually, starting from default values + let mut config = Config::default(); + + // Set the system clock to 200 MHz using a PLL with a reference frequency of 12 MHz + config.clocks = ClockConfig::manual_pll( + 12_000_000, + PllConfig { + refdiv: 1, + fbdiv: 100, + post_div1: 3, + post_div2: 2, + }, + // For 200 MHz, we need a voltage scale of 1.15V + Some(VoltageScale::V1_15), + ); + + config +} + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + // Initialize with our manual overclock configuration + let p = embassy_rp::init(configure_manual_overclock()); + + // Verify the actual system clock frequency + let sys_freq = clocks::clk_sys_freq(); + info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + + // LED to indicate the system is running + let mut led = Output::new(p.PIN_25, Level::Low); + + loop { + // Reset the counter at the start of measurement period + let mut counter = 0; + + // Turn LED on while counting + led.set_high(); + + let start = Instant::now(); + + // This is a busy loop that will take some time to complete + while counter < COUNT_TO { + counter += 1; + } + + let elapsed = Instant::now() - start; + + // Report the elapsed time + led.set_low(); + info!( + "At {}Mhz: Elapsed time to count to {}: {}ms", + sys_freq / 1_000_000, + counter, + elapsed.as_millis() + ); + + // Wait 2 seconds before starting the next measurement + Timer::after(Duration::from_secs(2)).await; + } +} -- cgit From 1efe59ec475aa38948d1fc95feb34860f08c8dcd Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 12:52:04 +0200 Subject: Update examples and tests --- examples/rp/src/bin/uart_buffered_split.rs | 2 +- examples/rp/src/bin/uart_unidir.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs index da7e94139..3adbc18ab 100644 --- a/examples/rp/src/bin/uart_buffered_split.rs +++ b/examples/rp/src/bin/uart_buffered_split.rs @@ -48,7 +48,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: BufferedUartRx<'static, UART0>) { +async fn reader(mut rx: BufferedUartRx) { info!("Reading..."); loop { let mut buf = [0; 31]; diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs index a45f40756..c2c8dfad8 100644 --- a/examples/rp/src/bin/uart_unidir.rs +++ b/examples/rp/src/bin/uart_unidir.rs @@ -39,7 +39,7 @@ async fn main(spawner: Spawner) { } #[embassy_executor::task] -async fn reader(mut rx: UartRx<'static, UART1, Async>) { +async fn reader(mut rx: UartRx<'static, Async>) { info!("Reading..."); loop { // read a total of 4 transmissions (32 / 8) and then print the result -- cgit From 8f3b6643b311a5a16fe6a64227066627990452b9 Mon Sep 17 00:00:00 2001 From: Marc <35759328+marcemmers@users.noreply.github.com> Date: Fri, 2 May 2025 14:36:08 +0200 Subject: And another fix, should be the last failing example --- examples/rp/src/bin/sharing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs index 5416e20ce..497c4f845 100644 --- a/examples/rp/src/bin/sharing.rs +++ b/examples/rp/src/bin/sharing.rs @@ -31,7 +31,7 @@ use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; -type UartAsyncMutex = mutex::Mutex>; +type UartAsyncMutex = mutex::Mutex>; struct MyType { inner: u32, -- cgit From 3441e805070c7efb7cad20a84d1986e215b4de3d Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Fri, 2 May 2025 23:51:28 +0200 Subject: first batch of changes after review --- examples/rp/src/bin/overclock.rs | 11 +++++------ examples/rp/src/bin/overclock_manual.rs | 20 +++++++++----------- 2 files changed, 14 insertions(+), 17 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index e3ac77340..f9a8c94d0 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -1,6 +1,6 @@ //! # Overclocking the RP2040 to 200 MHz //! -//! This example demonstrates how to configure the RP2040 to run at 200 MHz using a higher level API. +//! This example demonstrates how to configure the RP2040 to run at 200 MHz. #![no_std] #![no_main] @@ -17,19 +17,18 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { - // Set up for clock frequency of 200 MHz - // This will set all the necessary defaults including slightly raised voltage - let config = Config::new(ClockConfig::at_sys_frequency_mhz(200)); + // Set up for clock frequency of 200 MHz, setting all necessary defaults. + let config = Config::new(ClockConfig::crystal_freq(200_000_000)); // Show the voltage scale for verification - info!("System core voltage: {}", Debug2Format(&config.clocks.voltage_scale)); + info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification let sys_freq = clk_sys_freq(); - info!("System clock frequency: {} Hz", sys_freq); + info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index ad6abf0e7..35160b250 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -8,7 +8,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_rp::clocks; -use embassy_rp::clocks::{ClockConfig, PllConfig, VoltageScale}; +use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -16,23 +16,21 @@ use {defmt_rtt as _, panic_probe as _}; const COUNT_TO: i64 = 10_000_000; -/// Configure the RP2040 for 200 MHz operation by manually specifying -/// all the required parameters instead of using higher-level APIs. +/// Configure the RP2040 for 200 MHz operation by manually specifying the PLL settings. fn configure_manual_overclock() -> Config { // Set the PLL configuration manually, starting from default values let mut config = Config::default(); - // Set the system clock to 200 MHz using a PLL with a reference frequency of 12 MHz + // Set the system clock to 200 MHz config.clocks = ClockConfig::manual_pll( - 12_000_000, + 12_000_000, // Crystal frequency, 12 MHz is common. If using custom, set to your value. PllConfig { - refdiv: 1, - fbdiv: 100, - post_div1: 3, - post_div2: 2, + refdiv: 1, // Reference divider + fbdiv: 100, // Feedback divider + post_div1: 3, // Post divider 1 + post_div2: 2, // Post divider 2 }, - // For 200 MHz, we need a voltage scale of 1.15V - Some(VoltageScale::V1_15), + CoreVoltage::V1_15, // Core voltage, should be set to V1_15 for 200 MHz ); config -- cgit From a254daf4fffe74c65d1846f620dd674fa4e14aac Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Wed, 7 May 2025 21:19:09 +0200 Subject: Changes after review --- examples/rp/src/bin/overclock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index f9a8c94d0..9c78e0c9d 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -18,7 +18,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let config = Config::new(ClockConfig::crystal_freq(200_000_000)); + let config = Config::new(ClockConfig::system_freq(200_000_000)); // Show the voltage scale for verification info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); -- cgit From 4567beda7b7773c8cb11f19f0f4f146c1243508d Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Sun, 11 May 2025 17:26:36 +0200 Subject: rp235x overclocking --- examples/rp/src/bin/overclock.rs | 8 ++++---- examples/rp/src/bin/overclock_manual.rs | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 9c78e0c9d..89147ba42 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -7,7 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks::{clk_sys_freq, ClockConfig}; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -20,15 +20,15 @@ async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. let config = Config::new(ClockConfig::system_freq(200_000_000)); - // Show the voltage scale for verification - info!("System core voltage: {}", Debug2Format(&config.clocks.core_voltage)); - // Initialize the peripherals let p = embassy_rp::init(config); // Show CPU frequency for verification let sys_freq = clk_sys_freq(); info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index 35160b250..88ef26a7a 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -7,8 +7,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_rp::clocks; -use embassy_rp::clocks::{ClockConfig, CoreVoltage, PllConfig}; +use embassy_rp::clocks::{clk_sys_freq, core_voltage, ClockConfig, CoreVoltage, PllConfig}; use embassy_rp::config::Config; use embassy_rp::gpio::{Level, Output}; use embassy_time::{Duration, Instant, Timer}; @@ -41,9 +40,12 @@ async fn main(_spawner: Spawner) -> ! { // Initialize with our manual overclock configuration let p = embassy_rp::init(configure_manual_overclock()); - // Verify the actual system clock frequency - let sys_freq = clocks::clk_sys_freq(); + // Show CPU frequency for verification + let sys_freq = clk_sys_freq(); info!("System clock frequency: {} MHz", sys_freq / 1_000_000); + // Show core voltage for verification + let core_voltage = core_voltage().unwrap(); + info!("Core voltage: {}", Debug2Format(&core_voltage)); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); -- cgit From 79e452922a6b467f2e8547a6b28698ed5f409705 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:33:47 +0200 Subject: Add ClockError enum and update system_freq to return Result for error handling --- examples/rp/src/bin/overclock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 89147ba42..2706399af 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -18,7 +18,7 @@ const COUNT_TO: i64 = 10_000_000; #[embassy_executor::main] async fn main(_spawner: Spawner) -> ! { // Set up for clock frequency of 200 MHz, setting all necessary defaults. - let config = Config::new(ClockConfig::system_freq(200_000_000)); + let config = Config::new(ClockConfig::system_freq(200_000_000).unwrap()); // Initialize the peripherals let p = embassy_rp::init(config); -- cgit From abafbed0d5fba70ab5d0096b9d381577d2f880c8 Mon Sep 17 00:00:00 2001 From: 1-rafael-1 Date: Mon, 12 May 2025 21:43:17 +0200 Subject: remove Debug2Fmt from examples --- examples/rp/src/bin/overclock.rs | 2 +- examples/rp/src/bin/overclock_manual.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/overclock.rs b/examples/rp/src/bin/overclock.rs index 2706399af..83b17308b 100644 --- a/examples/rp/src/bin/overclock.rs +++ b/examples/rp/src/bin/overclock.rs @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); diff --git a/examples/rp/src/bin/overclock_manual.rs b/examples/rp/src/bin/overclock_manual.rs index 88ef26a7a..dea5cfb3c 100644 --- a/examples/rp/src/bin/overclock_manual.rs +++ b/examples/rp/src/bin/overclock_manual.rs @@ -45,7 +45,7 @@ async fn main(_spawner: Spawner) -> ! { info!("System clock frequency: {} MHz", sys_freq / 1_000_000); // Show core voltage for verification let core_voltage = core_voltage().unwrap(); - info!("Core voltage: {}", Debug2Format(&core_voltage)); + info!("Core voltage: {}", core_voltage); // LED to indicate the system is running let mut led = Output::new(p.PIN_25, Level::Low); -- cgit From fd9ed3924c5a7c4ef4f9bc4b8a4f934ad2bcc486 Mon Sep 17 00:00:00 2001 From: Marvin Gudel Date: Tue, 13 May 2025 22:49:35 +0200 Subject: Fix example --- examples/rp/src/bin/pio_i2s.rs | 2 -- 1 file changed, 2 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/pio_i2s.rs b/examples/rp/src/bin/pio_i2s.rs index 192c8f854..695a74cc3 100644 --- a/examples/rp/src/bin/pio_i2s.rs +++ b/examples/rp/src/bin/pio_i2s.rs @@ -27,7 +27,6 @@ bind_interrupts!(struct Irqs { const SAMPLE_RATE: u32 = 48_000; const BIT_DEPTH: u32 = 16; -const CHANNELS: u32 = 2; #[embassy_executor::main] async fn main(_spawner: Spawner) { @@ -50,7 +49,6 @@ async fn main(_spawner: Spawner) { left_right_clock_pin, SAMPLE_RATE, BIT_DEPTH, - CHANNELS, &program, ); -- cgit From 117eb45fa0829239da9152b9cf54c3cf706dc76d Mon Sep 17 00:00:00 2001 From: Ralph Ursprung Date: Thu, 15 May 2025 17:53:31 +0200 Subject: add the possibility to document `bind_interrupts` `struct`s the `bind_interrupts` macro creates a `struct` for the interrupts. it was so far not possible to document those (except for STM32) and there was no generic documentation being generated/added either, thus the `missing_docs` lint was triggered for consumers which enabled it. with this change it is now possible to manually add a comment on the `struct` being defined in the macro invocation. to show that this works one RP example has been modified accordingly. --- examples/rp/src/bin/adc.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs index 1bb7c2249..015915586 100644 --- a/examples/rp/src/bin/adc.rs +++ b/examples/rp/src/bin/adc.rs @@ -12,9 +12,12 @@ use embassy_rp::gpio::Pull; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; -bind_interrupts!(struct Irqs { - ADC_IRQ_FIFO => InterruptHandler; -}); +bind_interrupts!( + /// Binds the ADC interrupts. + struct Irqs { + ADC_IRQ_FIFO => InterruptHandler; + } +); #[embassy_executor::main] async fn main(_spawner: Spawner) { -- cgit From e4fc48764491f8981e4a145a72e9b6e72df8c546 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 18 May 2025 20:32:48 +0200 Subject: Add rand-core v0.9 support. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Aurélien Jacobs --- examples/rp/src/bin/ethernet_w5500_icmp.rs | 1 - examples/rp/src/bin/ethernet_w5500_icmp_ping.rs | 1 - examples/rp/src/bin/ethernet_w5500_multisocket.rs | 1 - examples/rp/src/bin/ethernet_w5500_tcp_client.rs | 1 - examples/rp/src/bin/ethernet_w5500_tcp_server.rs | 1 - examples/rp/src/bin/ethernet_w5500_udp.rs | 1 - examples/rp/src/bin/orchestrate_tasks.rs | 1 - examples/rp/src/bin/sharing.rs | 1 - examples/rp/src/bin/spi_gc9a01.rs | 1 - examples/rp/src/bin/usb_ethernet.rs | 1 - examples/rp/src/bin/usb_hid_mouse.rs | 4 ++-- examples/rp/src/bin/wifi_ap_tcp_server.rs | 1 - examples/rp/src/bin/wifi_tcp_server.rs | 1 - examples/rp/src/bin/wifi_webrequest.rs | 1 - 14 files changed, 2 insertions(+), 15 deletions(-) mode change 100644 => 100755 examples/rp/src/bin/usb_hid_mouse.rs (limited to 'examples/rp/src') diff --git a/examples/rp/src/bin/ethernet_w5500_icmp.rs b/examples/rp/src/bin/ethernet_w5500_icmp.rs index 5c42b2dde..e434b3bbc 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp.rs @@ -21,7 +21,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Instant, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs index 0724311f9..0ec594fd5 100644 --- a/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs +++ b/examples/rp/src/bin/ethernet_w5500_icmp_ping.rs @@ -23,7 +23,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index 2bea9fc9d..27e2f3c30 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs @@ -18,7 +18,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index 78d1b0b83..ba82f2a60 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs @@ -20,7 +20,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration, Timer}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 25a38c714..5c56dcafa 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs @@ -19,7 +19,6 @@ use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::{Delay, Duration}; use embedded_hal_bus::spi::ExclusiveDevice; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 683e29222..c5fc8de1d 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs @@ -18,7 +18,6 @@ use embassy_rp::peripherals::SPI0; use embassy_rp::spi::{Async, Config as SpiConfig, Spi}; use embassy_time::Delay; use embedded_hal_bus::spi::ExclusiveDevice; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/orchestrate_tasks.rs b/examples/rp/src/bin/orchestrate_tasks.rs index 5e2775793..c35679251 100644 --- a/examples/rp/src/bin/orchestrate_tasks.rs +++ b/examples/rp/src/bin/orchestrate_tasks.rs @@ -29,7 +29,6 @@ use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::{channel, signal}; use embassy_time::{Duration, Timer}; -use rand::RngCore; use {defmt_rtt as _, panic_probe as _}; // Hardware resource assignment. See other examples for different ways of doing this. diff --git a/examples/rp/src/bin/sharing.rs b/examples/rp/src/bin/sharing.rs index 497c4f845..856be6ace 100644 --- a/examples/rp/src/bin/sharing.rs +++ b/examples/rp/src/bin/sharing.rs @@ -27,7 +27,6 @@ use embassy_rp::{bind_interrupts, interrupt}; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::{blocking_mutex, mutex}; use embassy_time::{Duration, Ticker}; -use rand::RngCore; use static_cell::{ConstStaticCell, StaticCell}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/spi_gc9a01.rs b/examples/rp/src/bin/spi_gc9a01.rs index 30afc253d..fdef09d4b 100644 --- a/examples/rp/src/bin/spi_gc9a01.rs +++ b/examples/rp/src/bin/spi_gc9a01.rs @@ -26,7 +26,6 @@ use embedded_graphics::primitives::{PrimitiveStyleBuilder, Rectangle}; use mipidsi::models::GC9A01; use mipidsi::options::{ColorInversion, ColorOrder}; use mipidsi::Builder; -use rand_core::RngCore; use {defmt_rtt as _, panic_probe as _}; const DISPLAY_FREQ: u32 = 64_000_000; diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs index 2add20bc6..171f21a75 100644 --- a/examples/rp/src/bin/usb_ethernet.rs +++ b/examples/rp/src/bin/usb_ethernet.rs @@ -17,7 +17,6 @@ use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState use embassy_usb::class::cdc_ncm::{CdcNcmClass, State}; use embassy_usb::{Builder, Config, UsbDevice}; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/usb_hid_mouse.rs b/examples/rp/src/bin/usb_hid_mouse.rs old mode 100644 new mode 100755 index 5ee650910..4454c593c --- a/examples/rp/src/bin/usb_hid_mouse.rs +++ b/examples/rp/src/bin/usb_hid_mouse.rs @@ -85,8 +85,8 @@ async fn main(_spawner: Spawner) { _ = Timer::after_secs(1).await; let report = MouseReport { buttons: 0, - x: rng.gen_range(-100..100), // random small x movement - y: rng.gen_range(-100..100), // random small y movement + x: rng.random_range(-100..100), // random small x movement + y: rng.random_range(-100..100), // random small y movement wheel: 0, pan: 0, }; diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index e97ddb4c1..856838a8c 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -19,7 +19,6 @@ use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::Duration; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 7e3c663fe..fbc957e0e 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -20,7 +20,6 @@ use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; use embedded_io_async::Write; -use rand::RngCore; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index f1b398b65..1efd1cd28 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs @@ -20,7 +20,6 @@ use embassy_rp::gpio::{Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIO0}; use embassy_rp::pio::{InterruptHandler, Pio}; use embassy_time::{Duration, Timer}; -use rand::RngCore; use reqwless::client::{HttpClient, TlsConfig, TlsVerify}; use reqwless::request::Method; use serde::Deserialize; -- cgit