aboutsummaryrefslogtreecommitdiff
path: root/examples/rp/src
diff options
context:
space:
mode:
authorQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
committerQuentin Smith <[email protected]>2023-07-17 21:31:43 -0400
commit6f02403184eb7fb7990fb88fc9df9c4328a690a3 (patch)
tree748f510e190bb2724750507a6e69ed1a8e08cb20 /examples/rp/src
parentd896f80405aa8963877049ed999e4aba25d6e2bb (diff)
parent6b5df4523aa1c4902f02e803450ae4b418e0e3ca (diff)
Merge remote-tracking branch 'origin/main' into nrf-pdm
Diffstat (limited to 'examples/rp/src')
-rw-r--r--examples/rp/src/bin/adc.rs48
-rw-r--r--examples/rp/src/bin/blinky.rs4
-rw-r--r--examples/rp/src/bin/button.rs9
-rw-r--r--examples/rp/src/bin/ethernet_w5500_multisocket.rs136
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_client.rs124
-rw-r--r--examples/rp/src/bin/ethernet_w5500_tcp_server.rs132
-rw-r--r--examples/rp/src/bin/ethernet_w5500_udp.rs112
-rw-r--r--examples/rp/src/bin/flash.rs101
-rw-r--r--examples/rp/src/bin/gpio_async.rs6
-rw-r--r--examples/rp/src/bin/gpout.rs38
-rw-r--r--examples/rp/src/bin/i2c_async.rs111
-rw-r--r--examples/rp/src/bin/i2c_blocking.rs75
-rw-r--r--examples/rp/src/bin/lora_lorawan.rs81
-rw-r--r--examples/rp/src/bin/lora_p2p_receive.rs116
-rw-r--r--examples/rp/src/bin/lora_p2p_send.rs104
-rw-r--r--examples/rp/src/bin/lora_p2p_send_multicore.rs140
-rw-r--r--examples/rp/src/bin/multicore.rs64
-rw-r--r--examples/rp/src/bin/multiprio.rs146
-rw-r--r--examples/rp/src/bin/pio_async.rs135
-rw-r--r--examples/rp/src/bin/pio_dma.rs86
-rw-r--r--examples/rp/src/bin/pio_hd44780.rs244
-rw-r--r--examples/rp/src/bin/pio_ws2812.rs160
-rw-r--r--examples/rp/src/bin/pwm.rs30
-rw-r--r--examples/rp/src/bin/rtc.rs46
-rw-r--r--examples/rp/src/bin/spi.rs6
-rw-r--r--examples/rp/src/bin/spi_async.rs32
-rw-r--r--examples/rp/src/bin/spi_display.rs162
-rw-r--r--examples/rp/src/bin/uart.rs8
-rw-r--r--examples/rp/src/bin/uart_buffered_split.rs57
-rw-r--r--examples/rp/src/bin/uart_unidir.rs51
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs155
-rw-r--r--examples/rp/src/bin/usb_hid_keyboard.rs188
-rw-r--r--examples/rp/src/bin/usb_logger.rs37
-rw-r--r--examples/rp/src/bin/usb_serial.rs109
-rw-r--r--examples/rp/src/bin/watchdog.rs52
-rw-r--r--examples/rp/src/bin/wifi_ap_tcp_server.rs139
-rw-r--r--examples/rp/src/bin/wifi_blinky.rs68
-rw-r--r--examples/rp/src/bin/wifi_scan.rs75
-rw-r--r--examples/rp/src/bin/wifi_tcp_server.rs149
39 files changed, 3409 insertions, 127 deletions
diff --git a/examples/rp/src/bin/adc.rs b/examples/rp/src/bin/adc.rs
new file mode 100644
index 000000000..81a8b8340
--- /dev/null
+++ b/examples/rp/src/bin/adc.rs
@@ -0,0 +1,48 @@
1//! This example test the ADC (Analog to Digital Conversion) of the RS2040 pin 26, 27 and 28.
2//! It also reads the temperature sensor in the chip.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::adc::{Adc, Config, InterruptHandler, Pin};
11use embassy_rp::bind_interrupts;
12use embassy_rp::gpio::Pull;
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 ADC_IRQ_FIFO => InterruptHandler;
18});
19
20#[embassy_executor::main]
21async fn main(_spawner: Spawner) {
22 let p = embassy_rp::init(Default::default());
23 let mut adc = Adc::new(p.ADC, Irqs, Config::default());
24
25 let mut p26 = Pin::new(p.PIN_26, Pull::None);
26 let mut p27 = Pin::new(p.PIN_27, Pull::None);
27 let mut p28 = Pin::new(p.PIN_28, Pull::None);
28
29 loop {
30 let level = adc.read(&mut p26).await.unwrap();
31 info!("Pin 26 ADC: {}", level);
32 let level = adc.read(&mut p27).await.unwrap();
33 info!("Pin 27 ADC: {}", level);
34 let level = adc.read(&mut p28).await.unwrap();
35 info!("Pin 28 ADC: {}", level);
36 let temp = adc.read_temperature().await.unwrap();
37 info!("Temp: {} degrees", convert_to_celsius(temp));
38 Timer::after(Duration::from_secs(1)).await;
39 }
40}
41
42fn convert_to_celsius(raw_temp: u16) -> f32 {
43 // According to chapter 4.9.5. Temperature Sensor in RP2040 datasheet
44 let temp = 27.0 - (raw_temp as f32 * 3.3 / 4096.0 - 0.706) / 0.001721;
45 let sign = if temp < 0.0 { -1.0 } else { 1.0 };
46 let rounded_temp_x10: i16 = ((temp * 10.0) + 0.5 * sign) as i16;
47 (rounded_temp_x10 as f32) / 10.0
48}
diff --git a/examples/rp/src/bin/blinky.rs b/examples/rp/src/bin/blinky.rs
index 7aa36a19f..295b000f3 100644
--- a/examples/rp/src/bin/blinky.rs
+++ b/examples/rp/src/bin/blinky.rs
@@ -1,3 +1,7 @@
1//! This example test the RP Pico on board LED.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
diff --git a/examples/rp/src/bin/button.rs b/examples/rp/src/bin/button.rs
index c5422c616..d7aa89410 100644
--- a/examples/rp/src/bin/button.rs
+++ b/examples/rp/src/bin/button.rs
@@ -1,3 +1,7 @@
1//! This example uses the RP Pico on board LED to test input pin 28. This is not the button on the board.
2//!
3//! It does not work with the RP Pico W board. Use wifi_blinky.rs and add input pin.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -9,9 +13,12 @@ use {defmt_rtt as _, panic_probe as _};
9#[embassy_executor::main] 13#[embassy_executor::main]
10async fn main(_spawner: Spawner) { 14async fn main(_spawner: Spawner) {
11 let p = embassy_rp::init(Default::default()); 15 let p = embassy_rp::init(Default::default());
12 let button = Input::new(p.PIN_28, Pull::Up);
13 let mut led = Output::new(p.PIN_25, Level::Low); 16 let mut led = Output::new(p.PIN_25, Level::Low);
14 17
18 // Use PIN_28, Pin34 on J0 for RP Pico, as a input.
19 // You need to add your own button.
20 let button = Input::new(p.PIN_28, Pull::Up);
21
15 loop { 22 loop {
16 if button.is_high() { 23 if button.is_high() {
17 led.set_high(); 24 led.set_high();
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
new file mode 100644
index 000000000..e81da177b
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs
@@ -0,0 +1,136 @@
1//! This example shows how you can allow multiple simultaneous TCP connections, by having multiple sockets listening on the same port.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_futures::yield_now;
12use embassy_net::{Stack, StackResources};
13use embassy_net_w5500::*;
14use embassy_rp::clocks::RoscRng;
15use embassy_rp::gpio::{Input, Level, Output, Pull};
16use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
17use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
18use embassy_time::{Delay, Duration};
19use embedded_hal_async::spi::ExclusiveDevice;
20use embedded_io::asynch::Write;
21use rand::RngCore;
22use static_cell::make_static;
23use {defmt_rtt as _, panic_probe as _};
24
25#[embassy_executor::task]
26async fn ethernet_task(
27 runner: Runner<
28 'static,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>,
32 >,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let mut rng = RoscRng;
46
47 let mut spi_cfg = SpiConfig::default();
48 spi_cfg.frequency = 50_000_000;
49 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
50 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
51 let cs = Output::new(p.PIN_17, Level::High);
52 let w5500_int = Input::new(p.PIN_21, Pull::Up);
53 let w5500_reset = Output::new(p.PIN_20, Level::High);
54
55 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
56 let state = make_static!(State::<8, 8>::new());
57 let (device, runner) = embassy_net_w5500::new(
58 mac_addr,
59 state,
60 ExclusiveDevice::new(spi, cs, Delay),
61 w5500_int,
62 w5500_reset,
63 )
64 .await;
65 unwrap!(spawner.spawn(ethernet_task(runner)));
66
67 // Generate random seed
68 let seed = rng.next_u64();
69
70 // Init network stack
71 let stack = &*make_static!(Stack::new(
72 device,
73 embassy_net::Config::dhcpv4(Default::default()),
74 make_static!(StackResources::<3>::new()),
75 seed
76 ));
77
78 // Launch network task
79 unwrap!(spawner.spawn(net_task(&stack)));
80
81 info!("Waiting for DHCP...");
82 let cfg = wait_for_config(stack).await;
83 let local_addr = cfg.address.address();
84 info!("IP address: {:?}", local_addr);
85
86 // Create two sockets listening to the same port, to handle simultaneous connections
87 unwrap!(spawner.spawn(listen_task(&stack, 0, 1234)));
88 unwrap!(spawner.spawn(listen_task(&stack, 1, 1234)));
89}
90
91#[embassy_executor::task(pool_size = 2)]
92async fn listen_task(stack: &'static Stack<Device<'static>>, id: u8, port: u16) {
93 let mut rx_buffer = [0; 4096];
94 let mut tx_buffer = [0; 4096];
95 let mut buf = [0; 4096];
96 loop {
97 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
98 socket.set_timeout(Some(Duration::from_secs(10)));
99
100 info!("SOCKET {}: Listening on TCP:{}...", id, port);
101 if let Err(e) = socket.accept(port).await {
102 warn!("accept error: {:?}", e);
103 continue;
104 }
105 info!("SOCKET {}: Received connection from {:?}", id, socket.remote_endpoint());
106
107 loop {
108 let n = match socket.read(&mut buf).await {
109 Ok(0) => {
110 warn!("read EOF");
111 break;
112 }
113 Ok(n) => n,
114 Err(e) => {
115 warn!("SOCKET {}: {:?}", id, e);
116 break;
117 }
118 };
119 info!("SOCKET {}: rxd {}", id, core::str::from_utf8(&buf[..n]).unwrap());
120
121 if let Err(e) = socket.write_all(&buf[..n]).await {
122 warn!("write error: {:?}", e);
123 break;
124 }
125 }
126 }
127}
128
129async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
130 loop {
131 if let Some(config) = stack.config_v4() {
132 return config.clone();
133 }
134 yield_now().await;
135 }
136}
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
new file mode 100644
index 000000000..9dd7ae973
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs
@@ -0,0 +1,124 @@
1//! This example implements a TCP client that attempts to connect to a host on port 1234 and send it some data once per second.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use core::str::FromStr;
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::{Stack, StackResources};
15use embassy_net_w5500::*;
16use embassy_rp::clocks::RoscRng;
17use embassy_rp::gpio::{Input, Level, Output, Pull};
18use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
19use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
20use embassy_time::{Delay, Duration, Timer};
21use embedded_hal_async::spi::ExclusiveDevice;
22use embedded_io::asynch::Write;
23use rand::RngCore;
24use static_cell::make_static;
25use {defmt_rtt as _, panic_probe as _};
26
27#[embassy_executor::task]
28async fn ethernet_task(
29 runner: Runner<
30 'static,
31 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
32 Input<'static, PIN_21>,
33 Output<'static, PIN_20>,
34 >,
35) -> ! {
36 runner.run().await
37}
38
39#[embassy_executor::task]
40async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
41 stack.run().await
42}
43
44#[embassy_executor::main]
45async fn main(spawner: Spawner) {
46 let p = embassy_rp::init(Default::default());
47 let mut rng = RoscRng;
48 let mut led = Output::new(p.PIN_25, Level::Low);
49
50 let mut spi_cfg = SpiConfig::default();
51 spi_cfg.frequency = 50_000_000;
52 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
53 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
54 let cs = Output::new(p.PIN_17, Level::High);
55 let w5500_int = Input::new(p.PIN_21, Pull::Up);
56 let w5500_reset = Output::new(p.PIN_20, Level::High);
57
58 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
59 let state = make_static!(State::<8, 8>::new());
60 let (device, runner) = embassy_net_w5500::new(
61 mac_addr,
62 state,
63 ExclusiveDevice::new(spi, cs, Delay),
64 w5500_int,
65 w5500_reset,
66 )
67 .await;
68 unwrap!(spawner.spawn(ethernet_task(runner)));
69
70 // Generate random seed
71 let seed = rng.next_u64();
72
73 // Init network stack
74 let stack = &*make_static!(Stack::new(
75 device,
76 embassy_net::Config::dhcpv4(Default::default()),
77 make_static!(StackResources::<2>::new()),
78 seed
79 ));
80
81 // Launch network task
82 unwrap!(spawner.spawn(net_task(&stack)));
83
84 info!("Waiting for DHCP...");
85 let cfg = wait_for_config(stack).await;
86 let local_addr = cfg.address.address();
87 info!("IP address: {:?}", local_addr);
88
89 let mut rx_buffer = [0; 4096];
90 let mut tx_buffer = [0; 4096];
91 loop {
92 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
93 socket.set_timeout(Some(Duration::from_secs(10)));
94
95 led.set_low();
96 info!("Connecting...");
97 let host_addr = embassy_net::Ipv4Address::from_str("192.168.1.110").unwrap();
98 if let Err(e) = socket.connect((host_addr, 1234)).await {
99 warn!("connect error: {:?}", e);
100 continue;
101 }
102 info!("Connected to {:?}", socket.remote_endpoint());
103 led.set_high();
104
105 let msg = b"Hello world!\n";
106 loop {
107 if let Err(e) = socket.write_all(msg).await {
108 warn!("write error: {:?}", e);
109 break;
110 }
111 info!("txd: {}", core::str::from_utf8(msg).unwrap());
112 Timer::after(Duration::from_secs(1)).await;
113 }
114 }
115}
116
117async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
118 loop {
119 if let Some(config) = stack.config_v4() {
120 return config.clone();
121 }
122 yield_now().await;
123 }
124}
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
new file mode 100644
index 000000000..db21c2b6f
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs
@@ -0,0 +1,132 @@
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 W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
5
6#![no_std]
7#![no_main]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_futures::yield_now;
13use embassy_net::{Stack, StackResources};
14use embassy_net_w5500::*;
15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::{Delay, Duration};
20use embedded_hal_async::spi::ExclusiveDevice;
21use embedded_io::asynch::Write;
22use rand::RngCore;
23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _};
25#[embassy_executor::task]
26async fn ethernet_task(
27 runner: Runner<
28 'static,
29 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
30 Input<'static, PIN_21>,
31 Output<'static, PIN_20>,
32 >,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 let p = embassy_rp::init(Default::default());
45 let mut rng = RoscRng;
46 let mut led = Output::new(p.PIN_25, Level::Low);
47
48 let mut spi_cfg = SpiConfig::default();
49 spi_cfg.frequency = 50_000_000;
50 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
51 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
52 let cs = Output::new(p.PIN_17, Level::High);
53 let w5500_int = Input::new(p.PIN_21, Pull::Up);
54 let w5500_reset = Output::new(p.PIN_20, Level::High);
55
56 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
57 let state = make_static!(State::<8, 8>::new());
58 let (device, runner) = embassy_net_w5500::new(
59 mac_addr,
60 state,
61 ExclusiveDevice::new(spi, cs, Delay),
62 w5500_int,
63 w5500_reset,
64 )
65 .await;
66 unwrap!(spawner.spawn(ethernet_task(runner)));
67
68 // Generate random seed
69 let seed = rng.next_u64();
70
71 // Init network stack
72 let stack = &*make_static!(Stack::new(
73 device,
74 embassy_net::Config::dhcpv4(Default::default()),
75 make_static!(StackResources::<2>::new()),
76 seed
77 ));
78
79 // Launch network task
80 unwrap!(spawner.spawn(net_task(&stack)));
81
82 info!("Waiting for DHCP...");
83 let cfg = wait_for_config(stack).await;
84 let local_addr = cfg.address.address();
85 info!("IP address: {:?}", local_addr);
86
87 let mut rx_buffer = [0; 4096];
88 let mut tx_buffer = [0; 4096];
89 let mut buf = [0; 4096];
90 loop {
91 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
92 socket.set_timeout(Some(Duration::from_secs(10)));
93
94 led.set_low();
95 info!("Listening on TCP:1234...");
96 if let Err(e) = socket.accept(1234).await {
97 warn!("accept error: {:?}", e);
98 continue;
99 }
100 info!("Received connection from {:?}", socket.remote_endpoint());
101 led.set_high();
102
103 loop {
104 let n = match socket.read(&mut buf).await {
105 Ok(0) => {
106 warn!("read EOF");
107 break;
108 }
109 Ok(n) => n,
110 Err(e) => {
111 warn!("{:?}", e);
112 break;
113 }
114 };
115 info!("rxd {}", core::str::from_utf8(&buf[..n]).unwrap());
116
117 if let Err(e) = socket.write_all(&buf[..n]).await {
118 warn!("write error: {:?}", e);
119 break;
120 }
121 }
122 }
123}
124
125async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
126 loop {
127 if let Some(config) = stack.config_v4() {
128 return config.clone();
129 }
130 yield_now().await;
131 }
132}
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs
new file mode 100644
index 000000000..038432b17
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w5500_udp.rs
@@ -0,0 +1,112 @@
1//! This example implements a UDP server listening on port 1234 and echoing back the data.
2//!
3//! Example written for the [`WIZnet W5500-EVB-Pico`](https://www.wiznet.io/product-item/w5500-evb-pico/) board.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_futures::yield_now;
12use embassy_net::udp::{PacketMetadata, UdpSocket};
13use embassy_net::{Stack, StackResources};
14use embassy_net_w5500::*;
15use embassy_rp::clocks::RoscRng;
16use embassy_rp::gpio::{Input, Level, Output, Pull};
17use embassy_rp::peripherals::{PIN_17, PIN_20, PIN_21, SPI0};
18use embassy_rp::spi::{Async, Config as SpiConfig, Spi};
19use embassy_time::Delay;
20use embedded_hal_async::spi::ExclusiveDevice;
21use rand::RngCore;
22use static_cell::make_static;
23use {defmt_rtt as _, panic_probe as _};
24#[embassy_executor::task]
25async fn ethernet_task(
26 runner: Runner<
27 'static,
28 ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>,
29 Input<'static, PIN_21>,
30 Output<'static, PIN_20>,
31 >,
32) -> ! {
33 runner.run().await
34}
35
36#[embassy_executor::task]
37async fn net_task(stack: &'static Stack<Device<'static>>) -> ! {
38 stack.run().await
39}
40
41#[embassy_executor::main]
42async fn main(spawner: Spawner) {
43 let p = embassy_rp::init(Default::default());
44 let mut rng = RoscRng;
45
46 let mut spi_cfg = SpiConfig::default();
47 spi_cfg.frequency = 50_000_000;
48 let (miso, mosi, clk) = (p.PIN_16, p.PIN_19, p.PIN_18);
49 let spi = Spi::new(p.SPI0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
50 let cs = Output::new(p.PIN_17, Level::High);
51 let w5500_int = Input::new(p.PIN_21, Pull::Up);
52 let w5500_reset = Output::new(p.PIN_20, Level::High);
53
54 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
55 let state = make_static!(State::<8, 8>::new());
56 let (device, runner) = embassy_net_w5500::new(
57 mac_addr,
58 state,
59 ExclusiveDevice::new(spi, cs, Delay),
60 w5500_int,
61 w5500_reset,
62 )
63 .await;
64 unwrap!(spawner.spawn(ethernet_task(runner)));
65
66 // Generate random seed
67 let seed = rng.next_u64();
68
69 // Init network stack
70 let stack = &*make_static!(Stack::new(
71 device,
72 embassy_net::Config::dhcpv4(Default::default()),
73 make_static!(StackResources::<2>::new()),
74 seed
75 ));
76
77 // Launch network task
78 unwrap!(spawner.spawn(net_task(&stack)));
79
80 info!("Waiting for DHCP...");
81 let cfg = wait_for_config(stack).await;
82 let local_addr = cfg.address.address();
83 info!("IP address: {:?}", local_addr);
84
85 // Then we can use it!
86 let mut rx_buffer = [0; 4096];
87 let mut tx_buffer = [0; 4096];
88 let mut rx_meta = [PacketMetadata::EMPTY; 16];
89 let mut tx_meta = [PacketMetadata::EMPTY; 16];
90 let mut buf = [0; 4096];
91 loop {
92 let mut socket = UdpSocket::new(stack, &mut rx_meta, &mut rx_buffer, &mut tx_meta, &mut tx_buffer);
93 socket.bind(1234).unwrap();
94
95 loop {
96 let (n, ep) = socket.recv_from(&mut buf).await.unwrap();
97 if let Ok(s) = core::str::from_utf8(&buf[..n]) {
98 info!("rxd from {}: {}", ep, s);
99 }
100 socket.send_to(&buf[..n], ep).await.unwrap();
101 }
102 }
103}
104
105async fn wait_for_config(stack: &'static Stack<Device<'static>>) -> embassy_net::StaticConfigV4 {
106 loop {
107 if let Some(config) = stack.config_v4() {
108 return config.clone();
109 }
110 yield_now().await;
111 }
112}
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
new file mode 100644
index 000000000..4c4982acc
--- /dev/null
+++ b/examples/rp/src/bin/flash.rs
@@ -0,0 +1,101 @@
1//! This example test the flash connected to the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::flash::{ERASE_SIZE, FLASH_BASE};
10use embassy_rp::peripherals::FLASH;
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14const ADDR_OFFSET: u32 = 0x100000;
15const FLASH_SIZE: usize = 2 * 1024 * 1024;
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 info!("Hello World!");
21
22 // add some delay to give an attached debug probe time to parse the
23 // defmt RTT header. Reading that header might touch flash memory, which
24 // interferes with flash write operations.
25 // https://github.com/knurling-rs/defmt/pull/683
26 Timer::after(Duration::from_millis(10)).await;
27
28 let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH);
29
30 // Get JEDEC id
31 let jedec = flash.jedec_id().unwrap();
32 info!("jedec id: 0x{:x}", jedec);
33
34 // Get unique id
35 let mut uid = [0; 8];
36 flash.unique_id(&mut uid).unwrap();
37 info!("unique id: {:?}", uid);
38
39 erase_write_sector(&mut flash, 0x00);
40
41 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
42
43 loop {}
44}
45
46fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
47 info!(">>>> [multiwrite_bytes]");
48 let mut read_buf = [0u8; ERASE_SIZE];
49 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
50
51 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
52 info!("Contents start with {=[u8]}", read_buf[0..4]);
53
54 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
55
56 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
57 info!("Contents after erase starts with {=[u8]}", read_buf[0..4]);
58 if read_buf.iter().any(|x| *x != 0xFF) {
59 defmt::panic!("unexpected");
60 }
61
62 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &[0x01]));
63 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 1, &[0x02]));
64 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 2, &[0x03]));
65 defmt::unwrap!(flash.write(ADDR_OFFSET + offset + 3, &[0x04]));
66
67 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut read_buf));
68 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
69 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] {
70 defmt::panic!("unexpected");
71 }
72}
73
74fn erase_write_sector(flash: &mut embassy_rp::flash::Flash<'_, FLASH, FLASH_SIZE>, offset: u32) {
75 info!(">>>> [erase_write_sector]");
76 let mut buf = [0u8; ERASE_SIZE];
77 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
78
79 info!("Addr of flash block is {:x}", ADDR_OFFSET + offset + FLASH_BASE as u32);
80 info!("Contents start with {=[u8]}", buf[0..4]);
81
82 defmt::unwrap!(flash.erase(ADDR_OFFSET + offset, ADDR_OFFSET + offset + ERASE_SIZE as u32));
83
84 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
85 info!("Contents after erase starts with {=[u8]}", buf[0..4]);
86 if buf.iter().any(|x| *x != 0xFF) {
87 defmt::panic!("unexpected");
88 }
89
90 for b in buf.iter_mut() {
91 *b = 0xDA;
92 }
93
94 defmt::unwrap!(flash.write(ADDR_OFFSET + offset, &buf));
95
96 defmt::unwrap!(flash.read(ADDR_OFFSET + offset, &mut buf));
97 info!("Contents after write starts with {=[u8]}", buf[0..4]);
98 if buf.iter().any(|x| *x != 0xDA) {
99 defmt::panic!("unexpected");
100 }
101}
diff --git a/examples/rp/src/bin/gpio_async.rs b/examples/rp/src/bin/gpio_async.rs
index 52d13a9d5..bf58044d5 100644
--- a/examples/rp/src/bin/gpio_async.rs
+++ b/examples/rp/src/bin/gpio_async.rs
@@ -1,3 +1,7 @@
1//! This example shows how async gpio can be used with a RP2040.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -9,8 +13,6 @@ use embassy_time::{Duration, Timer};
9use gpio::{Input, Level, Output, Pull}; 13use gpio::{Input, Level, Output, Pull};
10use {defmt_rtt as _, panic_probe as _}; 14use {defmt_rtt as _, panic_probe as _};
11 15
12/// This example shows how async gpio can be used with a RP2040.
13///
14/// It requires an external signal to be manually triggered on PIN 16. For 16/// It requires an external signal to be manually triggered on PIN 16. For
15/// example, this could be accomplished using an external power source with a 17/// example, this could be accomplished using an external power source with a
16/// button so that it is possible to toggle the signal from low to high. 18/// button so that it is possible to toggle the signal from low to high.
diff --git a/examples/rp/src/bin/gpout.rs b/examples/rp/src/bin/gpout.rs
new file mode 100644
index 000000000..0a3b5fa98
--- /dev/null
+++ b/examples/rp/src/bin/gpout.rs
@@ -0,0 +1,38 @@
1//! This example shows how GPOUT (General purpose clock outputs) can toggle a output pin.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::clocks;
12use embassy_time::{Duration, Timer};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_rp::init(Default::default());
18
19 let gpout3 = clocks::Gpout::new(p.PIN_25);
20 gpout3.set_div(1000, 0);
21 gpout3.enable();
22
23 loop {
24 gpout3.set_src(clocks::GpoutSrc::Sys);
25 info!(
26 "Pin 25 is now outputing CLK_SYS/1000, should be toggling at {}",
27 gpout3.get_freq()
28 );
29 Timer::after(Duration::from_secs(2)).await;
30
31 gpout3.set_src(clocks::GpoutSrc::Ref);
32 info!(
33 "Pin 25 is now outputing CLK_REF/1000, should be toggling at {}",
34 gpout3.get_freq()
35 );
36 Timer::after(Duration::from_secs(2)).await;
37 }
38}
diff --git a/examples/rp/src/bin/i2c_async.rs b/examples/rp/src/bin/i2c_async.rs
new file mode 100644
index 000000000..93224bc43
--- /dev/null
+++ b/examples/rp/src/bin/i2c_async.rs
@@ -0,0 +1,111 @@
1//! This example shows how to communicate asynchronous using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
6#![no_std]
7#![no_main]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
13use embassy_rp::i2c::{self, Config, InterruptHandler};
14use embassy_rp::peripherals::I2C1;
15use embassy_time::{Duration, Timer};
16use embedded_hal_async::i2c::I2c;
17use {defmt_rtt as _, panic_probe as _};
18
19bind_interrupts!(struct Irqs {
20 I2C1_IRQ => InterruptHandler<I2C1>;
21});
22
23#[allow(dead_code)]
24mod mcp23017 {
25 pub const ADDR: u8 = 0x20; // default addr
26
27 macro_rules! mcpregs {
28 ($($name:ident : $val:expr),* $(,)?) => {
29 $(
30 pub const $name: u8 = $val;
31 )*
32
33 pub fn regname(reg: u8) -> &'static str {
34 match reg {
35 $(
36 $val => stringify!($name),
37 )*
38 _ => panic!("bad reg"),
39 }
40 }
41 }
42 }
43
44 // These are correct for IOCON.BANK=0
45 mcpregs! {
46 IODIRA: 0x00,
47 IPOLA: 0x02,
48 GPINTENA: 0x04,
49 DEFVALA: 0x06,
50 INTCONA: 0x08,
51 IOCONA: 0x0A,
52 GPPUA: 0x0C,
53 INTFA: 0x0E,
54 INTCAPA: 0x10,
55 GPIOA: 0x12,
56 OLATA: 0x14,
57 IODIRB: 0x01,
58 IPOLB: 0x03,
59 GPINTENB: 0x05,
60 DEFVALB: 0x07,
61 INTCONB: 0x09,
62 IOCONB: 0x0B,
63 GPPUB: 0x0D,
64 INTFB: 0x0F,
65 INTCAPB: 0x11,
66 GPIOB: 0x13,
67 OLATB: 0x15,
68 }
69}
70
71#[embassy_executor::main]
72async fn main(_spawner: Spawner) {
73 let p = embassy_rp::init(Default::default());
74
75 let sda = p.PIN_14;
76 let scl = p.PIN_15;
77
78 info!("set up i2c ");
79 let mut i2c = i2c::I2c::new_async(p.I2C1, scl, sda, Irqs, Config::default());
80
81 use mcp23017::*;
82
83 info!("init mcp23017 config for IxpandO");
84 // init - a outputs, b inputs
85 i2c.write(ADDR, &[IODIRA, 0x00]).await.unwrap();
86 i2c.write(ADDR, &[IODIRB, 0xff]).await.unwrap();
87 i2c.write(ADDR, &[GPPUB, 0xff]).await.unwrap(); // pullups
88
89 let mut val = 1;
90 loop {
91 let mut portb = [0];
92
93 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).await.unwrap();
94 info!("portb = {:02x}", portb[0]);
95 i2c.write(mcp23017::ADDR, &[GPIOA, val | portb[0]]).await.unwrap();
96 val = val.rotate_left(1);
97
98 // get a register dump
99 info!("getting register dump");
100 let mut regs = [0; 22];
101 i2c.write_read(ADDR, &[0], &mut regs).await.unwrap();
102 // always get the regdump but only display it if portb'0 is set
103 if portb[0] & 1 != 0 {
104 for (idx, reg) in regs.into_iter().enumerate() {
105 info!("{} => {:02x}", regname(idx as u8), reg);
106 }
107 }
108
109 Timer::after(Duration::from_millis(100)).await;
110 }
111}
diff --git a/examples/rp/src/bin/i2c_blocking.rs b/examples/rp/src/bin/i2c_blocking.rs
new file mode 100644
index 000000000..1c8c2039d
--- /dev/null
+++ b/examples/rp/src/bin/i2c_blocking.rs
@@ -0,0 +1,75 @@
1//! This example shows how to communicate using i2c with external chips.
2//!
3//! Example written for the [`MCP23017 16-Bit I2C I/O Expander with Serial Interface`] chip.
4//! (https://www.microchip.com/en-us/product/mcp23017)
5
6#![no_std]
7#![no_main]
8#![feature(type_alias_impl_trait)]
9
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::i2c::{self, Config};
13use embassy_time::{Duration, Timer};
14use embedded_hal_1::i2c::I2c;
15use {defmt_rtt as _, panic_probe as _};
16
17#[allow(dead_code)]
18mod mcp23017 {
19 pub const ADDR: u8 = 0x20; // default addr
20
21 pub const IODIRA: u8 = 0x00;
22 pub const IPOLA: u8 = 0x02;
23 pub const GPINTENA: u8 = 0x04;
24 pub const DEFVALA: u8 = 0x06;
25 pub const INTCONA: u8 = 0x08;
26 pub const IOCONA: u8 = 0x0A;
27 pub const GPPUA: u8 = 0x0C;
28 pub const INTFA: u8 = 0x0E;
29 pub const INTCAPA: u8 = 0x10;
30 pub const GPIOA: u8 = 0x12;
31 pub const OLATA: u8 = 0x14;
32 pub const IODIRB: u8 = 0x01;
33 pub const IPOLB: u8 = 0x03;
34 pub const GPINTENB: u8 = 0x05;
35 pub const DEFVALB: u8 = 0x07;
36 pub const INTCONB: u8 = 0x09;
37 pub const IOCONB: u8 = 0x0B;
38 pub const GPPUB: u8 = 0x0D;
39 pub const INTFB: u8 = 0x0F;
40 pub const INTCAPB: u8 = 0x11;
41 pub const GPIOB: u8 = 0x13;
42 pub const OLATB: u8 = 0x15;
43}
44
45#[embassy_executor::main]
46async fn main(_spawner: Spawner) {
47 let p = embassy_rp::init(Default::default());
48
49 let sda = p.PIN_14;
50 let scl = p.PIN_15;
51
52 info!("set up i2c ");
53 let mut i2c = i2c::I2c::new_blocking(p.I2C1, scl, sda, Config::default());
54
55 use mcp23017::*;
56
57 info!("init mcp23017 config for IxpandO");
58 // init - a outputs, b inputs
59 i2c.write(ADDR, &[IODIRA, 0x00]).unwrap();
60 i2c.write(ADDR, &[IODIRB, 0xff]).unwrap();
61 i2c.write(ADDR, &[GPPUB, 0xff]).unwrap(); // pullups
62
63 let mut val = 0xaa;
64 loop {
65 let mut portb = [0];
66
67 i2c.write(mcp23017::ADDR, &[GPIOA, val]).unwrap();
68 i2c.write_read(mcp23017::ADDR, &[GPIOB], &mut portb).unwrap();
69
70 info!("portb = {:02x}", portb[0]);
71 val = !val;
72
73 Timer::after(Duration::from_secs(1)).await;
74 }
75}
diff --git a/examples/rp/src/bin/lora_lorawan.rs b/examples/rp/src/bin/lora_lorawan.rs
new file mode 100644
index 000000000..d631fafa1
--- /dev/null
+++ b/examples/rp/src/bin/lora_lorawan.rs
@@ -0,0 +1,81 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LoRaWAN join functionality.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_lora::LoraTimer;
13use embassy_rp::gpio::{Input, Level, Output, Pin, Pull};
14use embassy_rp::spi::{Config, Spi};
15use embassy_time::Delay;
16use lora_phy::mod_params::*;
17use lora_phy::sx1261_2::SX1261_2;
18use lora_phy::LoRa;
19use lorawan::default_crypto::DefaultFactory as Crypto;
20use lorawan_device::async_device::lora_radio::LoRaRadio;
21use lorawan_device::async_device::{region, Device, JoinMode};
22use {defmt_rtt as _, panic_probe as _};
23
24const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set this appropriately for the region
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 let p = embassy_rp::init(Default::default());
29
30 let miso = p.PIN_12;
31 let mosi = p.PIN_11;
32 let clk = p.PIN_10;
33 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
34
35 let nss = Output::new(p.PIN_3.degrade(), Level::High);
36 let reset = Output::new(p.PIN_15.degrade(), Level::High);
37 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
38 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
39
40 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
41
42 let mut delay = Delay;
43
44 let lora = {
45 match LoRa::new(
46 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
47 true,
48 &mut delay,
49 )
50 .await
51 {
52 Ok(l) => l,
53 Err(err) => {
54 info!("Radio error = {}", err);
55 return;
56 }
57 }
58 };
59
60 let radio = LoRaRadio::new(lora);
61 let region: region::Configuration = region::Configuration::new(LORAWAN_REGION);
62 let mut device: Device<_, Crypto, _, _> = Device::new(region, radio, LoraTimer::new(), embassy_rp::clocks::RoscRng);
63
64 defmt::info!("Joining LoRaWAN network");
65
66 // TODO: Adjust the EUI and Keys according to your network credentials
67 match device
68 .join(&JoinMode::OTAA {
69 deveui: [0, 0, 0, 0, 0, 0, 0, 0],
70 appeui: [0, 0, 0, 0, 0, 0, 0, 0],
71 appkey: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
72 })
73 .await
74 {
75 Ok(()) => defmt::info!("LoRaWAN network joined"),
76 Err(err) => {
77 info!("Radio error = {}", err);
78 return;
79 }
80 };
81}
diff --git a/examples/rp/src/bin/lora_p2p_receive.rs b/examples/rp/src/bin/lora_p2p_receive.rs
new file mode 100644
index 000000000..396d669de
--- /dev/null
+++ b/examples/rp/src/bin/lora_p2p_receive.rs
@@ -0,0 +1,116 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P receive functionality in conjunction with the lora_p2p_send example.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{Input, Level, Output, Pin, Pull};
13use embassy_rp::spi::{Config, Spi};
14use embassy_time::{Delay, Duration, Timer};
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25
26 let miso = p.PIN_12;
27 let mosi = p.PIN_11;
28 let clk = p.PIN_10;
29 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
30
31 let nss = Output::new(p.PIN_3.degrade(), Level::High);
32 let reset = Output::new(p.PIN_15.degrade(), Level::High);
33 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
34 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
35
36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
37
38 let mut delay = Delay;
39
40 let mut lora = {
41 match LoRa::new(
42 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
43 false,
44 &mut delay,
45 )
46 .await
47 {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mut debug_indicator = Output::new(p.PIN_25, Level::Low);
57
58 let mut receiving_buffer = [00u8; 100];
59
60 let mdltn_params = {
61 match lora.create_modulation_params(
62 SpreadingFactor::_10,
63 Bandwidth::_250KHz,
64 CodingRate::_4_8,
65 LORA_FREQUENCY_IN_HZ,
66 ) {
67 Ok(mp) => mp,
68 Err(err) => {
69 info!("Radio error = {}", err);
70 return;
71 }
72 }
73 };
74
75 let rx_pkt_params = {
76 match lora.create_rx_packet_params(4, false, receiving_buffer.len() as u8, true, false, &mdltn_params) {
77 Ok(pp) => pp,
78 Err(err) => {
79 info!("Radio error = {}", err);
80 return;
81 }
82 }
83 };
84
85 match lora
86 .prepare_for_rx(&mdltn_params, &rx_pkt_params, None, true, false, 0, 0x00ffffffu32)
87 .await
88 {
89 Ok(()) => {}
90 Err(err) => {
91 info!("Radio error = {}", err);
92 return;
93 }
94 };
95
96 loop {
97 receiving_buffer = [00u8; 100];
98 match lora.rx(&rx_pkt_params, &mut receiving_buffer).await {
99 Ok((received_len, _rx_pkt_status)) => {
100 if (received_len == 3)
101 && (receiving_buffer[0] == 0x01u8)
102 && (receiving_buffer[1] == 0x02u8)
103 && (receiving_buffer[2] == 0x03u8)
104 {
105 info!("rx successful");
106 debug_indicator.set_high();
107 Timer::after(Duration::from_secs(5)).await;
108 debug_indicator.set_low();
109 } else {
110 info!("rx unknown packet");
111 }
112 }
113 Err(err) => info!("rx unsuccessful = {}", err),
114 }
115 }
116}
diff --git a/examples/rp/src/bin/lora_p2p_send.rs b/examples/rp/src/bin/lora_p2p_send.rs
new file mode 100644
index 000000000..a0f70fa5c
--- /dev/null
+++ b/examples/rp/src/bin/lora_p2p_send.rs
@@ -0,0 +1,104 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{Input, Level, Output, Pin, Pull};
13use embassy_rp::spi::{Config, Spi};
14use embassy_time::Delay;
15use lora_phy::mod_params::*;
16use lora_phy::sx1261_2::SX1261_2;
17use lora_phy::LoRa;
18use {defmt_rtt as _, panic_probe as _};
19
20const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
21
22#[embassy_executor::main]
23async fn main(_spawner: Spawner) {
24 let p = embassy_rp::init(Default::default());
25
26 let miso = p.PIN_12;
27 let mosi = p.PIN_11;
28 let clk = p.PIN_10;
29 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
30
31 let nss = Output::new(p.PIN_3.degrade(), Level::High);
32 let reset = Output::new(p.PIN_15.degrade(), Level::High);
33 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
34 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
35
36 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
37
38 let mut delay = Delay;
39
40 let mut lora = {
41 match LoRa::new(
42 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
43 false,
44 &mut delay,
45 )
46 .await
47 {
48 Ok(l) => l,
49 Err(err) => {
50 info!("Radio error = {}", err);
51 return;
52 }
53 }
54 };
55
56 let mdltn_params = {
57 match lora.create_modulation_params(
58 SpreadingFactor::_10,
59 Bandwidth::_250KHz,
60 CodingRate::_4_8,
61 LORA_FREQUENCY_IN_HZ,
62 ) {
63 Ok(mp) => mp,
64 Err(err) => {
65 info!("Radio error = {}", err);
66 return;
67 }
68 }
69 };
70
71 let mut tx_pkt_params = {
72 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
73 Ok(pp) => pp,
74 Err(err) => {
75 info!("Radio error = {}", err);
76 return;
77 }
78 }
79 };
80
81 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
82 Ok(()) => {}
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 };
88
89 let buffer = [0x01u8, 0x02u8, 0x03u8];
90 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
91 Ok(()) => {
92 info!("TX DONE");
93 }
94 Err(err) => {
95 info!("Radio error = {}", err);
96 return;
97 }
98 };
99
100 match lora.sleep(&mut delay).await {
101 Ok(()) => info!("Sleep successful"),
102 Err(err) => info!("Sleep unsuccessful = {}", err),
103 }
104}
diff --git a/examples/rp/src/bin/lora_p2p_send_multicore.rs b/examples/rp/src/bin/lora_p2p_send_multicore.rs
new file mode 100644
index 000000000..89a62818d
--- /dev/null
+++ b/examples/rp/src/bin/lora_p2p_send_multicore.rs
@@ -0,0 +1,140 @@
1//! This example runs on the Raspberry Pi Pico with a Waveshare board containing a Semtech Sx1262 radio.
2//! It demonstrates LORA P2P send functionality using the second core, with data provided by the first core.
3
4#![no_std]
5#![no_main]
6#![macro_use]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Executor;
11use embassy_lora::iv::GenericSx126xInterfaceVariant;
12use embassy_rp::gpio::{AnyPin, Input, Level, Output, Pin, Pull};
13use embassy_rp::multicore::{spawn_core1, Stack};
14use embassy_rp::peripherals::SPI1;
15use embassy_rp::spi::{Async, Config, Spi};
16use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
17use embassy_sync::channel::Channel;
18use embassy_time::{Delay, Duration, Timer};
19use lora_phy::mod_params::*;
20use lora_phy::sx1261_2::SX1261_2;
21use lora_phy::LoRa;
22use static_cell::StaticCell;
23use {defmt_rtt as _, panic_probe as _};
24
25static mut CORE1_STACK: Stack<4096> = Stack::new();
26static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
27static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
28static CHANNEL: Channel<CriticalSectionRawMutex, [u8; 3], 1> = Channel::new();
29
30const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriately for the region
31
32#[cortex_m_rt::entry]
33fn main() -> ! {
34 let p = embassy_rp::init(Default::default());
35
36 let miso = p.PIN_12;
37 let mosi = p.PIN_11;
38 let clk = p.PIN_10;
39 let spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
40
41 let nss = Output::new(p.PIN_3.degrade(), Level::High);
42 let reset = Output::new(p.PIN_15.degrade(), Level::High);
43 let dio1 = Input::new(p.PIN_20.degrade(), Pull::None);
44 let busy = Input::new(p.PIN_2.degrade(), Pull::None);
45
46 let iv = GenericSx126xInterfaceVariant::new(nss, reset, dio1, busy, None, None).unwrap();
47
48 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
49 let executor1 = EXECUTOR1.init(Executor::new());
50 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(spi, iv))));
51 });
52
53 let executor0 = EXECUTOR0.init(Executor::new());
54 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
55}
56
57#[embassy_executor::task]
58async fn core0_task() {
59 info!("Hello from core 0");
60 loop {
61 CHANNEL.send([0x01u8, 0x02u8, 0x03u8]).await;
62 Timer::after(Duration::from_millis(60 * 1000)).await;
63 }
64}
65
66#[embassy_executor::task]
67async fn core1_task(
68 spi: Spi<'static, SPI1, Async>,
69 iv: GenericSx126xInterfaceVariant<Output<'static, AnyPin>, Input<'static, AnyPin>>,
70) {
71 info!("Hello from core 1");
72 let mut delay = Delay;
73
74 let mut lora = {
75 match LoRa::new(
76 SX1261_2::new(BoardType::RpPicoWaveshareSx1262, spi, iv),
77 false,
78 &mut delay,
79 )
80 .await
81 {
82 Ok(l) => l,
83 Err(err) => {
84 info!("Radio error = {}", err);
85 return;
86 }
87 }
88 };
89
90 let mdltn_params = {
91 match lora.create_modulation_params(
92 SpreadingFactor::_10,
93 Bandwidth::_250KHz,
94 CodingRate::_4_8,
95 LORA_FREQUENCY_IN_HZ,
96 ) {
97 Ok(mp) => mp,
98 Err(err) => {
99 info!("Radio error = {}", err);
100 return;
101 }
102 }
103 };
104
105 let mut tx_pkt_params = {
106 match lora.create_tx_packet_params(4, false, true, false, &mdltn_params) {
107 Ok(pp) => pp,
108 Err(err) => {
109 info!("Radio error = {}", err);
110 return;
111 }
112 }
113 };
114
115 loop {
116 let buffer: [u8; 3] = CHANNEL.recv().await;
117 match lora.prepare_for_tx(&mdltn_params, 20, false).await {
118 Ok(()) => {}
119 Err(err) => {
120 info!("Radio error = {}", err);
121 return;
122 }
123 };
124
125 match lora.tx(&mdltn_params, &mut tx_pkt_params, &buffer, 0xffffff).await {
126 Ok(()) => {
127 info!("TX DONE");
128 }
129 Err(err) => {
130 info!("Radio error = {}", err);
131 return;
132 }
133 };
134
135 match lora.sleep(&mut delay).await {
136 Ok(()) => info!("Sleep successful"),
137 Err(err) => info!("Sleep unsuccessful = {}", err),
138 }
139 }
140}
diff --git a/examples/rp/src/bin/multicore.rs b/examples/rp/src/bin/multicore.rs
new file mode 100644
index 000000000..893b724bf
--- /dev/null
+++ b/examples/rp/src/bin/multicore.rs
@@ -0,0 +1,64 @@
1//! This example shows how to send messages between the two cores in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. See wifi_blinky.rs.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Executor;
11use embassy_rp::gpio::{Level, Output};
12use embassy_rp::multicore::{spawn_core1, Stack};
13use embassy_rp::peripherals::PIN_25;
14use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
15use embassy_sync::channel::Channel;
16use embassy_time::{Duration, Timer};
17use static_cell::StaticCell;
18use {defmt_rtt as _, panic_probe as _};
19
20static mut CORE1_STACK: Stack<4096> = Stack::new();
21static EXECUTOR0: StaticCell<Executor> = StaticCell::new();
22static EXECUTOR1: StaticCell<Executor> = StaticCell::new();
23static CHANNEL: Channel<CriticalSectionRawMutex, LedState, 1> = Channel::new();
24
25enum LedState {
26 On,
27 Off,
28}
29
30#[cortex_m_rt::entry]
31fn main() -> ! {
32 let p = embassy_rp::init(Default::default());
33 let led = Output::new(p.PIN_25, Level::Low);
34
35 spawn_core1(p.CORE1, unsafe { &mut CORE1_STACK }, move || {
36 let executor1 = EXECUTOR1.init(Executor::new());
37 executor1.run(|spawner| unwrap!(spawner.spawn(core1_task(led))));
38 });
39
40 let executor0 = EXECUTOR0.init(Executor::new());
41 executor0.run(|spawner| unwrap!(spawner.spawn(core0_task())));
42}
43
44#[embassy_executor::task]
45async fn core0_task() {
46 info!("Hello from core 0");
47 loop {
48 CHANNEL.send(LedState::On).await;
49 Timer::after(Duration::from_millis(100)).await;
50 CHANNEL.send(LedState::Off).await;
51 Timer::after(Duration::from_millis(400)).await;
52 }
53}
54
55#[embassy_executor::task]
56async fn core1_task(mut led: Output<'static, PIN_25>) {
57 info!("Hello from core 1");
58 loop {
59 match CHANNEL.recv().await {
60 LedState::On => led.set_high(),
61 LedState::Off => led.set_low(),
62 }
63 }
64}
diff --git a/examples/rp/src/bin/multiprio.rs b/examples/rp/src/bin/multiprio.rs
new file mode 100644
index 000000000..9ace4cd68
--- /dev/null
+++ b/examples/rp/src/bin/multiprio.rs
@@ -0,0 +1,146 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58#![feature(type_alias_impl_trait)]
59
60use cortex_m_rt::entry;
61use defmt::{info, unwrap};
62use embassy_executor::{Executor, InterruptExecutor};
63use embassy_rp::interrupt;
64use embassy_rp::interrupt::{InterruptExt, Priority};
65use embassy_time::{Duration, Instant, Timer, TICK_HZ};
66use static_cell::StaticCell;
67use {defmt_rtt as _, panic_probe as _};
68
69#[embassy_executor::task]
70async fn run_high() {
71 loop {
72 info!(" [high] tick!");
73 Timer::after(Duration::from_ticks(673740)).await;
74 }
75}
76
77#[embassy_executor::task]
78async fn run_med() {
79 loop {
80 let start = Instant::now();
81 info!(" [med] Starting long computation");
82
83 // Spin-wait to simulate a long CPU computation
84 cortex_m::asm::delay(125_000_000); // ~1 second
85
86 let end = Instant::now();
87 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
88 info!(" [med] done in {} ms", ms);
89
90 Timer::after(Duration::from_ticks(53421)).await;
91 }
92}
93
94#[embassy_executor::task]
95async fn run_low() {
96 loop {
97 let start = Instant::now();
98 info!("[low] Starting long computation");
99
100 // Spin-wait to simulate a long CPU computation
101 cortex_m::asm::delay(250_000_000); // ~2 seconds
102
103 let end = Instant::now();
104 let ms = end.duration_since(start).as_ticks() * 1000 / TICK_HZ;
105 info!("[low] done in {} ms", ms);
106
107 Timer::after(Duration::from_ticks(82983)).await;
108 }
109}
110
111static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
113static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
114
115#[interrupt]
116unsafe fn SWI_IRQ_1() {
117 EXECUTOR_HIGH.on_interrupt()
118}
119
120#[interrupt]
121unsafe fn SWI_IRQ_0() {
122 EXECUTOR_MED.on_interrupt()
123}
124
125#[entry]
126fn main() -> ! {
127 info!("Hello World!");
128
129 let _p = embassy_rp::init(Default::default());
130
131 // High-priority executor: SWI_IRQ_1, priority level 2
132 interrupt::SWI_IRQ_1.set_priority(Priority::P2);
133 let spawner = EXECUTOR_HIGH.start(interrupt::SWI_IRQ_1);
134 unwrap!(spawner.spawn(run_high()));
135
136 // Medium-priority executor: SWI_IRQ_0, priority level 3
137 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
138 let spawner = EXECUTOR_MED.start(interrupt::SWI_IRQ_0);
139 unwrap!(spawner.spawn(run_med()));
140
141 // Low priority executor: runs in thread mode, using WFE/SEV
142 let executor = EXECUTOR_LOW.init(Executor::new());
143 executor.run(|spawner| {
144 unwrap!(spawner.spawn(run_low()));
145 });
146}
diff --git a/examples/rp/src/bin/pio_async.rs b/examples/rp/src/bin/pio_async.rs
new file mode 100644
index 000000000..c001d6440
--- /dev/null
+++ b/examples/rp/src/bin/pio_async.rs
@@ -0,0 +1,135 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_rp::bind_interrupts;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Common, Config, InterruptHandler, Irq, Pio, PioPin, ShiftDirection, StateMachine};
11use embassy_rp::relocate::RelocatedProgram;
12use fixed::traits::ToFixed;
13use fixed_macro::types::U56F8;
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 PIO0_IRQ_0 => InterruptHandler<PIO0>;
18});
19
20fn setup_pio_task_sm0<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 0>, pin: impl PioPin) {
21 // Setup sm0
22
23 // Send data serially to pin
24 let prg = pio_proc::pio_asm!(
25 ".origin 16",
26 "set pindirs, 1",
27 ".wrap_target",
28 "out pins,1 [19]",
29 ".wrap",
30 );
31
32 let relocated = RelocatedProgram::new(&prg.program);
33 let mut cfg = Config::default();
34 cfg.use_program(&pio.load_program(&relocated), &[]);
35 let out_pin = pio.make_pio_pin(pin);
36 cfg.set_out_pins(&[&out_pin]);
37 cfg.set_set_pins(&[&out_pin]);
38 cfg.clock_divider = (U56F8!(125_000_000) / 20 / 200).to_fixed();
39 cfg.shift_out.auto_fill = true;
40 sm.set_config(&cfg);
41}
42
43#[embassy_executor::task]
44async fn pio_task_sm0(mut sm: StateMachine<'static, PIO0, 0>) {
45 sm.set_enable(true);
46
47 let mut v = 0x0f0caffa;
48 loop {
49 sm.tx().wait_push(v).await;
50 v ^= 0xffff;
51 info!("Pushed {:032b} to FIFO", v);
52 }
53}
54
55fn setup_pio_task_sm1<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 1>) {
56 // Setupm sm1
57
58 // Read 0b10101 repeatedly until ISR is full
59 let prg = pio_proc::pio_asm!(
60 //
61 ".origin 8",
62 "set x, 0x15",
63 ".wrap_target",
64 "in x, 5 [31]",
65 ".wrap",
66 );
67
68 let relocated = RelocatedProgram::new(&prg.program);
69 let mut cfg = Config::default();
70 cfg.use_program(&pio.load_program(&relocated), &[]);
71 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
72 cfg.shift_in.auto_fill = true;
73 cfg.shift_in.direction = ShiftDirection::Right;
74 sm.set_config(&cfg);
75}
76
77#[embassy_executor::task]
78async fn pio_task_sm1(mut sm: StateMachine<'static, PIO0, 1>) {
79 sm.set_enable(true);
80 loop {
81 let rx = sm.rx().wait_pull().await;
82 info!("Pulled {:032b} from FIFO", rx);
83 }
84}
85
86fn setup_pio_task_sm2<'a>(pio: &mut Common<'a, PIO0>, sm: &mut StateMachine<'a, PIO0, 2>) {
87 // Setup sm2
88
89 // Repeatedly trigger IRQ 3
90 let prg = pio_proc::pio_asm!(
91 ".origin 0",
92 ".wrap_target",
93 "set x,10",
94 "delay:",
95 "jmp x-- delay [15]",
96 "irq 3 [15]",
97 ".wrap",
98 );
99 let relocated = RelocatedProgram::new(&prg.program);
100 let mut cfg = Config::default();
101 cfg.use_program(&pio.load_program(&relocated), &[]);
102 cfg.clock_divider = (U56F8!(125_000_000) / 2000).to_fixed();
103 sm.set_config(&cfg);
104}
105
106#[embassy_executor::task]
107async fn pio_task_sm2(mut irq: Irq<'static, PIO0, 3>, mut sm: StateMachine<'static, PIO0, 2>) {
108 sm.set_enable(true);
109 loop {
110 irq.wait().await;
111 info!("IRQ trigged");
112 }
113}
114
115#[embassy_executor::main]
116async fn main(spawner: Spawner) {
117 let p = embassy_rp::init(Default::default());
118 let pio = p.PIO0;
119
120 let Pio {
121 mut common,
122 irq3,
123 mut sm0,
124 mut sm1,
125 mut sm2,
126 ..
127 } = Pio::new(pio, Irqs);
128
129 setup_pio_task_sm0(&mut common, &mut sm0, p.PIN_0);
130 setup_pio_task_sm1(&mut common, &mut sm1);
131 setup_pio_task_sm2(&mut common, &mut sm2);
132 spawner.spawn(pio_task_sm0(sm0)).unwrap();
133 spawner.spawn(pio_task_sm1(sm1)).unwrap();
134 spawner.spawn(pio_task_sm2(irq3, sm2)).unwrap();
135}
diff --git a/examples/rp/src/bin/pio_dma.rs b/examples/rp/src/bin/pio_dma.rs
new file mode 100644
index 000000000..9ab72e1f3
--- /dev/null
+++ b/examples/rp/src/bin/pio_dma.rs
@@ -0,0 +1,86 @@
1//! This example shows powerful PIO module in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6use defmt::info;
7use embassy_executor::Spawner;
8use embassy_futures::join::join;
9use embassy_rp::peripherals::PIO0;
10use embassy_rp::pio::{Config, InterruptHandler, Pio, ShiftConfig, ShiftDirection};
11use embassy_rp::relocate::RelocatedProgram;
12use embassy_rp::{bind_interrupts, Peripheral};
13use fixed::traits::ToFixed;
14use fixed_macro::types::U56F8;
15use {defmt_rtt as _, panic_probe as _};
16
17bind_interrupts!(struct Irqs {
18 PIO0_IRQ_0 => InterruptHandler<PIO0>;
19});
20
21fn swap_nibbles(v: u32) -> u32 {
22 let v = (v & 0x0f0f_0f0f) << 4 | (v & 0xf0f0_f0f0) >> 4;
23 let v = (v & 0x00ff_00ff) << 8 | (v & 0xff00_ff00) >> 8;
24 (v & 0x0000_ffff) << 16 | (v & 0xffff_0000) >> 16
25}
26
27#[embassy_executor::main]
28async fn main(_spawner: Spawner) {
29 let p = embassy_rp::init(Default::default());
30 let pio = p.PIO0;
31 let Pio {
32 mut common,
33 sm0: mut sm,
34 ..
35 } = Pio::new(pio, Irqs);
36
37 let prg = pio_proc::pio_asm!(
38 ".origin 0",
39 "set pindirs,1",
40 ".wrap_target",
41 "set y,7",
42 "loop:",
43 "out x,4",
44 "in x,4",
45 "jmp y--, loop",
46 ".wrap",
47 );
48
49 let relocated = RelocatedProgram::new(&prg.program);
50 let mut cfg = Config::default();
51 cfg.use_program(&common.load_program(&relocated), &[]);
52 cfg.clock_divider = (U56F8!(125_000_000) / U56F8!(10_000)).to_fixed();
53 cfg.shift_in = ShiftConfig {
54 auto_fill: true,
55 threshold: 32,
56 direction: ShiftDirection::Left,
57 };
58 cfg.shift_out = ShiftConfig {
59 auto_fill: true,
60 threshold: 32,
61 direction: ShiftDirection::Right,
62 };
63
64 sm.set_config(&cfg);
65 sm.set_enable(true);
66
67 let mut dma_out_ref = p.DMA_CH0.into_ref();
68 let mut dma_in_ref = p.DMA_CH1.into_ref();
69 let mut dout = [0x12345678u32; 29];
70 for i in 1..dout.len() {
71 dout[i] = (dout[i - 1] & 0x0fff_ffff) * 13 + 7;
72 }
73 let mut din = [0u32; 29];
74 loop {
75 let (rx, tx) = sm.rx_tx();
76 join(
77 tx.dma_push(dma_out_ref.reborrow(), &dout),
78 rx.dma_pull(dma_in_ref.reborrow(), &mut din),
79 )
80 .await;
81 for i in 0..din.len() {
82 assert_eq!(din[i], swap_nibbles(dout[i]));
83 }
84 info!("Swapped {} words", dout.len());
85 }
86}
diff --git a/examples/rp/src/bin/pio_hd44780.rs b/examples/rp/src/bin/pio_hd44780.rs
new file mode 100644
index 000000000..8aedd24b6
--- /dev/null
+++ b/examples/rp/src/bin/pio_hd44780.rs
@@ -0,0 +1,244 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with a HD44780 display.
2//! See (https://www.sparkfun.com/datasheets/LCD/HD44780.pdf)
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use core::fmt::Write;
9
10use embassy_executor::Spawner;
11use embassy_rp::dma::{AnyChannel, Channel};
12use embassy_rp::peripherals::PIO0;
13use embassy_rp::pio::{
14 Config, Direction, FifoJoin, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
15};
16use embassy_rp::pwm::{self, Pwm};
17use embassy_rp::relocate::RelocatedProgram;
18use embassy_rp::{bind_interrupts, into_ref, Peripheral, PeripheralRef};
19use embassy_time::{Duration, Instant, Timer};
20use {defmt_rtt as _, panic_probe as _};
21
22bind_interrupts!(pub struct Irqs {
23 PIO0_IRQ_0 => InterruptHandler<PIO0>;
24});
25
26#[embassy_executor::main]
27async fn main(_spawner: Spawner) {
28 // this test assumes a 2x16 HD44780 display attached as follow:
29 // rs = PIN0
30 // rw = PIN1
31 // e = PIN2
32 // db4 = PIN3
33 // db5 = PIN4
34 // db6 = PIN5
35 // db7 = PIN6
36 // additionally a pwm signal for a bias voltage charge pump is provided on pin 15,
37 // allowing direct connection of the display to the RP2040 without level shifters.
38 let p = embassy_rp::init(Default::default());
39
40 let _pwm = Pwm::new_output_b(p.PWM_CH7, p.PIN_15, {
41 let mut c = pwm::Config::default();
42 c.divider = 125.into();
43 c.top = 100;
44 c.compare_b = 50;
45 c
46 });
47
48 let mut hd = HD44780::new(
49 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,
50 )
51 .await;
52
53 loop {
54 struct Buf<const N: usize>([u8; N], usize);
55 impl<const N: usize> Write for Buf<N> {
56 fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
57 for b in s.as_bytes() {
58 if self.1 >= N {
59 return Err(core::fmt::Error);
60 }
61 self.0[self.1] = *b;
62 self.1 += 1;
63 }
64 Ok(())
65 }
66 }
67 let mut buf = Buf([0; 16], 0);
68 write!(buf, "up {}s", Instant::now().as_micros() as f32 / 1e6).unwrap();
69 hd.add_line(&buf.0[0..buf.1]).await;
70 Timer::after(Duration::from_secs(1)).await;
71 }
72}
73
74pub struct HD44780<'l> {
75 dma: PeripheralRef<'l, AnyChannel>,
76 sm: StateMachine<'l, PIO0, 0>,
77
78 buf: [u8; 40],
79}
80
81impl<'l> HD44780<'l> {
82 pub async fn new(
83 pio: impl Peripheral<P = PIO0> + 'l,
84 irq: Irqs,
85 dma: impl Peripheral<P = impl Channel> + 'l,
86 rs: impl PioPin,
87 rw: impl PioPin,
88 e: impl PioPin,
89 db4: impl PioPin,
90 db5: impl PioPin,
91 db6: impl PioPin,
92 db7: impl PioPin,
93 ) -> HD44780<'l> {
94 into_ref!(dma);
95
96 let Pio {
97 mut common,
98 mut irq0,
99 mut sm0,
100 ..
101 } = Pio::new(pio, irq);
102
103 // takes command words (<wait:24> <command:4> <0:4>)
104 let prg = pio_proc::pio_asm!(
105 r#"
106 .side_set 1 opt
107 .origin 20
108
109 loop:
110 out x, 24
111 delay:
112 jmp x--, delay
113 out pins, 4 side 1
114 out null, 4 side 0
115 jmp !osre, loop
116 irq 0
117 "#,
118 );
119
120 let rs = common.make_pio_pin(rs);
121 let rw = common.make_pio_pin(rw);
122 let e = common.make_pio_pin(e);
123 let db4 = common.make_pio_pin(db4);
124 let db5 = common.make_pio_pin(db5);
125 let db6 = common.make_pio_pin(db6);
126 let db7 = common.make_pio_pin(db7);
127
128 sm0.set_pin_dirs(Direction::Out, &[&rs, &rw, &e, &db4, &db5, &db6, &db7]);
129
130 let relocated = RelocatedProgram::new(&prg.program);
131 let mut cfg = Config::default();
132 cfg.use_program(&common.load_program(&relocated), &[&e]);
133 cfg.clock_divider = 125u8.into();
134 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
135 cfg.shift_out = ShiftConfig {
136 auto_fill: true,
137 direction: ShiftDirection::Left,
138 threshold: 32,
139 };
140 cfg.fifo_join = FifoJoin::TxOnly;
141 sm0.set_config(&cfg);
142
143 sm0.set_enable(true);
144 // init to 8 bit thrice
145 sm0.tx().push((50000 << 8) | 0x30);
146 sm0.tx().push((5000 << 8) | 0x30);
147 sm0.tx().push((200 << 8) | 0x30);
148 // init 4 bit
149 sm0.tx().push((200 << 8) | 0x20);
150 // set font and lines
151 sm0.tx().push((50 << 8) | 0x20);
152 sm0.tx().push(0b1100_0000);
153
154 irq0.wait().await;
155 sm0.set_enable(false);
156
157 // takes command sequences (<rs:1> <count:7>, data...)
158 // many side sets are only there to free up a delay bit!
159 let prg = pio_proc::pio_asm!(
160 r#"
161 .origin 27
162 .side_set 1
163
164 .wrap_target
165 pull side 0
166 out x 1 side 0 ; !rs
167 out y 7 side 0 ; #data - 1
168
169 ; rs/rw to e: >= 60ns
170 ; e high time: >= 500ns
171 ; e low time: >= 500ns
172 ; read data valid after e falling: ~5ns
173 ; write data hold after e falling: ~10ns
174
175 loop:
176 pull side 0
177 jmp !x data side 0
178 command:
179 set pins 0b00 side 0
180 jmp shift side 0
181 data:
182 set pins 0b01 side 0
183 shift:
184 out pins 4 side 1 [9]
185 nop side 0 [9]
186 out pins 4 side 1 [9]
187 mov osr null side 0 [7]
188 out pindirs 4 side 0
189 set pins 0b10 side 0
190 busy:
191 nop side 1 [9]
192 jmp pin more side 0 [9]
193 mov osr ~osr side 1 [9]
194 nop side 0 [4]
195 out pindirs 4 side 0
196 jmp y-- loop side 0
197 .wrap
198 more:
199 nop side 1 [9]
200 jmp busy side 0 [9]
201 "#
202 );
203
204 let relocated = RelocatedProgram::new(&prg.program);
205 let mut cfg = Config::default();
206 cfg.use_program(&common.load_program(&relocated), &[&e]);
207 cfg.clock_divider = 8u8.into(); // ~64ns/insn
208 cfg.set_jmp_pin(&db7);
209 cfg.set_set_pins(&[&rs, &rw]);
210 cfg.set_out_pins(&[&db4, &db5, &db6, &db7]);
211 cfg.shift_out.direction = ShiftDirection::Left;
212 cfg.fifo_join = FifoJoin::TxOnly;
213 sm0.set_config(&cfg);
214
215 sm0.set_enable(true);
216
217 // display on and cursor on and blinking, reset display
218 sm0.tx().dma_push(dma.reborrow(), &[0x81u8, 0x0f, 1]).await;
219
220 Self {
221 dma: dma.map_into(),
222 sm: sm0,
223 buf: [0x20; 40],
224 }
225 }
226
227 pub async fn add_line(&mut self, s: &[u8]) {
228 // move cursor to 0:0, prepare 16 characters
229 self.buf[..3].copy_from_slice(&[0x80, 0x80, 15]);
230 // move line 2 up
231 self.buf.copy_within(22..38, 3);
232 // move cursor to 1:0, prepare 16 characters
233 self.buf[19..22].copy_from_slice(&[0x80, 0xc0, 15]);
234 // file line 2 with spaces
235 self.buf[22..38].fill(0x20);
236 // copy input line
237 let len = s.len().min(16);
238 self.buf[22..22 + len].copy_from_slice(&s[0..len]);
239 // set cursor to 1:15
240 self.buf[38..].copy_from_slice(&[0x80, 0xcf]);
241
242 self.sm.tx().dma_push(self.dma.reborrow(), &self.buf).await;
243 }
244}
diff --git a/examples/rp/src/bin/pio_ws2812.rs b/examples/rp/src/bin/pio_ws2812.rs
new file mode 100644
index 000000000..3de2bd48d
--- /dev/null
+++ b/examples/rp/src/bin/pio_ws2812.rs
@@ -0,0 +1,160 @@
1//! This example shows powerful PIO module in the RP2040 chip to communicate with WS2812 LED modules.
2//! See (https://www.sparkfun.com/categories/tags/ws2812)
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::dma::{AnyChannel, Channel};
11use embassy_rp::peripherals::PIO0;
12use embassy_rp::pio::{
13 Common, Config, FifoJoin, Instance, InterruptHandler, Pio, PioPin, ShiftConfig, ShiftDirection, StateMachine,
14};
15use embassy_rp::relocate::RelocatedProgram;
16use embassy_rp::{bind_interrupts, clocks, into_ref, Peripheral, PeripheralRef};
17use embassy_time::{Duration, Timer};
18use fixed::types::U24F8;
19use fixed_macro::fixed;
20use smart_leds::RGB8;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
27pub struct Ws2812<'d, P: Instance, const S: usize, const N: usize> {
28 dma: PeripheralRef<'d, AnyChannel>,
29 sm: StateMachine<'d, P, S>,
30}
31
32impl<'d, P: Instance, const S: usize, const N: usize> Ws2812<'d, P, S, N> {
33 pub fn new(
34 pio: &mut Common<'d, P>,
35 mut sm: StateMachine<'d, P, S>,
36 dma: impl Peripheral<P = impl Channel> + 'd,
37 pin: impl PioPin,
38 ) -> Self {
39 into_ref!(dma);
40
41 // Setup sm0
42
43 // prepare the PIO program
44 let side_set = pio::SideSet::new(false, 1, false);
45 let mut a: pio::Assembler<32> = pio::Assembler::new_with_side_set(side_set);
46
47 const T1: u8 = 2; // start bit
48 const T2: u8 = 5; // data bit
49 const T3: u8 = 3; // stop bit
50 const CYCLES_PER_BIT: u32 = (T1 + T2 + T3) as u32;
51
52 let mut wrap_target = a.label();
53 let mut wrap_source = a.label();
54 let mut do_zero = a.label();
55 a.set_with_side_set(pio::SetDestination::PINDIRS, 1, 0);
56 a.bind(&mut wrap_target);
57 // Do stop bit
58 a.out_with_delay_and_side_set(pio::OutDestination::X, 1, T3 - 1, 0);
59 // Do start bit
60 a.jmp_with_delay_and_side_set(pio::JmpCondition::XIsZero, &mut do_zero, T1 - 1, 1);
61 // Do data bit = 1
62 a.jmp_with_delay_and_side_set(pio::JmpCondition::Always, &mut wrap_target, T2 - 1, 1);
63 a.bind(&mut do_zero);
64 // Do data bit = 0
65 a.nop_with_delay_and_side_set(T2 - 1, 0);
66 a.bind(&mut wrap_source);
67
68 let prg = a.assemble_with_wrap(wrap_source, wrap_target);
69 let mut cfg = Config::default();
70
71 // Pin config
72 let out_pin = pio.make_pio_pin(pin);
73 cfg.set_out_pins(&[&out_pin]);
74 cfg.set_set_pins(&[&out_pin]);
75
76 let relocated = RelocatedProgram::new(&prg);
77 cfg.use_program(&pio.load_program(&relocated), &[&out_pin]);
78
79 // Clock config, measured in kHz to avoid overflows
80 // TODO CLOCK_FREQ should come from embassy_rp
81 let clock_freq = U24F8::from_num(clocks::clk_sys_freq() / 1000);
82 let ws2812_freq = fixed!(800: U24F8);
83 let bit_freq = ws2812_freq * CYCLES_PER_BIT;
84 cfg.clock_divider = clock_freq / bit_freq;
85
86 // FIFO config
87 cfg.fifo_join = FifoJoin::TxOnly;
88 cfg.shift_out = ShiftConfig {
89 auto_fill: true,
90 threshold: 24,
91 direction: ShiftDirection::Left,
92 };
93
94 sm.set_config(&cfg);
95 sm.set_enable(true);
96
97 Self {
98 dma: dma.map_into(),
99 sm,
100 }
101 }
102
103 pub async fn write(&mut self, colors: &[RGB8; N]) {
104 // Precompute the word bytes from the colors
105 let mut words = [0u32; N];
106 for i in 0..N {
107 let word = (u32::from(colors[i].g) << 24) | (u32::from(colors[i].r) << 16) | (u32::from(colors[i].b) << 8);
108 words[i] = word;
109 }
110
111 // DMA transfer
112 self.sm.tx().dma_push(self.dma.reborrow(), &words).await;
113 }
114}
115
116/// Input a value 0 to 255 to get a color value
117/// The colours are a transition r - g - b - back to r.
118fn wheel(mut wheel_pos: u8) -> RGB8 {
119 wheel_pos = 255 - wheel_pos;
120 if wheel_pos < 85 {
121 return (255 - wheel_pos * 3, 0, wheel_pos * 3).into();
122 }
123 if wheel_pos < 170 {
124 wheel_pos -= 85;
125 return (0, wheel_pos * 3, 255 - wheel_pos * 3).into();
126 }
127 wheel_pos -= 170;
128 (wheel_pos * 3, 255 - wheel_pos * 3, 0).into()
129}
130
131#[embassy_executor::main]
132async fn main(_spawner: Spawner) {
133 info!("Start");
134 let p = embassy_rp::init(Default::default());
135
136 let Pio { mut common, sm0, .. } = Pio::new(p.PIO0, Irqs);
137
138 // This is the number of leds in the string. Helpfully, the sparkfun thing plus and adafruit
139 // feather boards for the 2040 both have one built in.
140 const NUM_LEDS: usize = 1;
141 let mut data = [RGB8::default(); NUM_LEDS];
142
143 // For the thing plus, use pin 8
144 // For the feather, use pin 16
145 let mut ws2812 = Ws2812::new(&mut common, sm0, p.DMA_CH0, p.PIN_16);
146
147 // Loop forever making RGB values and pushing them out to the WS2812.
148 loop {
149 for j in 0..(256 * 5) {
150 debug!("New Colors:");
151 for i in 0..NUM_LEDS {
152 data[i] = wheel((((i * 256) as u16 / NUM_LEDS as u16 + j as u16) & 255) as u8);
153 debug!("R: {} G: {} B: {}", data[i].r, data[i].g, data[i].b);
154 }
155 ws2812.write(&data).await;
156
157 Timer::after(Duration::from_micros(5)).await;
158 }
159 }
160}
diff --git a/examples/rp/src/bin/pwm.rs b/examples/rp/src/bin/pwm.rs
new file mode 100644
index 000000000..9d919287c
--- /dev/null
+++ b/examples/rp/src/bin/pwm.rs
@@ -0,0 +1,30 @@
1//! This example shows how to use PWM (Pulse Width Modulation) in the RP2040 chip.
2//!
3//! The LED on the RP Pico W board is connected differently. Add a LED and resistor to another pin.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::pwm::{Config, Pwm};
12use embassy_time::{Duration, Timer};
13use {defmt_rtt as _, panic_probe as _};
14
15#[embassy_executor::main]
16async fn main(_spawner: Spawner) {
17 let p = embassy_rp::init(Default::default());
18
19 let mut c: Config = Default::default();
20 c.top = 0x8000;
21 c.compare_b = 8;
22 let mut pwm = Pwm::new_output_b(p.PWM_CH4, p.PIN_25, c.clone());
23
24 loop {
25 info!("current LED duty cycle: {}/32768", c.compare_b);
26 Timer::after(Duration::from_secs(1)).await;
27 c.compare_b = c.compare_b.rotate_left(4);
28 pwm.set_config(&c);
29 }
30}
diff --git a/examples/rp/src/bin/rtc.rs b/examples/rp/src/bin/rtc.rs
new file mode 100644
index 000000000..15aa8243f
--- /dev/null
+++ b/examples/rp/src/bin/rtc.rs
@@ -0,0 +1,46 @@
1//! This example shows how to use RTC (Real Time Clock) in the RP2040 chip.
2
3#![no_std]
4#![no_main]
5#![feature(type_alias_impl_trait)]
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_rp::rtc::{DateTime, DayOfWeek, Rtc};
10use embassy_time::{Duration, Timer};
11use {defmt_rtt as _, panic_probe as _};
12
13#[embassy_executor::main]
14async fn main(_spawner: Spawner) {
15 let p = embassy_rp::init(Default::default());
16 info!("Wait for 20s");
17
18 let mut rtc = Rtc::new(p.RTC);
19
20 if !rtc.is_running() {
21 info!("Start RTC");
22 let now = DateTime {
23 year: 2000,
24 month: 1,
25 day: 1,
26 day_of_week: DayOfWeek::Saturday,
27 hour: 0,
28 minute: 0,
29 second: 0,
30 };
31 rtc.set_datetime(now).unwrap();
32 }
33
34 Timer::after(Duration::from_millis(20000)).await;
35
36 if let Ok(dt) = rtc.now() {
37 info!(
38 "Now: {}-{:02}-{:02} {}:{:02}:{:02}",
39 dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second,
40 );
41 }
42
43 info!("Reboot.");
44 Timer::after(Duration::from_millis(200)).await;
45 cortex_m::peripheral::SCB::sys_reset();
46}
diff --git a/examples/rp/src/bin/spi.rs b/examples/rp/src/bin/spi.rs
index 88003ee17..602348f7a 100644
--- a/examples/rp/src/bin/spi.rs
+++ b/examples/rp/src/bin/spi.rs
@@ -1,3 +1,7 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example for resistive touch sensor in Waveshare Pico-ResTouch
4
1#![no_std] 5#![no_std]
2#![no_main] 6#![no_main]
3#![feature(type_alias_impl_trait)] 7#![feature(type_alias_impl_trait)]
@@ -24,7 +28,7 @@ async fn main(_spawner: Spawner) {
24 // create SPI 28 // create SPI
25 let mut config = spi::Config::default(); 29 let mut config = spi::Config::default();
26 config.frequency = 2_000_000; 30 config.frequency = 2_000_000;
27 let mut spi = Spi::new(p.SPI1, clk, mosi, miso, config); 31 let mut spi = Spi::new_blocking(p.SPI1, clk, mosi, miso, config);
28 32
29 // Configure CS 33 // Configure CS
30 let mut cs = Output::new(touch_cs, Level::Low); 34 let mut cs = Output::new(touch_cs, Level::Low);
diff --git a/examples/rp/src/bin/spi_async.rs b/examples/rp/src/bin/spi_async.rs
new file mode 100644
index 000000000..328074e8b
--- /dev/null
+++ b/examples/rp/src/bin/spi_async.rs
@@ -0,0 +1,32 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//! No specific hardware is specified in this example. If you connect pin 11 and 12 you should get the same data back.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7
8use defmt::*;
9use embassy_executor::Spawner;
10use embassy_rp::spi::{Config, Spi};
11use embassy_time::{Duration, Timer};
12use {defmt_rtt as _, panic_probe as _};
13
14#[embassy_executor::main]
15async fn main(_spawner: Spawner) {
16 let p = embassy_rp::init(Default::default());
17 info!("Hello World!");
18
19 let miso = p.PIN_12;
20 let mosi = p.PIN_11;
21 let clk = p.PIN_10;
22
23 let mut spi = Spi::new(p.SPI1, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, Config::default());
24
25 loop {
26 let tx_buf = [1_u8, 2, 3, 4, 5, 6];
27 let mut rx_buf = [0_u8; 6];
28 spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
29 info!("{:?}", rx_buf);
30 Timer::after(Duration::from_secs(1)).await;
31 }
32}
diff --git a/examples/rp/src/bin/spi_display.rs b/examples/rp/src/bin/spi_display.rs
index f0e54d87f..26c258e1c 100644
--- a/examples/rp/src/bin/spi_display.rs
+++ b/examples/rp/src/bin/spi_display.rs
@@ -1,3 +1,8 @@
1//! This example shows how to use SPI (Serial Peripheral Interface) in the RP2040 chip.
2//!
3//! Example written for a display using the ST7789 chip. Possibly the Waveshare Pico-ResTouch
4//! (https://www.waveshare.com/wiki/Pico-ResTouch-LCD-2.8)
5
1#![no_std] 6#![no_std]
2#![no_main] 7#![no_main]
3#![feature(type_alias_impl_trait)] 8#![feature(type_alias_impl_trait)]
@@ -5,10 +10,13 @@
5use core::cell::RefCell; 10use core::cell::RefCell;
6 11
7use defmt::*; 12use defmt::*;
13use embassy_embedded_hal::shared_bus::blocking::spi::SpiDeviceWithConfig;
8use embassy_executor::Spawner; 14use embassy_executor::Spawner;
9use embassy_rp::gpio::{Level, Output}; 15use embassy_rp::gpio::{Level, Output};
10use embassy_rp::spi; 16use embassy_rp::spi;
11use embassy_rp::spi::Spi; 17use embassy_rp::spi::{Blocking, Spi};
18use embassy_sync::blocking_mutex::raw::NoopRawMutex;
19use embassy_sync::blocking_mutex::Mutex;
12use embassy_time::Delay; 20use embassy_time::Delay;
13use embedded_graphics::image::{Image, ImageRawLE}; 21use embedded_graphics::image::{Image, ImageRawLE};
14use embedded_graphics::mono_font::ascii::FONT_10X20; 22use embedded_graphics::mono_font::ascii::FONT_10X20;
@@ -21,10 +29,9 @@ use st7789::{Orientation, ST7789};
21use {defmt_rtt as _, panic_probe as _}; 29use {defmt_rtt as _, panic_probe as _};
22 30
23use crate::my_display_interface::SPIDeviceInterface; 31use crate::my_display_interface::SPIDeviceInterface;
24use crate::shared_spi::SpiDeviceWithCs;
25use crate::touch::Touch; 32use crate::touch::Touch;
26 33
27//const DISPLAY_FREQ: u32 = 64_000_000; 34const DISPLAY_FREQ: u32 = 64_000_000;
28const TOUCH_FREQ: u32 = 200_000; 35const TOUCH_FREQ: u32 = 200_000;
29 36
30#[embassy_executor::main] 37#[embassy_executor::main]
@@ -43,15 +50,20 @@ async fn main(_spawner: Spawner) {
43 //let touch_irq = p.PIN_17; 50 //let touch_irq = p.PIN_17;
44 51
45 // create SPI 52 // create SPI
46 let mut config = spi::Config::default(); 53 let mut display_config = spi::Config::default();
47 config.frequency = TOUCH_FREQ; // use the lowest freq 54 display_config.frequency = DISPLAY_FREQ;
48 config.phase = spi::Phase::CaptureOnSecondTransition; 55 display_config.phase = spi::Phase::CaptureOnSecondTransition;
49 config.polarity = spi::Polarity::IdleHigh; 56 display_config.polarity = spi::Polarity::IdleHigh;
57 let mut touch_config = spi::Config::default();
58 touch_config.frequency = TOUCH_FREQ;
59 touch_config.phase = spi::Phase::CaptureOnSecondTransition;
60 touch_config.polarity = spi::Polarity::IdleHigh;
50 61
51 let spi_bus = RefCell::new(Spi::new(p.SPI1, clk, mosi, miso, config)); 62 let spi: Spi<'_, _, Blocking> = Spi::new_blocking(p.SPI1, clk, mosi, miso, touch_config.clone());
63 let spi_bus: Mutex<NoopRawMutex, _> = Mutex::new(RefCell::new(spi));
52 64
53 let display_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(display_cs, Level::High)); 65 let display_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(display_cs, Level::High), display_config);
54 let touch_spi = SpiDeviceWithCs::new(&spi_bus, Output::new(touch_cs, Level::High)); 66 let touch_spi = SpiDeviceWithConfig::new(&spi_bus, Output::new(touch_cs, Level::High), touch_config);
55 67
56 let mut touch = Touch::new(touch_spi); 68 let mut touch = Touch::new(touch_spi);
57 69
@@ -103,85 +115,9 @@ async fn main(_spawner: Spawner) {
103 } 115 }
104} 116}
105 117
106mod shared_spi {
107 use core::cell::RefCell;
108 use core::fmt::Debug;
109
110 use embedded_hal_1::digital::blocking::OutputPin;
111 use embedded_hal_1::spi;
112 use embedded_hal_1::spi::blocking::SpiDevice;
113
114 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
115 pub enum SpiDeviceWithCsError<BUS, CS> {
116 #[allow(unused)] // will probably use in the future when adding a flush() to SpiBus
117 Spi(BUS),
118 Cs(CS),
119 }
120
121 impl<BUS, CS> spi::Error for SpiDeviceWithCsError<BUS, CS>
122 where
123 BUS: spi::Error + Debug,
124 CS: Debug,
125 {
126 fn kind(&self) -> spi::ErrorKind {
127 match self {
128 Self::Spi(e) => e.kind(),
129 Self::Cs(_) => spi::ErrorKind::Other,
130 }
131 }
132 }
133
134 pub struct SpiDeviceWithCs<'a, BUS, CS> {
135 bus: &'a RefCell<BUS>,
136 cs: CS,
137 }
138
139 impl<'a, BUS, CS> SpiDeviceWithCs<'a, BUS, CS> {
140 pub fn new(bus: &'a RefCell<BUS>, cs: CS) -> Self {
141 Self { bus, cs }
142 }
143 }
144
145 impl<'a, BUS, CS> spi::ErrorType for SpiDeviceWithCs<'a, BUS, CS>
146 where
147 BUS: spi::ErrorType,
148 CS: OutputPin,
149 {
150 type Error = SpiDeviceWithCsError<BUS::Error, CS::Error>;
151 }
152
153 impl<'a, BUS, CS> SpiDevice for SpiDeviceWithCs<'a, BUS, CS>
154 where
155 BUS: spi::blocking::SpiBusFlush,
156 CS: OutputPin,
157 {
158 type Bus = BUS;
159
160 fn transaction<R>(
161 &mut self,
162 f: impl FnOnce(&mut Self::Bus) -> Result<R, BUS::Error>,
163 ) -> Result<R, Self::Error> {
164 let mut bus = self.bus.borrow_mut();
165 self.cs.set_low().map_err(SpiDeviceWithCsError::Cs)?;
166
167 let f_res = f(&mut bus);
168
169 // On failure, it's important to still flush and deassert CS.
170 let flush_res = bus.flush();
171 let cs_res = self.cs.set_high();
172
173 let f_res = f_res.map_err(SpiDeviceWithCsError::Spi)?;
174 flush_res.map_err(SpiDeviceWithCsError::Spi)?;
175 cs_res.map_err(SpiDeviceWithCsError::Cs)?;
176
177 Ok(f_res)
178 }
179 }
180}
181
182/// Driver for the XPT2046 resistive touchscreen sensor 118/// Driver for the XPT2046 resistive touchscreen sensor
183mod touch { 119mod touch {
184 use embedded_hal_1::spi::blocking::{SpiBus, SpiBusRead, SpiBusWrite, SpiDevice}; 120 use embedded_hal_1::spi::{Operation, SpiDevice};
185 121
186 struct Calibration { 122 struct Calibration {
187 x1: i32, 123 x1: i32,
@@ -208,7 +144,6 @@ mod touch {
208 impl<SPI> Touch<SPI> 144 impl<SPI> Touch<SPI>
209 where 145 where
210 SPI: SpiDevice, 146 SPI: SpiDevice,
211 SPI::Bus: SpiBus,
212 { 147 {
213 pub fn new(spi: SPI) -> Self { 148 pub fn new(spi: SPI) -> Self {
214 Self { spi } 149 Self { spi }
@@ -218,13 +153,12 @@ mod touch {
218 let mut x = [0; 2]; 153 let mut x = [0; 2];
219 let mut y = [0; 2]; 154 let mut y = [0; 2];
220 self.spi 155 self.spi
221 .transaction(|bus| { 156 .transaction(&mut [
222 bus.write(&[0x90])?; 157 Operation::Write(&[0x90]),
223 bus.read(&mut x)?; 158 Operation::Read(&mut x),
224 bus.write(&[0xd0])?; 159 Operation::Write(&[0xd0]),
225 bus.read(&mut y)?; 160 Operation::Read(&mut y),
226 Ok(()) 161 ])
227 })
228 .unwrap(); 162 .unwrap();
229 163
230 let x = (u16::from_be_bytes(x) >> 3) as i32; 164 let x = (u16::from_be_bytes(x) >> 3) as i32;
@@ -245,8 +179,8 @@ mod touch {
245 179
246mod my_display_interface { 180mod my_display_interface {
247 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand}; 181 use display_interface::{DataFormat, DisplayError, WriteOnlyDataCommand};
248 use embedded_hal_1::digital::blocking::OutputPin; 182 use embedded_hal_1::digital::OutputPin;
249 use embedded_hal_1::spi::blocking::{SpiBusWrite, SpiDevice}; 183 use embedded_hal_1::spi::SpiDevice;
250 184
251 /// SPI display interface. 185 /// SPI display interface.
252 /// 186 ///
@@ -259,7 +193,6 @@ mod my_display_interface {
259 impl<SPI, DC> SPIDeviceInterface<SPI, DC> 193 impl<SPI, DC> SPIDeviceInterface<SPI, DC>
260 where 194 where
261 SPI: SpiDevice, 195 SPI: SpiDevice,
262 SPI::Bus: SpiBusWrite,
263 DC: OutputPin, 196 DC: OutputPin,
264 { 197 {
265 /// Create new SPI interface for communciation with a display driver 198 /// Create new SPI interface for communciation with a display driver
@@ -271,41 +204,26 @@ mod my_display_interface {
271 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC> 204 impl<SPI, DC> WriteOnlyDataCommand for SPIDeviceInterface<SPI, DC>
272 where 205 where
273 SPI: SpiDevice, 206 SPI: SpiDevice,
274 SPI::Bus: SpiBusWrite,
275 DC: OutputPin, 207 DC: OutputPin,
276 { 208 {
277 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> { 209 fn send_commands(&mut self, cmds: DataFormat<'_>) -> Result<(), DisplayError> {
278 let r = self.spi.transaction(|bus| { 210 // 1 = data, 0 = command
279 // 1 = data, 0 = command 211 self.dc.set_low().map_err(|_| DisplayError::DCError)?;
280 if let Err(_) = self.dc.set_low() {
281 return Ok(Err(DisplayError::DCError));
282 }
283
284 // Send words over SPI
285 send_u8(bus, cmds)?;
286 212
287 Ok(Ok(())) 213 send_u8(&mut self.spi, cmds).map_err(|_| DisplayError::BusWriteError)?;
288 }); 214 Ok(())
289 r.map_err(|_| DisplayError::BusWriteError)?
290 } 215 }
291 216
292 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> { 217 fn send_data(&mut self, buf: DataFormat<'_>) -> Result<(), DisplayError> {
293 let r = self.spi.transaction(|bus| { 218 // 1 = data, 0 = command
294 // 1 = data, 0 = command 219 self.dc.set_high().map_err(|_| DisplayError::DCError)?;
295 if let Err(_) = self.dc.set_high() {
296 return Ok(Err(DisplayError::DCError));
297 }
298
299 // Send words over SPI
300 send_u8(bus, buf)?;
301 220
302 Ok(Ok(())) 221 send_u8(&mut self.spi, buf).map_err(|_| DisplayError::BusWriteError)?;
303 }); 222 Ok(())
304 r.map_err(|_| DisplayError::BusWriteError)?
305 } 223 }
306 } 224 }
307 225
308 fn send_u8<T: SpiBusWrite>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> { 226 fn send_u8<T: SpiDevice>(spi: &mut T, words: DataFormat<'_>) -> Result<(), T::Error> {
309 match words { 227 match words {
310 DataFormat::U8(slice) => spi.write(slice), 228 DataFormat::U8(slice) => spi.write(slice),
311 DataFormat::U16(slice) => { 229 DataFormat::U16(slice) => {
diff --git a/examples/rp/src/bin/uart.rs b/examples/rp/src/bin/uart.rs
index c63b31cae..451c3c396 100644
--- a/examples/rp/src/bin/uart.rs
+++ b/examples/rp/src/bin/uart.rs
@@ -1,3 +1,9 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. Only output on pin 0 is tested.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
1#![no_std] 7#![no_std]
2#![no_main] 8#![no_main]
3#![feature(type_alias_impl_trait)] 9#![feature(type_alias_impl_trait)]
@@ -10,7 +16,7 @@ use {defmt_rtt as _, panic_probe as _};
10async fn main(_spawner: Spawner) { 16async fn main(_spawner: Spawner) {
11 let p = embassy_rp::init(Default::default()); 17 let p = embassy_rp::init(Default::default());
12 let config = uart::Config::default(); 18 let config = uart::Config::default();
13 let mut uart = uart::Uart::new_with_rtscts(p.UART0, p.PIN_0, p.PIN_1, p.PIN_2, p.PIN_3, config); 19 let mut uart = uart::Uart::new_with_rtscts_blocking(p.UART0, p.PIN_0, p.PIN_1, p.PIN_3, p.PIN_2, config);
14 uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap(); 20 uart.blocking_write("Hello World!\r\n".as_bytes()).unwrap();
15 21
16 loop { 22 loop {
diff --git a/examples/rp/src/bin/uart_buffered_split.rs b/examples/rp/src/bin/uart_buffered_split.rs
new file mode 100644
index 000000000..735201718
--- /dev/null
+++ b/examples/rp/src/bin/uart_buffered_split.rs
@@ -0,0 +1,57 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! No specific hardware is specified in this example. If you connect pin 0 and 1 you should get the same data back.
4//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
5//! with its UART port.
6
7#![no_std]
8#![no_main]
9#![feature(type_alias_impl_trait)]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_rp::bind_interrupts;
14use embassy_rp::peripherals::UART0;
15use embassy_rp::uart::{BufferedInterruptHandler, BufferedUart, BufferedUartRx, Config};
16use embassy_time::{Duration, Timer};
17use embedded_io::asynch::{Read, Write};
18use static_cell::make_static;
19use {defmt_rtt as _, panic_probe as _};
20
21bind_interrupts!(struct Irqs {
22 UART0_IRQ => BufferedInterruptHandler<UART0>;
23});
24
25#[embassy_executor::main]
26async fn main(spawner: Spawner) {
27 let p = embassy_rp::init(Default::default());
28 let (tx_pin, rx_pin, uart) = (p.PIN_0, p.PIN_1, p.UART0);
29
30 let tx_buf = &mut make_static!([0u8; 16])[..];
31 let rx_buf = &mut make_static!([0u8; 16])[..];
32 let uart = BufferedUart::new(uart, Irqs, tx_pin, rx_pin, tx_buf, rx_buf, Config::default());
33 let (rx, mut tx) = uart.split();
34
35 unwrap!(spawner.spawn(reader(rx)));
36
37 info!("Writing...");
38 loop {
39 let data = [
40 1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
41 29, 30, 31,
42 ];
43 info!("TX {:?}", data);
44 tx.write_all(&data).await.unwrap();
45 Timer::after(Duration::from_secs(1)).await;
46 }
47}
48
49#[embassy_executor::task]
50async fn reader(mut rx: BufferedUartRx<'static, UART0>) {
51 info!("Reading...");
52 loop {
53 let mut buf = [0; 31];
54 rx.read_exact(&mut buf).await.unwrap();
55 info!("RX {:?}", buf);
56 }
57}
diff --git a/examples/rp/src/bin/uart_unidir.rs b/examples/rp/src/bin/uart_unidir.rs
new file mode 100644
index 000000000..c1515a911
--- /dev/null
+++ b/examples/rp/src/bin/uart_unidir.rs
@@ -0,0 +1,51 @@
1//! This example shows how to use UART (Universal asynchronous receiver-transmitter) in the RP2040 chip.
2//!
3//! Test TX-only and RX-only on two different UARTs. You need to connect GPIO0 to GPIO5 for
4//! this to work
5//! The Raspberry Pi Debug Probe (https://www.raspberrypi.com/products/debug-probe/) could be used
6//! with its UART port.
7
8#![no_std]
9#![no_main]
10#![feature(type_alias_impl_trait)]
11
12use defmt::*;
13use embassy_executor::Spawner;
14use embassy_rp::bind_interrupts;
15use embassy_rp::peripherals::UART1;
16use embassy_rp::uart::{Async, Config, InterruptHandler, UartRx, UartTx};
17use embassy_time::{Duration, Timer};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 UART1_IRQ => InterruptHandler<UART1>;
22});
23
24#[embassy_executor::main]
25async fn main(spawner: Spawner) {
26 let p = embassy_rp::init(Default::default());
27
28 let mut uart_tx = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, Config::default());
29 let uart_rx = UartRx::new(p.UART1, p.PIN_5, Irqs, p.DMA_CH1, Config::default());
30
31 unwrap!(spawner.spawn(reader(uart_rx)));
32
33 info!("Writing...");
34 loop {
35 let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
36 info!("TX {:?}", data);
37 uart_tx.write(&data).await.unwrap();
38 Timer::after(Duration::from_secs(1)).await;
39 }
40}
41
42#[embassy_executor::task]
43async fn reader(mut rx: UartRx<'static, UART1, Async>) {
44 info!("Reading...");
45 loop {
46 // read a total of 4 transmissions (32 / 8) and then print the result
47 let mut buf = [0; 32];
48 rx.read(&mut buf).await.unwrap();
49 info!("RX {:?}", buf);
50 }
51}
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..0a08f667e
--- /dev/null
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -0,0 +1,155 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This is a CDC-NCM class implementation, aka Ethernet over USB.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{Stack, StackResources};
13use embassy_rp::peripherals::USB;
14use embassy_rp::usb::{Driver, InterruptHandler};
15use embassy_rp::{bind_interrupts, peripherals};
16use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
17use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
18use embassy_usb::{Builder, Config, UsbDevice};
19use embedded_io::asynch::Write;
20use static_cell::make_static;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 USBCTRL_IRQ => InterruptHandler<USB>;
25});
26
27type MyDriver = Driver<'static, peripherals::USB>;
28
29const MTU: usize = 1514;
30
31#[embassy_executor::task]
32async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
33 device.run().await
34}
35
36#[embassy_executor::task]
37async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
38 class.run().await
39}
40
41#[embassy_executor::task]
42async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
43 stack.run().await
44}
45
46#[embassy_executor::main]
47async fn main(spawner: Spawner) {
48 let p = embassy_rp::init(Default::default());
49
50 // Create the driver, from the HAL.
51 let driver = Driver::new(p.USB, Irqs);
52
53 // Create embassy-usb Config
54 let mut config = Config::new(0xc0de, 0xcafe);
55 config.manufacturer = Some("Embassy");
56 config.product = Some("USB-Ethernet example");
57 config.serial_number = Some("12345678");
58 config.max_power = 100;
59 config.max_packet_size_0 = 64;
60
61 // Required for Windows support.
62 config.composite_with_iads = true;
63 config.device_class = 0xEF;
64 config.device_sub_class = 0x02;
65 config.device_protocol = 0x01;
66
67 // Create embassy-usb DeviceBuilder using the driver and config.
68 let mut builder = Builder::new(
69 driver,
70 config,
71 &mut make_static!([0; 256])[..],
72 &mut make_static!([0; 256])[..],
73 &mut make_static!([0; 256])[..],
74 &mut make_static!([0; 128])[..],
75 );
76
77 // Our MAC addr.
78 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
79 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
80 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
81
82 // Create classes on the builder.
83 let class = CdcNcmClass::new(&mut builder, make_static!(State::new()), host_mac_addr, 64);
84
85 // Build the builder.
86 let usb = builder.build();
87
88 unwrap!(spawner.spawn(usb_task(usb)));
89
90 let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(make_static!(NetState::new()), our_mac_addr);
91 unwrap!(spawner.spawn(usb_ncm_task(runner)));
92
93 let config = embassy_net::Config::dhcpv4(Default::default());
94 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
95 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
96 // dns_servers: Vec::new(),
97 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
98 //});
99
100 // Generate random seed
101 let seed = 1234; // guaranteed random, chosen by a fair dice roll
102
103 // Init network stack
104 let stack = &*make_static!(Stack::new(
105 device,
106 config,
107 make_static!(StackResources::<2>::new()),
108 seed
109 ));
110
111 unwrap!(spawner.spawn(net_task(stack)));
112
113 // And now we can use it!
114
115 let mut rx_buffer = [0; 4096];
116 let mut tx_buffer = [0; 4096];
117 let mut buf = [0; 4096];
118
119 loop {
120 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
121 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
122
123 info!("Listening on TCP:1234...");
124 if let Err(e) = socket.accept(1234).await {
125 warn!("accept error: {:?}", e);
126 continue;
127 }
128
129 info!("Received connection from {:?}", socket.remote_endpoint());
130
131 loop {
132 let n = match socket.read(&mut buf).await {
133 Ok(0) => {
134 warn!("read EOF");
135 break;
136 }
137 Ok(n) => n,
138 Err(e) => {
139 warn!("read error: {:?}", e);
140 break;
141 }
142 };
143
144 info!("rxd {:02x}", &buf[..n]);
145
146 match socket.write_all(&buf[..n]).await {
147 Ok(()) => {}
148 Err(e) => {
149 warn!("write error: {:?}", e);
150 break;
151 }
152 };
153 }
154 }
155}
diff --git a/examples/rp/src/bin/usb_hid_keyboard.rs b/examples/rp/src/bin/usb_hid_keyboard.rs
new file mode 100644
index 000000000..99af1f02f
--- /dev/null
+++ b/examples/rp/src/bin/usb_hid_keyboard.rs
@@ -0,0 +1,188 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::sync::atomic::{AtomicBool, Ordering};
6
7use defmt::*;
8use embassy_executor::Spawner;
9use embassy_futures::join::join;
10use embassy_rp::bind_interrupts;
11use embassy_rp::gpio::{Input, Pull};
12use embassy_rp::peripherals::USB;
13use embassy_rp::usb::{Driver, InterruptHandler};
14use embassy_usb::class::hid::{HidReaderWriter, ReportId, RequestHandler, State};
15use embassy_usb::control::OutResponse;
16use embassy_usb::{Builder, Config, Handler};
17use usbd_hid::descriptor::{KeyboardReport, SerializedDescriptor};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 USBCTRL_IRQ => InterruptHandler<USB>;
22});
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 let p = embassy_rp::init(Default::default());
27 // Create the driver, from the HAL.
28 let driver = Driver::new(p.USB, Irqs);
29
30 // Create embassy-usb Config
31 let mut config = Config::new(0xc0de, 0xcafe);
32 config.manufacturer = Some("Embassy");
33 config.product = Some("HID keyboard example");
34 config.serial_number = Some("12345678");
35 config.max_power = 100;
36 config.max_packet_size_0 = 64;
37
38 // Create embassy-usb DeviceBuilder using the driver and config.
39 // It needs some buffers for building the descriptors.
40 let mut device_descriptor = [0; 256];
41 let mut config_descriptor = [0; 256];
42 let mut bos_descriptor = [0; 256];
43 // You can also add a Microsoft OS descriptor.
44 // let mut msos_descriptor = [0; 256];
45 let mut control_buf = [0; 64];
46 let request_handler = MyRequestHandler {};
47 let mut device_handler = MyDeviceHandler::new();
48
49 let mut state = State::new();
50
51 let mut builder = Builder::new(
52 driver,
53 config,
54 &mut device_descriptor,
55 &mut config_descriptor,
56 &mut bos_descriptor,
57 // &mut msos_descriptor,
58 &mut control_buf,
59 );
60
61 builder.handler(&mut device_handler);
62
63 // Create classes on the builder.
64 let config = embassy_usb::class::hid::Config {
65 report_descriptor: KeyboardReport::desc(),
66 request_handler: Some(&request_handler),
67 poll_ms: 60,
68 max_packet_size: 64,
69 };
70 let hid = HidReaderWriter::<_, 1, 8>::new(&mut builder, &mut state, config);
71
72 // Build the builder.
73 let mut usb = builder.build();
74
75 // Run the USB device.
76 let usb_fut = usb.run();
77
78 // Set up the signal pin that will be used to trigger the keyboard.
79 let mut signal_pin = Input::new(p.PIN_16, Pull::None);
80
81 let (reader, mut writer) = hid.split();
82
83 // Do stuff with the class!
84 let in_fut = async {
85 loop {
86 info!("Waiting for HIGH on pin 16");
87 signal_pin.wait_for_high().await;
88 info!("HIGH DETECTED");
89 // Create a report with the A key pressed. (no shift modifier)
90 let report = KeyboardReport {
91 keycodes: [4, 0, 0, 0, 0, 0],
92 leds: 0,
93 modifier: 0,
94 reserved: 0,
95 };
96 // Send the report.
97 match writer.write_serialize(&report).await {
98 Ok(()) => {}
99 Err(e) => warn!("Failed to send report: {:?}", e),
100 };
101 signal_pin.wait_for_low().await;
102 info!("LOW DETECTED");
103 let report = KeyboardReport {
104 keycodes: [0, 0, 0, 0, 0, 0],
105 leds: 0,
106 modifier: 0,
107 reserved: 0,
108 };
109 match writer.write_serialize(&report).await {
110 Ok(()) => {}
111 Err(e) => warn!("Failed to send report: {:?}", e),
112 };
113 }
114 };
115
116 let out_fut = async {
117 reader.run(false, &request_handler).await;
118 };
119
120 // Run everything concurrently.
121 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
122 join(usb_fut, join(in_fut, out_fut)).await;
123}
124
125struct MyRequestHandler {}
126
127impl RequestHandler for MyRequestHandler {
128 fn get_report(&self, id: ReportId, _buf: &mut [u8]) -> Option<usize> {
129 info!("Get report for {:?}", id);
130 None
131 }
132
133 fn set_report(&self, id: ReportId, data: &[u8]) -> OutResponse {
134 info!("Set report for {:?}: {=[u8]}", id, data);
135 OutResponse::Accepted
136 }
137
138 fn set_idle_ms(&self, id: Option<ReportId>, dur: u32) {
139 info!("Set idle rate for {:?} to {:?}", id, dur);
140 }
141
142 fn get_idle_ms(&self, id: Option<ReportId>) -> Option<u32> {
143 info!("Get idle rate for {:?}", id);
144 None
145 }
146}
147
148struct MyDeviceHandler {
149 configured: AtomicBool,
150}
151
152impl MyDeviceHandler {
153 fn new() -> Self {
154 MyDeviceHandler {
155 configured: AtomicBool::new(false),
156 }
157 }
158}
159
160impl Handler for MyDeviceHandler {
161 fn enabled(&mut self, enabled: bool) {
162 self.configured.store(false, Ordering::Relaxed);
163 if enabled {
164 info!("Device enabled");
165 } else {
166 info!("Device disabled");
167 }
168 }
169
170 fn reset(&mut self) {
171 self.configured.store(false, Ordering::Relaxed);
172 info!("Bus reset, the Vbus current limit is 100mA");
173 }
174
175 fn addressed(&mut self, addr: u8) {
176 self.configured.store(false, Ordering::Relaxed);
177 info!("USB address set to: {}", addr);
178 }
179
180 fn configured(&mut self, configured: bool) {
181 self.configured.store(configured, Ordering::Relaxed);
182 if configured {
183 info!("Device configured, it may now draw up to the configured current limit from Vbus.")
184 } else {
185 info!("Device is no longer configured, the Vbus current limit is 100mA.");
186 }
187 }
188}
diff --git a/examples/rp/src/bin/usb_logger.rs b/examples/rp/src/bin/usb_logger.rs
new file mode 100644
index 000000000..9c5e6897d
--- /dev/null
+++ b/examples/rp/src/bin/usb_logger.rs
@@ -0,0 +1,37 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates the possibility to send log::info/warn/error/debug! to USB serial port.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use embassy_executor::Spawner;
10use embassy_rp::bind_interrupts;
11use embassy_rp::peripherals::USB;
12use embassy_rp::usb::{Driver, InterruptHandler};
13use embassy_time::{Duration, Timer};
14use {defmt_rtt as _, panic_probe as _};
15
16bind_interrupts!(struct Irqs {
17 USBCTRL_IRQ => InterruptHandler<USB>;
18});
19
20#[embassy_executor::task]
21async fn logger_task(driver: Driver<'static, USB>) {
22 embassy_usb_logger::run!(1024, log::LevelFilter::Info, driver);
23}
24
25#[embassy_executor::main]
26async fn main(spawner: Spawner) {
27 let p = embassy_rp::init(Default::default());
28 let driver = Driver::new(p.USB, Irqs);
29 spawner.spawn(logger_task(driver)).unwrap();
30
31 let mut counter = 0;
32 loop {
33 counter += 1;
34 log::info!("Tick {}", counter);
35 Timer::after(Duration::from_secs(1)).await;
36 }
37}
diff --git a/examples/rp/src/bin/usb_serial.rs b/examples/rp/src/bin/usb_serial.rs
new file mode 100644
index 000000000..164e2052d
--- /dev/null
+++ b/examples/rp/src/bin/usb_serial.rs
@@ -0,0 +1,109 @@
1//! This example shows how to use USB (Universal Serial Bus) in the RP2040 chip.
2//!
3//! This creates a USB serial port that echos.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::{info, panic};
10use embassy_executor::Spawner;
11use embassy_futures::join::join;
12use embassy_rp::bind_interrupts;
13use embassy_rp::peripherals::USB;
14use embassy_rp::usb::{Driver, Instance, InterruptHandler};
15use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
16use embassy_usb::driver::EndpointError;
17use embassy_usb::{Builder, Config};
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 USBCTRL_IRQ => InterruptHandler<USB>;
22});
23
24#[embassy_executor::main]
25async fn main(_spawner: Spawner) {
26 info!("Hello there!");
27
28 let p = embassy_rp::init(Default::default());
29
30 // Create the driver, from the HAL.
31 let driver = Driver::new(p.USB, Irqs);
32
33 // Create embassy-usb Config
34 let mut config = Config::new(0xc0de, 0xcafe);
35 config.manufacturer = Some("Embassy");
36 config.product = Some("USB-serial example");
37 config.serial_number = Some("12345678");
38 config.max_power = 100;
39 config.max_packet_size_0 = 64;
40
41 // Required for windows compatibility.
42 // https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
43 config.device_class = 0xEF;
44 config.device_sub_class = 0x02;
45 config.device_protocol = 0x01;
46 config.composite_with_iads = true;
47
48 // Create embassy-usb DeviceBuilder using the driver and config.
49 // It needs some buffers for building the descriptors.
50 let mut device_descriptor = [0; 256];
51 let mut config_descriptor = [0; 256];
52 let mut bos_descriptor = [0; 256];
53 let mut control_buf = [0; 64];
54
55 let mut state = State::new();
56
57 let mut builder = Builder::new(
58 driver,
59 config,
60 &mut device_descriptor,
61 &mut config_descriptor,
62 &mut bos_descriptor,
63 &mut control_buf,
64 );
65
66 // Create classes on the builder.
67 let mut class = CdcAcmClass::new(&mut builder, &mut state, 64);
68
69 // Build the builder.
70 let mut usb = builder.build();
71
72 // Run the USB device.
73 let usb_fut = usb.run();
74
75 // Do stuff with the class!
76 let echo_fut = async {
77 loop {
78 class.wait_connection().await;
79 info!("Connected");
80 let _ = echo(&mut class).await;
81 info!("Disconnected");
82 }
83 };
84
85 // Run everything concurrently.
86 // If we had made everything `'static` above instead, we could do this using separate tasks instead.
87 join(usb_fut, echo_fut).await;
88}
89
90struct Disconnected {}
91
92impl From<EndpointError> for Disconnected {
93 fn from(val: EndpointError) -> Self {
94 match val {
95 EndpointError::BufferOverflow => panic!("Buffer overflow"),
96 EndpointError::Disabled => Disconnected {},
97 }
98 }
99}
100
101async fn echo<'d, T: Instance + 'd>(class: &mut CdcAcmClass<'d, Driver<'d, T>>) -> Result<(), Disconnected> {
102 let mut buf = [0; 64];
103 loop {
104 let n = class.read_packet(&mut buf).await?;
105 let data = &buf[..n];
106 info!("data: {:x}", data);
107 class.write_packet(data).await?;
108 }
109}
diff --git a/examples/rp/src/bin/watchdog.rs b/examples/rp/src/bin/watchdog.rs
new file mode 100644
index 000000000..fe5eaf926
--- /dev/null
+++ b/examples/rp/src/bin/watchdog.rs
@@ -0,0 +1,52 @@
1//! This example shows how to use Watchdog in the RP2040 chip.
2//!
3//! It does not work with the RP Pico W board. See wifi_blinky.rs or connect external LED and resistor.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use defmt::info;
10use embassy_executor::Spawner;
11use embassy_rp::gpio;
12use embassy_rp::watchdog::*;
13use embassy_time::{Duration, Timer};
14use gpio::{Level, Output};
15use {defmt_rtt as _, panic_probe as _};
16
17#[embassy_executor::main]
18async fn main(_spawner: Spawner) {
19 let p = embassy_rp::init(Default::default());
20 info!("Hello world!");
21
22 let mut watchdog = Watchdog::new(p.WATCHDOG);
23 let mut led = Output::new(p.PIN_25, Level::Low);
24
25 // Set the LED high for 2 seconds so we know when we're about to start the watchdog
26 led.set_high();
27 Timer::after(Duration::from_secs(2)).await;
28
29 // Set to watchdog to reset if it's not fed within 1.05 seconds, and start it
30 watchdog.start(Duration::from_millis(1_050));
31 info!("Started the watchdog timer");
32
33 // Blink once a second for 5 seconds, feed the watchdog timer once a second to avoid a reset
34 for _ in 1..=5 {
35 led.set_low();
36 Timer::after(Duration::from_millis(500)).await;
37 led.set_high();
38 Timer::after(Duration::from_millis(500)).await;
39 info!("Feeding watchdog");
40 watchdog.feed();
41 }
42
43 info!("Stopped feeding, device will reset in 1.05 seconds");
44 // Blink 10 times per second, not feeding the watchdog.
45 // The processor should reset in 1.05 seconds.
46 loop {
47 led.set_low();
48 Timer::after(Duration::from_millis(100)).await;
49 led.set_high();
50 Timer::after(Duration::from_millis(100)).await;
51 }
52}
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs
new file mode 100644
index 000000000..e3e393445
--- /dev/null
+++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs
@@ -0,0 +1,139 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Creates an Access point Wifi network and creates a TCP endpoint on port 1234.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![feature(async_fn_in_trait)]
8#![allow(incomplete_features)]
9
10use core::str::from_utf8;
11
12use cyw43_pio::PioSpi;
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_net::tcp::TcpSocket;
16use embassy_net::{Config, Stack, StackResources};
17use embassy_rp::bind_interrupts;
18use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
20use embassy_rp::pio::{InterruptHandler, Pio};
21use embassy_time::Duration;
22use embedded_io::asynch::Write;
23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30#[embassy_executor::task]
31async fn wifi_task(
32 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
33) -> ! {
34 runner.run().await
35}
36
37#[embassy_executor::task]
38async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
39 stack.run().await
40}
41
42#[embassy_executor::main]
43async fn main(spawner: Spawner) {
44 info!("Hello World!");
45
46 let p = embassy_rp::init(Default::default());
47
48 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
49 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
50
51 // To make flashing faster for development, you may want to flash the firmwares independently
52 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
53 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
54 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
55 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
56 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
57
58 let pwr = Output::new(p.PIN_23, Level::Low);
59 let cs = Output::new(p.PIN_25, Level::High);
60 let mut pio = Pio::new(p.PIO0, Irqs);
61 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
62
63 let state = make_static!(cyw43::State::new());
64 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
65 unwrap!(spawner.spawn(wifi_task(runner)));
66
67 control.init(clm).await;
68 control
69 .set_power_management(cyw43::PowerManagementMode::PowerSave)
70 .await;
71
72 // Use a link-local address for communication without DHCP server
73 let config = Config::ipv4_static(embassy_net::StaticConfigV4 {
74 address: embassy_net::Ipv4Cidr::new(embassy_net::Ipv4Address::new(169, 254, 1, 1), 16),
75 dns_servers: heapless::Vec::new(),
76 gateway: None,
77 });
78
79 // Generate random seed
80 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
81
82 // Init network stack
83 let stack = &*make_static!(Stack::new(
84 net_device,
85 config,
86 make_static!(StackResources::<2>::new()),
87 seed
88 ));
89
90 unwrap!(spawner.spawn(net_task(stack)));
91
92 //control.start_ap_open("cyw43", 5).await;
93 control.start_ap_wpa2("cyw43", "password", 5).await;
94
95 // And now we can use it!
96
97 let mut rx_buffer = [0; 4096];
98 let mut tx_buffer = [0; 4096];
99 let mut buf = [0; 4096];
100
101 loop {
102 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
103 socket.set_timeout(Some(Duration::from_secs(10)));
104
105 control.gpio_set(0, false).await;
106 info!("Listening on TCP:1234...");
107 if let Err(e) = socket.accept(1234).await {
108 warn!("accept error: {:?}", e);
109 continue;
110 }
111
112 info!("Received connection from {:?}", socket.remote_endpoint());
113 control.gpio_set(0, true).await;
114
115 loop {
116 let n = match socket.read(&mut buf).await {
117 Ok(0) => {
118 warn!("read EOF");
119 break;
120 }
121 Ok(n) => n,
122 Err(e) => {
123 warn!("read error: {:?}", e);
124 break;
125 }
126 };
127
128 info!("rxd {}", from_utf8(&buf[..n]).unwrap());
129
130 match socket.write_all(&buf[..n]).await {
131 Ok(()) => {}
132 Err(e) => {
133 warn!("write error: {:?}", e);
134 break;
135 }
136 };
137 }
138 }
139}
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs
new file mode 100644
index 000000000..33d43788c
--- /dev/null
+++ b/examples/rp/src/bin/wifi_blinky.rs
@@ -0,0 +1,68 @@
1//! This example test the RP Pico W on board LED.
2//!
3//! It does not work with the RP Pico board. See blinky.rs.
4
5#![no_std]
6#![no_main]
7#![feature(type_alias_impl_trait)]
8
9use cyw43_pio::PioSpi;
10use defmt::*;
11use embassy_executor::Spawner;
12use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::{Level, Output};
14use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
15use embassy_rp::pio::{InterruptHandler, Pio};
16use embassy_time::{Duration, Timer};
17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _};
19
20bind_interrupts!(struct Irqs {
21 PIO0_IRQ_0 => InterruptHandler<PIO0>;
22});
23
24#[embassy_executor::task]
25async fn wifi_task(
26 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
27) -> ! {
28 runner.run().await
29}
30
31#[embassy_executor::main]
32async fn main(spawner: Spawner) {
33 let p = embassy_rp::init(Default::default());
34 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
35 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
36
37 // To make flashing faster for development, you may want to flash the firmwares independently
38 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
39 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
40 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
41 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
42 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
43
44 let pwr = Output::new(p.PIN_23, Level::Low);
45 let cs = Output::new(p.PIN_25, Level::High);
46 let mut pio = Pio::new(p.PIO0, Irqs);
47 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
48
49 let state = make_static!(cyw43::State::new());
50 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
51 unwrap!(spawner.spawn(wifi_task(runner)));
52
53 control.init(clm).await;
54 control
55 .set_power_management(cyw43::PowerManagementMode::PowerSave)
56 .await;
57
58 let delay = Duration::from_secs(1);
59 loop {
60 info!("led on!");
61 control.gpio_set(0, true).await;
62 Timer::after(delay).await;
63
64 info!("led off!");
65 control.gpio_set(0, false).await;
66 Timer::after(delay).await;
67 }
68}
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs
new file mode 100644
index 000000000..743fab617
--- /dev/null
+++ b/examples/rp/src/bin/wifi_scan.rs
@@ -0,0 +1,75 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Scans Wifi for ssid names.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![feature(async_fn_in_trait)]
8#![allow(incomplete_features)]
9
10use core::str;
11
12use cyw43_pio::PioSpi;
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_net::Stack;
16use embassy_rp::bind_interrupts;
17use embassy_rp::gpio::{Level, Output};
18use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
19use embassy_rp::pio::{InterruptHandler, Pio};
20use static_cell::make_static;
21use {defmt_rtt as _, panic_probe as _};
22
23bind_interrupts!(struct Irqs {
24 PIO0_IRQ_0 => InterruptHandler<PIO0>;
25});
26
27#[embassy_executor::task]
28async fn wifi_task(
29 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
30) -> ! {
31 runner.run().await
32}
33
34#[embassy_executor::task]
35async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
36 stack.run().await
37}
38
39#[embassy_executor::main]
40async fn main(spawner: Spawner) {
41 info!("Hello World!");
42
43 let p = embassy_rp::init(Default::default());
44
45 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
46 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
47
48 // To make flashing faster for development, you may want to flash the firmwares independently
49 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
50 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
51 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
52 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
53 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
54
55 let pwr = Output::new(p.PIN_23, Level::Low);
56 let cs = Output::new(p.PIN_25, Level::High);
57 let mut pio = Pio::new(p.PIO0, Irqs);
58 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
59
60 let state = make_static!(cyw43::State::new());
61 let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
62 unwrap!(spawner.spawn(wifi_task(runner)));
63
64 control.init(clm).await;
65 control
66 .set_power_management(cyw43::PowerManagementMode::PowerSave)
67 .await;
68
69 let mut scanner = control.scan().await;
70 while let Some(bss) = scanner.next().await {
71 if let Ok(ssid_str) = str::from_utf8(&bss.ssid) {
72 info!("scanned {} == {:x}", ssid_str, bss.bssid);
73 }
74 }
75}
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs
new file mode 100644
index 000000000..0223a3636
--- /dev/null
+++ b/examples/rp/src/bin/wifi_tcp_server.rs
@@ -0,0 +1,149 @@
1//! This example uses the RP Pico W board Wifi chip (cyw43).
2//! Connects to specified Wifi network and creates a TCP endpoint on port 1234.
3
4#![no_std]
5#![no_main]
6#![feature(type_alias_impl_trait)]
7#![feature(async_fn_in_trait)]
8#![allow(incomplete_features)]
9
10use core::str::from_utf8;
11
12use cyw43_pio::PioSpi;
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_net::tcp::TcpSocket;
16use embassy_net::{Config, Stack, StackResources};
17use embassy_rp::bind_interrupts;
18use embassy_rp::gpio::{Level, Output};
19use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_25, PIO0};
20use embassy_rp::pio::{InterruptHandler, Pio};
21use embassy_time::Duration;
22use embedded_io::asynch::Write;
23use static_cell::make_static;
24use {defmt_rtt as _, panic_probe as _};
25
26bind_interrupts!(struct Irqs {
27 PIO0_IRQ_0 => InterruptHandler<PIO0>;
28});
29
30const WIFI_NETWORK: &str = "EmbassyTest";
31const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
32
33#[embassy_executor::task]
34async fn wifi_task(
35 runner: cyw43::Runner<'static, Output<'static, PIN_23>, PioSpi<'static, PIN_25, PIO0, 0, DMA_CH0>>,
36) -> ! {
37 runner.run().await
38}
39
40#[embassy_executor::task]
41async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
42 stack.run().await
43}
44
45#[embassy_executor::main]
46async fn main(spawner: Spawner) {
47 info!("Hello World!");
48
49 let p = embassy_rp::init(Default::default());
50
51 let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin");
52 let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin");
53
54 // To make flashing faster for development, you may want to flash the firmwares independently
55 // at hardcoded addresses, instead of baking them into the program with `include_bytes!`:
56 // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
57 // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
58 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) };
59 //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) };
60
61 let pwr = Output::new(p.PIN_23, Level::Low);
62 let cs = Output::new(p.PIN_25, Level::High);
63 let mut pio = Pio::new(p.PIO0, Irqs);
64 let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0);
65
66 let state = make_static!(cyw43::State::new());
67 let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await;
68 unwrap!(spawner.spawn(wifi_task(runner)));
69
70 control.init(clm).await;
71 control
72 .set_power_management(cyw43::PowerManagementMode::PowerSave)
73 .await;
74
75 let config = Config::dhcpv4(Default::default());
76 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
77 // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
78 // dns_servers: Vec::new(),
79 // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
80 //});
81
82 // Generate random seed
83 let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
84
85 // Init network stack
86 let stack = &*make_static!(Stack::new(
87 net_device,
88 config,
89 make_static!(StackResources::<2>::new()),
90 seed
91 ));
92
93 unwrap!(spawner.spawn(net_task(stack)));
94
95 loop {
96 //control.join_open(WIFI_NETWORK).await;
97 match control.join_wpa2(WIFI_NETWORK, WIFI_PASSWORD).await {
98 Ok(_) => break,
99 Err(err) => {
100 info!("join failed with status={}", err.status);
101 }
102 }
103 }
104
105 // And now we can use it!
106
107 let mut rx_buffer = [0; 4096];
108 let mut tx_buffer = [0; 4096];
109 let mut buf = [0; 4096];
110
111 loop {
112 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
113 socket.set_timeout(Some(Duration::from_secs(10)));
114
115 control.gpio_set(0, false).await;
116 info!("Listening on TCP:1234...");
117 if let Err(e) = socket.accept(1234).await {
118 warn!("accept error: {:?}", e);
119 continue;
120 }
121
122 info!("Received connection from {:?}", socket.remote_endpoint());
123 control.gpio_set(0, true).await;
124
125 loop {
126 let n = match socket.read(&mut buf).await {
127 Ok(0) => {
128 warn!("read EOF");
129 break;
130 }
131 Ok(n) => n,
132 Err(e) => {
133 warn!("read error: {:?}", e);
134 break;
135 }
136 };
137
138 info!("rxd {}", from_utf8(&buf[..n]).unwrap());
139
140 match socket.write_all(&buf[..n]).await {
141 Ok(()) => {}
142 Err(e) => {
143 warn!("write error: {:?}", e);
144 break;
145 }
146 };
147 }
148 }
149}