aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorkbleeke <[email protected]>2023-02-19 16:31:35 +0100
committerkbleeke <[email protected]>2023-03-19 16:58:22 +0100
commit0ff606dfc151b1b3812087b7508fdf4bee3b240b (patch)
tree78f56aa0bbb64e97c1551258440402386267a9dc /examples
parentd57fe0de867cfc6510f0192fab488355d9ae8586 (diff)
Add pio transport to pico w example
Diffstat (limited to 'examples')
-rw-r--r--examples/rpi-pico-w/Cargo.toml40
-rw-r--r--examples/rpi-pico-w/build.rs34
-rw-r--r--examples/rpi-pico-w/src/main.rs31
-rw-r--r--examples/rpi-pico-w/src/pio.rs190
4 files changed, 262 insertions, 33 deletions
diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml
index 99b82ca31..0d789a932 100644
--- a/examples/rpi-pico-w/Cargo.toml
+++ b/examples/rpi-pico-w/Cargo.toml
@@ -5,11 +5,31 @@ edition = "2021"
5 5
6 6
7[dependencies] 7[dependencies]
8cyw43 = { path = "../../", features = ["defmt", "firmware-logs"]} 8cyw43 = { path = "../../", features = ["defmt", "firmware-logs"] }
9embassy-executor = { version = "0.1.0", features = ["defmt", "integrated-timers"] } 9embassy-executor = { version = "0.1.0", features = [
10embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] } 10 "defmt",
11embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } 11 "integrated-timers",
12embassy-net = { version = "0.1.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "nightly"] } 12] }
13embassy-time = { version = "0.1.0", features = [
14 "defmt",
15 "defmt-timestamp-uptime",
16] }
17embassy-rp = { version = "0.1.0", features = [
18 "defmt",
19 "unstable-traits",
20 "nightly",
21 "unstable-pac",
22 "pio",
23 "time-driver",
24] }
25embassy-net = { version = "0.1.0", features = [
26 "defmt",
27 "tcp",
28 "dhcpv4",
29 "medium-ethernet",
30 "unstable-traits",
31 "nightly",
32] }
13atomic-polyfill = "0.1.5" 33atomic-polyfill = "0.1.5"
14static_cell = "1.0" 34static_cell = "1.0"
15 35
@@ -17,9 +37,15 @@ defmt = "0.3"
17defmt-rtt = "0.3" 37defmt-rtt = "0.3"
18panic-probe = { version = "0.3", features = ["print-defmt"] } 38panic-probe = { version = "0.3", features = ["print-defmt"] }
19 39
20cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]} 40cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
21cortex-m-rt = "0.7.0" 41cortex-m-rt = "0.7.0"
22futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } 42futures = { version = "0.3.17", default-features = false, features = [
43 "async-await",
44 "cfg-target-has-atomic",
45 "unstable",
46] }
47pio-proc = "0.2"
48pio = "0.2.1"
23 49
24embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.9" } 50embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.9" }
25embedded-hal-async = { version = "0.2.0-alpha.0" } 51embedded-hal-async = { version = "0.2.0-alpha.0" }
diff --git a/examples/rpi-pico-w/build.rs b/examples/rpi-pico-w/build.rs
index d4c3ec89d..3f915f931 100644
--- a/examples/rpi-pico-w/build.rs
+++ b/examples/rpi-pico-w/build.rs
@@ -14,23 +14,23 @@ use std::io::Write;
14use std::path::PathBuf; 14use std::path::PathBuf;
15 15
16fn main() { 16fn main() {
17 // // Put `memory.x` in our output directory and ensure it's 17 // Put `memory.x` in our output directory and ensure it's
18 // // on the linker search path. 18 // on the linker search path.
19 // let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 // File::create(out.join("memory.x")) 20 File::create(out.join("memory.x"))
21 // .unwrap() 21 .unwrap()
22 // .write_all(include_bytes!("memory.x")) 22 .write_all(include_bytes!("memory.x"))
23 // .unwrap(); 23 .unwrap();
24 // println!("cargo:rustc-link-search={}", out.display()); 24 println!("cargo:rustc-link-search={}", out.display());
25 25
26 // // By default, Cargo will re-run a build script whenever 26 // By default, Cargo will re-run a build script whenever
27 // // any file in the project changes. By specifying `memory.x` 27 // any file in the project changes. By specifying `memory.x`
28 // // here, we ensure the build script is only re-run when 28 // here, we ensure the build script is only re-run when
29 // // `memory.x` is changed. 29 // `memory.x` is changed.
30 // println!("cargo:rerun-if-changed=memory.x"); 30 println!("cargo:rerun-if-changed=memory.x");
31 31
32 // println!("cargo:rustc-link-arg-bins=--nmagic"); 32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 // println!("cargo:rustc-link-arg-bins=-Tlink.x"); 33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 // println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); 34 println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
35 // println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36} 36}
diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs
index f768af193..3563d165a 100644
--- a/examples/rpi-pico-w/src/main.rs
+++ b/examples/rpi-pico-w/src/main.rs
@@ -4,21 +4,25 @@
4#![feature(async_fn_in_trait)] 4#![feature(async_fn_in_trait)]
5#![allow(incomplete_features)] 5#![allow(incomplete_features)]
6 6
7mod pio;
8
7use core::convert::Infallible; 9use core::convert::Infallible;
10use core::str::from_utf8;
8 11
9use defmt::*; 12use defmt::*;
10use embassy_executor::Spawner; 13use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket; 14use embassy_net::tcp::TcpSocket;
12use embassy_net::{Config, Stack, StackResources}; 15use embassy_net::{Config, Stack, StackResources};
13use embassy_rp::gpio::{Flex, Level, Output}; 16use embassy_rp::gpio::{Flex, Level, Output};
14use embassy_rp::peripherals::{PIN_23, PIN_24, PIN_25, PIN_29}; 17use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_24, PIN_25, PIN_29};
18use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachineInstance, Sm0};
15use embedded_hal_1::spi::ErrorType; 19use embedded_hal_1::spi::ErrorType;
16use embedded_hal_async::spi::{ExclusiveDevice, SpiBusFlush, SpiBusRead, SpiBusWrite}; 20use embedded_hal_async::spi::{ExclusiveDevice, SpiBusFlush, SpiBusRead, SpiBusWrite};
17use embedded_io::asynch::Write; 21use embedded_io::asynch::Write;
18use static_cell::StaticCell; 22use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _}; 23use {defmt_rtt as _, panic_probe as _};
20 24
21use core::str::from_utf8; 25use crate::pio::PioSpi;
22 26
23macro_rules! singleton { 27macro_rules! singleton {
24 ($val:expr) => {{ 28 ($val:expr) => {{
@@ -30,7 +34,11 @@ macro_rules! singleton {
30 34
31#[embassy_executor::task] 35#[embassy_executor::task]
32async fn wifi_task( 36async fn wifi_task(
33 runner: cyw43::Runner<'static, Output<'static, PIN_23>, ExclusiveDevice<MySpi, Output<'static, PIN_25>>>, 37 runner: cyw43::Runner<
38 'static,
39 Output<'static, PIN_23>,
40 ExclusiveDevice<PioSpi<PioStateMachineInstance<Pio0, Sm0>, DMA_CH0>, Output<'static, PIN_25>>,
41 >,
34) -> ! { 42) -> ! {
35 runner.run().await 43 runner.run().await
36} 44}
@@ -59,12 +67,15 @@ async fn main(spawner: Spawner) {
59 67
60 let pwr = Output::new(p.PIN_23, Level::Low); 68 let pwr = Output::new(p.PIN_23, Level::Low);
61 let cs = Output::new(p.PIN_25, Level::High); 69 let cs = Output::new(p.PIN_25, Level::High);
62 let clk = Output::new(p.PIN_29, Level::Low); 70 // let clk = Output::new(p.PIN_29, Level::Low);
63 let mut dio = Flex::new(p.PIN_24); 71 // let mut dio = Flex::new(p.PIN_24);
64 dio.set_low(); 72 // dio.set_low();
65 dio.set_as_output(); 73 // dio.set_as_output();
66 74 // // let bus = MySpi { clk, dio };
67 let bus = MySpi { clk, dio }; 75
76 let (_, sm, _, _, _) = p.PIO0.split();
77 let dma = p.DMA_CH0;
78 let bus = PioSpi::new(sm, p.PIN_24, p.PIN_29, dma);
68 let spi = ExclusiveDevice::new(bus, cs); 79 let spi = ExclusiveDevice::new(bus, cs);
69 80
70 let state = singleton!(cyw43::State::new()); 81 let state = singleton!(cyw43::State::new());
@@ -110,6 +121,7 @@ async fn main(spawner: Spawner) {
110 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); 121 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
111 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); 122 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
112 123
124 control.gpio_set(0, false).await;
113 info!("Listening on TCP:1234..."); 125 info!("Listening on TCP:1234...");
114 if let Err(e) = socket.accept(1234).await { 126 if let Err(e) = socket.accept(1234).await {
115 warn!("accept error: {:?}", e); 127 warn!("accept error: {:?}", e);
@@ -117,6 +129,7 @@ async fn main(spawner: Spawner) {
117 } 129 }
118 130
119 info!("Received connection from {:?}", socket.remote_endpoint()); 131 info!("Received connection from {:?}", socket.remote_endpoint());
132 control.gpio_set(0, true).await;
120 133
121 loop { 134 loop {
122 let n = match socket.read(&mut buf).await { 135 let n = match socket.read(&mut buf).await {
diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs
new file mode 100644
index 000000000..abb71b5de
--- /dev/null
+++ b/examples/rpi-pico-w/src/pio.rs
@@ -0,0 +1,190 @@
1use core::slice;
2
3use cyw43::SpiBusCyw43;
4use embassy_rp::dma::Channel;
5use embassy_rp::gpio::{Pin, Pull};
6use embassy_rp::pio::{PioStateMachine, ShiftDirection};
7use embassy_rp::relocate::RelocatedProgram;
8use embassy_rp::{pio_instr_util, Peripheral};
9use embedded_hal_1::spi::ErrorType;
10use embedded_hal_async::spi::SpiBusFlush;
11use pio::Wrap;
12use pio_proc::pio_asm;
13
14pub struct PioSpi<SM, DMA> {
15 // cs: Output<'static, AnyPin>,
16 sm: SM,
17 dma: DMA,
18 wrap_target: u8,
19}
20
21impl<SM, DMA> PioSpi<SM, DMA>
22where
23 SM: PioStateMachine,
24 DMA: Channel,
25{
26 pub fn new<DIO, CLK>(
27 mut sm: SM,
28 // cs: AnyPin,
29 dio: DIO,
30 clk: CLK,
31 dma: DMA,
32 ) -> Self
33 where
34 DIO: Pin,
35 CLK: Pin,
36 {
37 let program = pio_asm!(
38 ".side_set 1"
39 // "set pindirs, 1 side 0"
40 // "set pins, 0 side 0"
41 ".wrap_target"
42 "lp:",
43 "out pins, 1 side 0"
44 "jmp x-- lp side 1"
45 "set pindirs, 0 side 0"
46 // "nop side 1"
47 "lp2:"
48 "in pins, 1 side 0"
49 "jmp y-- lp2 side 1"
50 ".wrap"
51 );
52
53 let relocated = RelocatedProgram::new(&program.program);
54
55 let mut pin_io = sm.make_pio_pin(dio);
56 pin_io.set_pull(Pull::Down);
57 pin_io.set_schmitt(true);
58 let pin_clk = sm.make_pio_pin(clk);
59
60 sm.write_instr(relocated.origin() as usize, relocated.code());
61
62 // 16 Mhz
63 sm.set_clkdiv(0x07d0);
64
65 // 8Mhz
66 sm.set_clkdiv(0x0a_00);
67
68 // 1Mhz
69 // sm.set_clkdiv(0x7d_00);
70
71 // slowest possible
72 // sm.set_clkdiv(0xffff_00);
73
74 sm.set_autopull(true);
75 // sm.set_pull_threshold(32);
76 sm.set_autopush(true);
77 // sm.set_push_threshold(32);
78
79 sm.set_out_pins(&[&pin_io]);
80 sm.set_in_base_pin(&pin_io);
81
82 sm.set_set_pins(&[&pin_clk]);
83 pio_instr_util::set_pindir(&mut sm, 0b1);
84 sm.set_set_pins(&[&pin_io]);
85 pio_instr_util::set_pindir(&mut sm, 0b1);
86
87 sm.set_sideset_base_pin(&pin_clk);
88 sm.set_sideset_count(1);
89
90 sm.set_out_shift_dir(ShiftDirection::Left);
91 sm.set_in_shift_dir(ShiftDirection::Left);
92
93 let Wrap { source, target } = relocated.wrap();
94 sm.set_wrap(source, target);
95
96 // pull low for startup
97 pio_instr_util::set_pin(&mut sm, 0);
98
99 Self {
100 // cs: Output::new(cs, Level::High),
101 sm,
102 dma,
103 wrap_target: target,
104 }
105 }
106
107 pub async fn write(&mut self, write: &[u32]) {
108 let write_bits = write.len() * 32 - 1;
109 let read_bits = 31;
110
111 defmt::trace!("write={} read={}", write_bits, read_bits);
112
113 let mut dma = Peripheral::into_ref(&mut self.dma);
114 pio_instr_util::set_x(&mut self.sm, write_bits as u32);
115 pio_instr_util::set_y(&mut self.sm, read_bits as u32);
116 pio_instr_util::set_pindir(&mut self.sm, 0b1);
117 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target);
118
119 self.sm.set_enable(true);
120
121 self.sm.dma_push(dma.reborrow(), write).await;
122
123 let mut status = 0;
124 self.sm.dma_pull(dma, slice::from_mut(&mut status)).await;
125 defmt::trace!("{:#08x}", status);
126
127 self.sm.set_enable(false);
128 }
129
130 pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) {
131 let write_bits = 31;
132 let read_bits = read.len() * 32 - 1;
133
134 defmt::trace!("write={} read={}", write_bits, read_bits);
135
136 let mut dma = Peripheral::into_ref(&mut self.dma);
137 pio_instr_util::set_y(&mut self.sm, read_bits as u32);
138 pio_instr_util::set_x(&mut self.sm, write_bits as u32);
139 pio_instr_util::set_pindir(&mut self.sm, 0b1);
140 pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target);
141 // self.cs.set_low();
142 self.sm.set_enable(true);
143
144 self.sm.dma_push(dma.reborrow(), slice::from_ref(&cmd)).await;
145 self.sm.dma_pull(dma, read).await;
146
147 self.sm.set_enable(false);
148 }
149}
150
151#[derive(Debug)]
152pub enum PioError {}
153
154impl embedded_hal_async::spi::Error for PioError {
155 fn kind(&self) -> embedded_hal_1::spi::ErrorKind {
156 embedded_hal_1::spi::ErrorKind::Other
157 }
158}
159
160impl<SM, DMA> ErrorType for PioSpi<SM, DMA>
161where
162 SM: PioStateMachine,
163{
164 type Error = PioError;
165}
166
167impl<SM, DMA> SpiBusFlush for PioSpi<SM, DMA>
168where
169 SM: PioStateMachine,
170{
171 async fn flush(&mut self) -> Result<(), Self::Error> {
172 Ok(())
173 }
174}
175
176impl<SM, DMA> SpiBusCyw43<u32> for PioSpi<SM, DMA>
177where
178 SM: PioStateMachine,
179 DMA: Channel,
180{
181 async fn cmd_write<'a>(&'a mut self, write: &'a [u32]) -> Result<(), Self::Error> {
182 self.write(write).await;
183 Ok(())
184 }
185
186 async fn cmd_read<'a>(&'a mut self, write: &'a [u32], read: &'a mut [u32]) -> Result<(), Self::Error> {
187 self.cmd_read(write[0], read).await;
188 Ok(())
189 }
190}