aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/lpc55s69/Cargo.toml2
-rw-r--r--examples/mspm0c1104/Cargo.toml3
-rw-r--r--examples/nrf52840-edf/.cargo/config.toml9
-rw-r--r--examples/nrf52840-edf/Cargo.toml27
-rw-r--r--examples/nrf52840-edf/build.rs35
-rw-r--r--examples/nrf52840-edf/memory.x12
-rw-r--r--examples/nrf52840-edf/src/bin/basic.rs194
-rw-r--r--examples/nrf52840-rtic/src/bin/blinky.rs1
-rw-r--r--examples/nrf52840/Cargo.toml4
-rw-r--r--examples/nrf52840/src/bin/sixlowpan.rs120
-rw-r--r--examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs155
-rw-r--r--examples/rp/src/bin/pio_onewire.rs1
-rw-r--r--examples/rp/src/bin/pio_onewire_parasite.rs89
-rw-r--r--examples/rp235x/src/bin/pio_onewire.rs103
-rw-r--r--examples/rp235x/src/bin/pio_onewire_parasite.rs89
-rw-r--r--examples/stm32f7/src/bin/qspi.rs16
-rw-r--r--examples/stm32h742/src/bin/qspi.rs16
-rw-r--r--examples/stm32l432/src/bin/qspi_mmap.rs16
18 files changed, 813 insertions, 79 deletions
diff --git a/examples/lpc55s69/Cargo.toml b/examples/lpc55s69/Cargo.toml
index 79b27f269..579748595 100644
--- a/examples/lpc55s69/Cargo.toml
+++ b/examples/lpc55s69/Cargo.toml
@@ -7,7 +7,7 @@ license = "MIT OR Apache-2.0"
7publish = false 7publish = false
8 8
9[dependencies] 9[dependencies]
10embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55", "rt", "defmt", "time-driver-rtc"] } 10embassy-nxp = { version = "0.1.0", path = "../../embassy-nxp", features = ["lpc55-core0", "rt", "defmt", "time-driver-rtc"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt"] }
12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 12embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] } 13embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "tick-hz-32_768"] }
diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml
index 4daddbbb4..21434106a 100644
--- a/examples/mspm0c1104/Cargo.toml
+++ b/examples/mspm0c1104/Cargo.toml
@@ -33,7 +33,6 @@ lto = true
33codegen-units = 1 33codegen-units = 1
34 34
35[package.metadata.embassy] 35[package.metadata.embassy]
36skip = true # TODO: remove when we find a way to decrease the defmt buffer size in ci.
37build = [ 36build = [
38 { target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0c1104" } 37 { target = "thumbv6m-none-eabi", artifact-dir = "out/examples/mspm0c1104", env = { DEFMT_RTT_BUFFER_SIZE = "72" }}
39] 38]
diff --git a/examples/nrf52840-edf/.cargo/config.toml b/examples/nrf52840-edf/.cargo/config.toml
new file mode 100644
index 000000000..e0b9ce59e
--- /dev/null
+++ b/examples/nrf52840-edf/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list`
3runner = "probe-rs run --chip nRF52840_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "debug"
diff --git a/examples/nrf52840-edf/Cargo.toml b/examples/nrf52840-edf/Cargo.toml
new file mode 100644
index 000000000..1e8803233
--- /dev/null
+++ b/examples/nrf52840-edf/Cargo.toml
@@ -0,0 +1,27 @@
1[package]
2edition = "2021"
3name = "embassy-nrf52840-edf-examples"
4version = "0.1.0"
5license = "MIT OR Apache-2.0"
6publish = false
7
8[dependencies]
9# NOTE: "scheduler-deadline" and "embassy-time-driver" features are enabled
10embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "scheduler-deadline", "embassy-time-driver"] }
11embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
12embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] }
13
14defmt = "1.0.1"
15defmt-rtt = "1.0.0"
16
17cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
18cortex-m-rt = "0.7.0"
19panic-probe = { version = "1.0.0", features = ["print-defmt"] }
20
21[profile.release]
22debug = 2
23
24[package.metadata.embassy]
25build = [
26 { target = "thumbv7em-none-eabi", artifact-dir = "out/examples/nrf52840-edf" }
27]
diff --git a/examples/nrf52840-edf/build.rs b/examples/nrf52840-edf/build.rs
new file mode 100644
index 000000000..30691aa97
--- /dev/null
+++ b/examples/nrf52840-edf/build.rs
@@ -0,0 +1,35 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
35}
diff --git a/examples/nrf52840-edf/memory.x b/examples/nrf52840-edf/memory.x
new file mode 100644
index 000000000..15b492bce
--- /dev/null
+++ b/examples/nrf52840-edf/memory.x
@@ -0,0 +1,12 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
5 RAM : ORIGIN = 0x20000000, LENGTH = 256K
6
7 /* These values correspond to the NRF52840 with Softdevices S140 7.3.0 */
8 /*
9 FLASH : ORIGIN = 0x00027000, LENGTH = 868K
10 RAM : ORIGIN = 0x20020000, LENGTH = 128K
11 */
12}
diff --git a/examples/nrf52840-edf/src/bin/basic.rs b/examples/nrf52840-edf/src/bin/basic.rs
new file mode 100644
index 000000000..d888e17d1
--- /dev/null
+++ b/examples/nrf52840-edf/src/bin/basic.rs
@@ -0,0 +1,194 @@
1//! Basic side-by-side example of the Earliest Deadline First scheduler
2//!
3//! This test spawns a number of background "ambient system load" workers
4//! that are constantly working, and runs two sets of trials.
5//!
6//! The first trial runs with no deadline set, so our trial task is at the
7//! same prioritization level as the background worker tasks.
8//!
9//! The second trial sets a deadline, meaning that it will be given higher
10//! scheduling priority than background tasks, that have no deadline set
11
12#![no_std]
13#![no_main]
14
15use core::sync::atomic::{compiler_fence, Ordering};
16
17use defmt::unwrap;
18use embassy_executor::Spawner;
19use embassy_time::{Duration, Instant, Timer};
20use {defmt_rtt as _, panic_probe as _};
21
22#[embassy_executor::main]
23async fn main(spawner: Spawner) {
24 embassy_nrf::init(Default::default());
25
26 // Enable flash cache to remove some flash latency jitter
27 compiler_fence(Ordering::SeqCst);
28 embassy_nrf::pac::NVMC.icachecnf().write(|w| {
29 w.set_cacheen(true);
30 });
31 compiler_fence(Ordering::SeqCst);
32
33 //
34 // Baseline system load tunables
35 //
36
37 // how many load tasks? More load tasks means more tasks contending
38 // for the runqueue
39 let tasks = 32;
40 // how long should each task work for? The longer the working time,
41 // the longer the max jitter possible, even when a task is prioritized,
42 // as EDF is still cooperative and not pre-emptive
43 //
44 // 33 ticks ~= 1ms
45 let work_time_ticks = 33;
46 // what fraction, 1/denominator, should the system be busy?
47 // bigger number means **less** busy
48 //
49 // 2 => 50%
50 // 4 => 25%
51 // 10 => 10%
52 let denominator = 2;
53
54 // Total time window, so each worker is working 1/denominator
55 // amount of the total time
56 let time_window = work_time_ticks * u64::from(tasks) * denominator;
57
58 // Spawn all of our load workers!
59 for i in 0..tasks {
60 spawner.spawn(unwrap!(load_task(i, work_time_ticks, time_window)));
61 }
62
63 // Let all the tasks spin up
64 defmt::println!("Spinning up load tasks...");
65 Timer::after_secs(1).await;
66
67 //
68 // Trial task worker tunables
69 //
70
71 // How many steps should the workers under test run?
72 // More steps means more chances to have to wait for other tasks
73 // in line ahead of us.
74 let num_steps = 100;
75
76 // How many ticks should the worker take working on each step?
77 //
78 // 33 ticks ~= 1ms
79 let work_ticks = 33;
80 // How many ticks should the worker wait on each step?
81 //
82 // 66 ticks ~= 2ms
83 let idle_ticks = 66;
84
85 // How many times to repeat each trial?
86 let trials = 3;
87
88 // The total time a trial would take, in a perfect unloaded system
89 let theoretical = (num_steps * work_ticks) + (num_steps * idle_ticks);
90
91 defmt::println!("");
92 defmt::println!("Starting UNPRIORITIZED worker trials");
93 for _ in 0..trials {
94 //
95 // UNPRIORITIZED worker
96 //
97 defmt::println!("");
98 defmt::println!("Starting unprioritized worker");
99 let start = Instant::now();
100 for _ in 0..num_steps {
101 let now = Instant::now();
102 while now.elapsed().as_ticks() < work_ticks {}
103 Timer::after_ticks(idle_ticks).await;
104 }
105 let elapsed = start.elapsed().as_ticks();
106 defmt::println!(
107 "Trial complete, theoretical ticks: {=u64}, actual ticks: {=u64}",
108 theoretical,
109 elapsed
110 );
111 let ratio = ((elapsed as f32) / (theoretical as f32)) * 100.0;
112 defmt::println!("Took {=f32}% of ideal time", ratio);
113 Timer::after_millis(500).await;
114 }
115
116 Timer::after_secs(1).await;
117
118 defmt::println!("");
119 defmt::println!("Starting PRIORITIZED worker trials");
120 for _ in 0..trials {
121 //
122 // PRIORITIZED worker
123 //
124 defmt::println!("");
125 defmt::println!("Starting prioritized worker");
126 let start = Instant::now();
127 // Set the deadline to ~2x the theoretical time. In practice, setting any deadline
128 // here elevates the current task above all other worker tasks.
129 let meta = embassy_executor::Metadata::for_current_task().await;
130 meta.set_deadline_after(theoretical * 2);
131
132 // Perform the trial
133 for _ in 0..num_steps {
134 let now = Instant::now();
135 while now.elapsed().as_ticks() < work_ticks {}
136 Timer::after_ticks(idle_ticks).await;
137 }
138
139 let elapsed = start.elapsed().as_ticks();
140 defmt::println!(
141 "Trial complete, theoretical ticks: {=u64}, actual ticks: {=u64}",
142 theoretical,
143 elapsed
144 );
145 let ratio = ((elapsed as f32) / (theoretical as f32)) * 100.0;
146 defmt::println!("Took {=f32}% of ideal time", ratio);
147
148 // Unset the deadline, deadlines are not automatically cleared, and if our
149 // deadline is in the past, then we get very high priority!
150 meta.unset_deadline();
151
152 Timer::after_millis(500).await;
153 }
154
155 defmt::println!("");
156 defmt::println!("Trials Complete.");
157}
158
159#[embassy_executor::task(pool_size = 32)]
160async fn load_task(id: u32, ticks_on: u64, ttl_ticks: u64) {
161 let mut last_print = Instant::now();
162 let mut last_tick = last_print;
163 let mut variance = 0;
164 let mut max_variance = 0;
165 loop {
166 let tgt = last_tick + Duration::from_ticks(ttl_ticks);
167 assert!(tgt > Instant::now(), "fell too behind!");
168
169 Timer::at(tgt).await;
170 let now = Instant::now();
171 // How late are we from the target?
172 let var = now.duration_since(tgt).as_ticks();
173 max_variance = max_variance.max(var);
174 variance += var;
175
176 // blocking work
177 while now.elapsed().as_ticks() < ticks_on {}
178
179 if last_print.elapsed() >= Duration::from_secs(1) {
180 defmt::trace!(
181 "Task {=u32} variance ticks (1s): {=u64}, max: {=u64}, act: {=u64}",
182 id,
183 variance,
184 max_variance,
185 ticks_on,
186 );
187 max_variance = 0;
188 variance = 0;
189 last_print = Instant::now();
190 }
191
192 last_tick = tgt;
193 }
194}
diff --git a/examples/nrf52840-rtic/src/bin/blinky.rs b/examples/nrf52840-rtic/src/bin/blinky.rs
index 719e22729..2adac7e0a 100644
--- a/examples/nrf52840-rtic/src/bin/blinky.rs
+++ b/examples/nrf52840-rtic/src/bin/blinky.rs
@@ -1,6 +1,5 @@
1#![no_std] 1#![no_std]
2#![no_main] 2#![no_main]
3#![feature(type_alias_impl_trait)]
4 3
5use {defmt_rtt as _, panic_probe as _}; 4use {defmt_rtt as _, panic_probe as _};
6 5
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index a9339bcd3..452e83b7e 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -10,8 +10,8 @@ embassy-futures = { version = "0.1.2", path = "../../embassy-futures" }
10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 11embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } 12embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
13embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } 13embassy-nrf = { version = "0.7.0", path = "../../embassy-nrf", features = ["defmt", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac", "time", "net-driver"] }
14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet"] } 14embassy-net = { version = "0.7.1", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet","udp", "medium-ieee802154", "proto-ipv6"] }
15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] } 15embassy-usb = { version = "0.5.1", path = "../../embassy-usb", features = ["defmt"] }
16embedded-io = { version = "0.6.0", features = ["defmt-03"] } 16embedded-io = { version = "0.6.0", features = ["defmt-03"] }
17embedded-io-async = { version = "0.6.1", features = ["defmt-03"] } 17embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
diff --git a/examples/nrf52840/src/bin/sixlowpan.rs b/examples/nrf52840/src/bin/sixlowpan.rs
new file mode 100644
index 000000000..00a597366
--- /dev/null
+++ b/examples/nrf52840/src/bin/sixlowpan.rs
@@ -0,0 +1,120 @@
1#![no_std]
2#![no_main]
3
4use core::net::Ipv6Addr;
5
6use defmt::{info, unwrap, warn};
7use embassy_executor::Spawner;
8use embassy_net::udp::{PacketMetadata, UdpMetadata, UdpSocket};
9use embassy_net::{IpAddress, IpEndpoint, IpListenEndpoint, Ipv6Cidr, StackResources, StaticConfigV6};
10use embassy_nrf::config::{Config, HfclkSource};
11use embassy_nrf::rng::Rng;
12use embassy_nrf::{bind_interrupts, embassy_net_802154_driver as net, peripherals, radio};
13use embassy_time::Delay;
14use embedded_hal_async::delay::DelayNs;
15use static_cell::StaticCell;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 RADIO => radio::InterruptHandler<peripherals::RADIO>;
20 RNG => embassy_nrf::rng::InterruptHandler<peripherals::RNG>;
21});
22
23#[embassy_executor::task]
24async fn ieee802154_task(runner: net::Runner<'static, peripherals::RADIO>) -> ! {
25 runner.run().await
26}
27
28#[embassy_executor::task]
29async fn net_task(mut runner: embassy_net::Runner<'static, net::Device<'static>>) -> ! {
30 runner.run().await
31}
32
33#[embassy_executor::main]
34async fn main(spawner: Spawner) {
35 let mut config = Config::default();
36 // Necessary to run the radio nrf52840 v1.11 5.4.1
37 config.hfclk_source = HfclkSource::ExternalXtal;
38 let p = embassy_nrf::init(config);
39
40 let mac_addr: [u8; 8] = [2, 3, 4, 5, 6, 7, 8, 9];
41 static NRF802154_STATE: StaticCell<net::State<20, 20>> = StaticCell::new();
42 let (device, runner) = net::new(mac_addr, p.RADIO, Irqs, NRF802154_STATE.init(net::State::new()))
43 .await
44 .unwrap();
45
46 spawner.spawn(unwrap!(ieee802154_task(runner)));
47
48 // Swap these when flashing a second board
49 let peer = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a4);
50 let local = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xd701, 0xda3f, 0x3955, 0x82a5);
51
52 let config = embassy_net::Config::ipv6_static(StaticConfigV6 {
53 address: Ipv6Cidr::new(local, 64),
54 gateway: None,
55 dns_servers: Default::default(),
56 });
57
58 // Generate random seed
59 let mut rng = Rng::new(p.RNG, Irqs);
60 let mut seed = [0; 8];
61 rng.blocking_fill_bytes(&mut seed);
62 let seed = u64::from_le_bytes(seed);
63
64 // Init network stack
65 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
66 let (stack, runner) = embassy_net::new(device, config, RESOURCES.init(StackResources::new()), seed);
67
68 spawner.spawn(unwrap!(net_task(runner)));
69
70 let mut rx_buffer = [0; 2096];
71 let mut tx_buffer = [0; 2096];
72 let mut tx_m_buffer = [PacketMetadata::EMPTY; 5];
73 let mut rx_m_buffer = [PacketMetadata::EMPTY; 5];
74
75 let mut delay = Delay;
76 loop {
77 let mut socket = UdpSocket::new(
78 stack,
79 &mut tx_m_buffer,
80 &mut rx_buffer,
81 &mut rx_m_buffer,
82 &mut tx_buffer,
83 );
84 socket
85 .bind(IpListenEndpoint {
86 addr: Some(IpAddress::Ipv6(local)),
87 port: 1234,
88 })
89 .unwrap();
90 let rep = UdpMetadata {
91 endpoint: IpEndpoint {
92 addr: IpAddress::Ipv6(peer),
93 port: 1234,
94 },
95 local_address: Some(IpAddress::Ipv6(local)),
96 meta: Default::default(),
97 };
98
99 info!("Listening on {:?} UDP:1234...", local);
100
101 let mut recv_buf = [0; 12];
102 loop {
103 delay.delay_ms(2000).await;
104 if socket.may_recv() {
105 let n = match socket.recv_from(&mut recv_buf).await {
106 Ok((0, _)) => panic!(),
107 Ok((n, _)) => n,
108 Err(e) => {
109 warn!("read error: {:?}", e);
110 break;
111 }
112 };
113 info!("Received {:02x}", &recv_buf[..n]);
114 }
115
116 info!("Sending");
117 socket.send_to(b"Hello World", rep).await.unwrap();
118 }
119 }
120}
diff --git a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
new file mode 100644
index 000000000..f51df2df9
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
@@ -0,0 +1,155 @@
1//! This example implements a TCP echo server on port 1234 and using DHCP.
2//! Send it some data, you should see it echoed back and printed in the console.
3//!
4//! Example written for the [`WIZnet W55RP20-EVB-Pico`](https://docs.wiznet.io/Product/ioNIC/W55RP20/w55rp20-evb-pico) board.
5//! Note: the W55RP20 is a single package that contains both a RP2040 and the Wiznet W5500 ethernet
6//! controller
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::{Stack, StackResources};
15use embassy_net_wiznet::chip::W5500;
16use embassy_net_wiznet::*;
17use embassy_rp::clocks::RoscRng;
18use embassy_rp::gpio::{Input, Level, Output, Pull};
19use embassy_rp::peripherals::PIO0;
20use embassy_rp::pio_programs::spi::Spi;
21use embassy_rp::spi::{Async, Config as SpiConfig};
22use embassy_rp::{bind_interrupts, pio};
23use embassy_time::{Delay, Duration};
24use embedded_hal_bus::spi::ExclusiveDevice;
25use embedded_io_async::Write;
26use static_cell::StaticCell;
27use {defmt_rtt as _, panic_probe as _};
28
29bind_interrupts!(struct Irqs {
30 PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
31});
32
33#[embassy_executor::task]
34async fn ethernet_task(
35 runner: Runner<
36 'static,
37 W5500,
38 ExclusiveDevice<Spi<'static, PIO0, 0, Async>, Output<'static>, Delay>,
39 Input<'static>,
40 Output<'static>,
41 >,
42) -> ! {
43 runner.run().await
44}
45
46#[embassy_executor::task]
47async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
48 runner.run().await
49}
50
51#[embassy_executor::main]
52async fn main(spawner: Spawner) {
53 let p = embassy_rp::init(Default::default());
54 let mut rng = RoscRng;
55 let mut led = Output::new(p.PIN_19, Level::Low);
56
57 // The W55RP20 uses a PIO unit for SPI communication, once the SPI bus has been formed using a
58 // PIO statemachine everything else is generally unchanged from the other examples that use the W5500
59 let mosi = p.PIN_23;
60 let miso = p.PIN_22;
61 let clk = p.PIN_21;
62
63 let pio::Pio { mut common, sm0, .. } = pio::Pio::new(p.PIO0, Irqs);
64
65 // Construct an SPI driver backed by a PIO state machine
66 let mut spi_cfg = SpiConfig::default();
67 spi_cfg.frequency = 12_500_000; // The PIO SPI program is much less stable than the actual SPI
68 // peripheral, use higher speeds at your peril
69 let spi = Spi::new(&mut common, sm0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
70
71 // Further control pins
72 let cs = Output::new(p.PIN_20, Level::High);
73 let w5500_int = Input::new(p.PIN_24, Pull::Up);
74 let w5500_reset = Output::new(p.PIN_25, Level::High);
75
76 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
77 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
78 let state = STATE.init(State::<8, 8>::new());
79 let (device, runner) = embassy_net_wiznet::new(
80 mac_addr,
81 state,
82 ExclusiveDevice::new(spi, cs, Delay),
83 w5500_int,
84 w5500_reset,
85 )
86 .await
87 .unwrap();
88 spawner.spawn(unwrap!(ethernet_task(runner)));
89
90 // Generate random seed
91 let seed = rng.next_u64();
92
93 // Init network stack
94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
95 let (stack, runner) = embassy_net::new(
96 device,
97 embassy_net::Config::dhcpv4(Default::default()),
98 RESOURCES.init(StackResources::new()),
99 seed,
100 );
101
102 // Launch network task
103 spawner.spawn(unwrap!(net_task(runner)));
104
105 info!("Waiting for DHCP...");
106 let cfg = wait_for_config(stack).await;
107 let local_addr = cfg.address.address();
108 info!("IP address: {:?}", local_addr);
109
110 let mut rx_buffer = [0; 4096];
111 let mut tx_buffer = [0; 4096];
112 let mut buf = [0; 4096];
113 loop {
114 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
115 socket.set_timeout(Some(Duration::from_secs(10)));
116
117 led.set_low();
118 info!("Listening on TCP:1234...");
119 if let Err(e) = socket.accept(1234).await {
120 warn!("accept error: {:?}", e);
121 continue;
122 }
123 info!("Received connection from {:?}", socket.remote_endpoint());
124 led.set_high();
125
126 loop {
127 let n = match socket.read(&mut buf).await {
128 Ok(0) => {
129 warn!("read EOF");
130 break;
131 }
132 Ok(n) => n,
133 Err(e) => {
134 warn!("{:?}", e);
135 break;
136 }
137 };
138 info!("rxd {}", core::str::from_utf8(&buf[..n]).unwrap());
139
140 if let Err(e) = socket.write_all(&buf[..n]).await {
141 warn!("write error: {:?}", e);
142 break;
143 }
144 }
145 }
146}
147
148async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
149 loop {
150 if let Some(config) = stack.config_v4() {
151 return config.clone();
152 }
153 yield_now().await;
154 }
155}
diff --git a/examples/rp/src/bin/pio_onewire.rs b/examples/rp/src/bin/pio_onewire.rs
index 379e2b8f9..102f13c45 100644
--- a/examples/rp/src/bin/pio_onewire.rs
+++ b/examples/rp/src/bin/pio_onewire.rs
@@ -1,4 +1,5 @@
1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors. 1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
2//! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example.
2 3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
diff --git a/examples/rp/src/bin/pio_onewire_parasite.rs b/examples/rp/src/bin/pio_onewire_parasite.rs
new file mode 100644
index 000000000..fd076dee0
--- /dev/null
+++ b/examples/rp/src/bin/pio_onewire_parasite.rs
@@ -0,0 +1,89 @@
1//! This example shows how you can use PIO to read one or more `DS18B20`
2//! one-wire temperature sensors using parasite power.
3//! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet.
4//! For externally powered sensors, use the pio_onewire.rs example.
5
6#![no_std]
7#![no_main]
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
14use embassy_time::Duration;
15use heapless::Vec;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25 let mut pio = Pio::new(p.PIO0, Irqs);
26
27 let prg = PioOneWireProgram::new(&mut pio.common);
28 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
29
30 info!("Starting onewire search");
31
32 let mut devices = Vec::<u64, 10>::new();
33 let mut search = PioOneWireSearch::new();
34 for _ in 0..10 {
35 if !search.is_finished() {
36 if let Some(address) = search.next(&mut onewire).await {
37 if crc8(&address.to_le_bytes()) == 0 {
38 info!("Found address: {:x}", address);
39 let _ = devices.push(address);
40 } else {
41 warn!("Found invalid address: {:x}", address);
42 }
43 }
44 }
45 }
46
47 info!("Search done, found {} devices", devices.len());
48
49 loop {
50 // Read all devices one by one
51 for device in &devices {
52 onewire.reset().await;
53 onewire.write_bytes(&[0x55]).await; // Match rom
54 onewire.write_bytes(&device.to_le_bytes()).await;
55 // 750 ms delay required for default 12-bit resolution.
56 onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await;
57
58 onewire.reset().await;
59 onewire.write_bytes(&[0x55]).await; // Match rom
60 onewire.write_bytes(&device.to_le_bytes()).await;
61 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
62
63 let mut data = [0; 9];
64 onewire.read_bytes(&mut data).await;
65 if crc8(&data) == 0 {
66 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
67 info!("Read device {:x}: {} deg C", device, temp);
68 } else {
69 warn!("Reading device {:x} failed. {:02x}", device, data);
70 }
71 }
72 }
73}
74
75fn crc8(data: &[u8]) -> u8 {
76 let mut crc = 0;
77 for b in data {
78 let mut data_byte = *b;
79 for _ in 0..8 {
80 let temp = (crc ^ data_byte) & 0x01;
81 crc >>= 1;
82 if temp != 0 {
83 crc ^= 0x8C;
84 }
85 data_byte >>= 1;
86 }
87 }
88 crc
89}
diff --git a/examples/rp235x/src/bin/pio_onewire.rs b/examples/rp235x/src/bin/pio_onewire.rs
index 991510851..102f13c45 100644
--- a/examples/rp235x/src/bin/pio_onewire.rs
+++ b/examples/rp235x/src/bin/pio_onewire.rs
@@ -1,4 +1,5 @@
1//! This example shows how you can use PIO to read a `DS18B20` one-wire temperature sensor. 1//! This example shows how you can use PIO to read one or more `DS18B20` one-wire temperature sensors.
2//! This uses externally powered sensors. For parasite power, see the pio_onewire_parasite.rs example.
2 3
3#![no_std] 4#![no_std]
4#![no_main] 5#![no_main]
@@ -6,9 +7,10 @@ use defmt::*;
6use embassy_executor::Spawner; 7use embassy_executor::Spawner;
7use embassy_rp::bind_interrupts; 8use embassy_rp::bind_interrupts;
8use embassy_rp::peripherals::PIO0; 9use embassy_rp::peripherals::PIO0;
9use embassy_rp::pio::{self, InterruptHandler, Pio}; 10use embassy_rp::pio::{InterruptHandler, Pio};
10use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram}; 11use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
11use embassy_time::Timer; 12use embassy_time::Timer;
13use heapless::Vec;
12use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
13 15
14bind_interrupts!(struct Irqs { 16bind_interrupts!(struct Irqs {
@@ -21,63 +23,66 @@ async fn main(_spawner: Spawner) {
21 let mut pio = Pio::new(p.PIO0, Irqs); 23 let mut pio = Pio::new(p.PIO0, Irqs);
22 24
23 let prg = PioOneWireProgram::new(&mut pio.common); 25 let prg = PioOneWireProgram::new(&mut pio.common);
24 let onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg); 26 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
25 27
26 let mut sensor = Ds18b20::new(onewire); 28 info!("Starting onewire search");
27 29
28 loop { 30 let mut devices = Vec::<u64, 10>::new();
29 sensor.start().await; // Start a new measurement 31 let mut search = PioOneWireSearch::new();
30 Timer::after_secs(1).await; // Allow 1s for the measurement to finish 32 for _ in 0..10 {
31 match sensor.temperature().await { 33 if !search.is_finished() {
32 Ok(temp) => info!("temp = {:?} deg C", temp), 34 if let Some(address) = search.next(&mut onewire).await {
33 _ => error!("sensor error"), 35 if crc8(&address.to_le_bytes()) == 0 {
36 info!("Found addres: {:x}", address);
37 let _ = devices.push(address);
38 } else {
39 warn!("Found invalid address: {:x}", address);
40 }
41 }
34 } 42 }
35 Timer::after_secs(1).await;
36 } 43 }
37}
38 44
39/// DS18B20 temperature sensor driver 45 info!("Search done, found {} devices", devices.len());
40pub struct Ds18b20<'d, PIO: pio::Instance, const SM: usize> {
41 wire: PioOneWire<'d, PIO, SM>,
42}
43 46
44impl<'d, PIO: pio::Instance, const SM: usize> Ds18b20<'d, PIO, SM> { 47 loop {
45 pub fn new(wire: PioOneWire<'d, PIO, SM>) -> Self { 48 onewire.reset().await;
46 Self { wire } 49 // Skip rom and trigger conversion, we can trigger all devices on the bus immediately
47 } 50 onewire.write_bytes(&[0xCC, 0x44]).await;
48 51
49 /// Calculate CRC8 of the data 52 Timer::after_secs(1).await; // Allow 1s for the measurement to finish
50 fn crc8(data: &[u8]) -> u8 { 53
51 let mut temp; 54 // Read all devices one by one
52 let mut data_byte; 55 for device in &devices {
53 let mut crc = 0; 56 onewire.reset().await;
54 for b in data { 57 onewire.write_bytes(&[0x55]).await; // Match rom
55 data_byte = *b; 58 onewire.write_bytes(&device.to_le_bytes()).await;
56 for _ in 0..8 { 59 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
57 temp = (crc ^ data_byte) & 0x01; 60
58 crc >>= 1; 61 let mut data = [0; 9];
59 if temp != 0 { 62 onewire.read_bytes(&mut data).await;
60 crc ^= 0x8C; 63 if crc8(&data) == 0 {
61 } 64 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
62 data_byte >>= 1; 65 info!("Read device {:x}: {} deg C", device, temp);
66 } else {
67 warn!("Reading device {:x} failed", device);
63 } 68 }
64 } 69 }
65 crc 70 Timer::after_secs(1).await;
66 }
67
68 /// Start a new measurement. Allow at least 1000ms before getting `temperature`.
69 pub async fn start(&mut self) {
70 self.wire.write_bytes(&[0xCC, 0x44]).await;
71 } 71 }
72}
72 73
73 /// Read the temperature. Ensure >1000ms has passed since `start` before calling this. 74fn crc8(data: &[u8]) -> u8 {
74 pub async fn temperature(&mut self) -> Result<f32, ()> { 75 let mut crc = 0;
75 self.wire.write_bytes(&[0xCC, 0xBE]).await; 76 for b in data {
76 let mut data = [0; 9]; 77 let mut data_byte = *b;
77 self.wire.read_bytes(&mut data).await; 78 for _ in 0..8 {
78 match Self::crc8(&data) == 0 { 79 let temp = (crc ^ data_byte) & 0x01;
79 true => Ok(((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.), 80 crc >>= 1;
80 false => Err(()), 81 if temp != 0 {
82 crc ^= 0x8C;
83 }
84 data_byte >>= 1;
81 } 85 }
82 } 86 }
87 crc
83} 88}
diff --git a/examples/rp235x/src/bin/pio_onewire_parasite.rs b/examples/rp235x/src/bin/pio_onewire_parasite.rs
new file mode 100644
index 000000000..fd076dee0
--- /dev/null
+++ b/examples/rp235x/src/bin/pio_onewire_parasite.rs
@@ -0,0 +1,89 @@
1//! This example shows how you can use PIO to read one or more `DS18B20`
2//! one-wire temperature sensors using parasite power.
3//! It applies a strong pullup during conversion, see "Powering the DS18B20" in the datasheet.
4//! For externally powered sensors, use the pio_onewire.rs example.
5
6#![no_std]
7#![no_main]
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{InterruptHandler, Pio};
13use embassy_rp::pio_programs::onewire::{PioOneWire, PioOneWireProgram, PioOneWireSearch};
14use embassy_time::Duration;
15use heapless::Vec;
16use {defmt_rtt as _, panic_probe as _};
17
18bind_interrupts!(struct Irqs {
19 PIO0_IRQ_0 => InterruptHandler<PIO0>;
20});
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25 let mut pio = Pio::new(p.PIO0, Irqs);
26
27 let prg = PioOneWireProgram::new(&mut pio.common);
28 let mut onewire = PioOneWire::new(&mut pio.common, pio.sm0, p.PIN_2, &prg);
29
30 info!("Starting onewire search");
31
32 let mut devices = Vec::<u64, 10>::new();
33 let mut search = PioOneWireSearch::new();
34 for _ in 0..10 {
35 if !search.is_finished() {
36 if let Some(address) = search.next(&mut onewire).await {
37 if crc8(&address.to_le_bytes()) == 0 {
38 info!("Found address: {:x}", address);
39 let _ = devices.push(address);
40 } else {
41 warn!("Found invalid address: {:x}", address);
42 }
43 }
44 }
45 }
46
47 info!("Search done, found {} devices", devices.len());
48
49 loop {
50 // Read all devices one by one
51 for device in &devices {
52 onewire.reset().await;
53 onewire.write_bytes(&[0x55]).await; // Match rom
54 onewire.write_bytes(&device.to_le_bytes()).await;
55 // 750 ms delay required for default 12-bit resolution.
56 onewire.write_bytes_pullup(&[0x44], Duration::from_millis(750)).await;
57
58 onewire.reset().await;
59 onewire.write_bytes(&[0x55]).await; // Match rom
60 onewire.write_bytes(&device.to_le_bytes()).await;
61 onewire.write_bytes(&[0xBE]).await; // Read scratchpad
62
63 let mut data = [0; 9];
64 onewire.read_bytes(&mut data).await;
65 if crc8(&data) == 0 {
66 let temp = ((data[1] as u32) << 8 | data[0] as u32) as f32 / 16.;
67 info!("Read device {:x}: {} deg C", device, temp);
68 } else {
69 warn!("Reading device {:x} failed. {:02x}", device, data);
70 }
71 }
72 }
73}
74
75fn crc8(data: &[u8]) -> u8 {
76 let mut crc = 0;
77 for b in data {
78 let mut data_byte = *b;
79 for _ in 0..8 {
80 let temp = (crc ^ data_byte) & 0x01;
81 crc >>= 1;
82 if temp != 0 {
83 crc ^= 0x8C;
84 }
85 data_byte >>= 1;
86 }
87 }
88 crc
89}
diff --git a/examples/stm32f7/src/bin/qspi.rs b/examples/stm32f7/src/bin/qspi.rs
index ab29ddeff..80652b865 100644
--- a/examples/stm32f7/src/bin/qspi.rs
+++ b/examples/stm32f7/src/bin/qspi.rs
@@ -273,14 +273,14 @@ async fn main(_spawner: Spawner) -> ! {
273 let p = embassy_stm32::init(config); 273 let p = embassy_stm32::init(config);
274 info!("Embassy initialized"); 274 info!("Embassy initialized");
275 275
276 let config = QspiCfg { 276 let mut config = QspiCfg::default();
277 memory_size: MemorySize::_8MiB, 277 config.memory_size = MemorySize::_8MiB;
278 address_size: AddressSize::_24bit, 278 config.address_size = AddressSize::_24bit;
279 prescaler: 16, 279 config.prescaler = 16;
280 cs_high_time: ChipSelectHighTime::_1Cycle, 280 config.cs_high_time = ChipSelectHighTime::_1Cycle;
281 fifo_threshold: FIFOThresholdLevel::_16Bytes, 281 config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
282 sample_shifting: SampleShifting::None, 282 config.sample_shifting = SampleShifting::None;
283 }; 283
284 let driver = Qspi::new_bank1( 284 let driver = Qspi::new_bank1(
285 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config, 285 p.QUADSPI, p.PF8, p.PF9, p.PE2, p.PF6, p.PF10, p.PB10, p.DMA2_CH7, config,
286 ); 286 );
diff --git a/examples/stm32h742/src/bin/qspi.rs b/examples/stm32h742/src/bin/qspi.rs
index 50e37ec52..9e79d7089 100644
--- a/examples/stm32h742/src/bin/qspi.rs
+++ b/examples/stm32h742/src/bin/qspi.rs
@@ -266,14 +266,14 @@ async fn main(_spawner: Spawner) -> ! {
266 let p = embassy_stm32::init(config); 266 let p = embassy_stm32::init(config);
267 info!("Embassy initialized"); 267 info!("Embassy initialized");
268 268
269 let config = QspiCfg { 269 let mut config = QspiCfg::default();
270 memory_size: MemorySize::_8MiB, 270 config.memory_size = MemorySize::_8MiB;
271 address_size: AddressSize::_24bit, 271 config.address_size = AddressSize::_24bit;
272 prescaler: 16, 272 config.prescaler = 16;
273 cs_high_time: ChipSelectHighTime::_1Cycle, 273 config.cs_high_time = ChipSelectHighTime::_1Cycle;
274 fifo_threshold: FIFOThresholdLevel::_16Bytes, 274 config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
275 sample_shifting: SampleShifting::None, 275 config.sample_shifting = SampleShifting::None;
276 }; 276
277 let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config); 277 let driver = Qspi::new_blocking_bank1(p.QUADSPI, p.PD11, p.PD12, p.PE2, p.PD13, p.PB2, p.PB10, config);
278 let mut flash = FlashMemory::new(driver); 278 let mut flash = FlashMemory::new(driver);
279 let flash_id = flash.read_id(); 279 let flash_id = flash.read_id();
diff --git a/examples/stm32l432/src/bin/qspi_mmap.rs b/examples/stm32l432/src/bin/qspi_mmap.rs
index 075458fe5..feabdd532 100644
--- a/examples/stm32l432/src/bin/qspi_mmap.rs
+++ b/examples/stm32l432/src/bin/qspi_mmap.rs
@@ -246,14 +246,14 @@ const MEMORY_ADDR: u32 = 0x00000000 as u32;
246async fn main(_spawner: Spawner) { 246async fn main(_spawner: Spawner) {
247 let p = embassy_stm32::init(Default::default()); 247 let p = embassy_stm32::init(Default::default());
248 248
249 let config = qspi::Config { 249 let mut config = qspi::Config::default();
250 memory_size: MemorySize::_16MiB, 250 config.memory_size = MemorySize::_16MiB;
251 address_size: AddressSize::_24bit, 251 config.address_size = AddressSize::_24bit;
252 prescaler: 200, 252 config.prescaler = 200;
253 cs_high_time: ChipSelectHighTime::_1Cycle, 253 config.cs_high_time = ChipSelectHighTime::_1Cycle;
254 fifo_threshold: FIFOThresholdLevel::_16Bytes, 254 config.fifo_threshold = FIFOThresholdLevel::_16Bytes;
255 sample_shifting: SampleShifting::None, 255 config.sample_shifting = SampleShifting::None;
256 }; 256
257 let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config); 257 let driver = qspi::Qspi::new_bank1(p.QUADSPI, p.PB1, p.PB0, p.PA7, p.PA6, p.PA3, p.PA2, p.DMA2_CH7, config);
258 let mut flash = FlashMemory::new(driver); 258 let mut flash = FlashMemory::new(driver);
259 let mut wr_buf = [0u8; 256]; 259 let mut wr_buf = [0u8; 256];