From d57fe0de867cfc6510f0192fab488355d9ae8586 Mon Sep 17 00:00:00 2001 From: kbleeke Date: Sun, 19 Feb 2023 16:31:33 +0100 Subject: [PATCH 1/7] Custom Bus Trait to support PIO --- examples/rpi-pico-w/build.rs | 34 +++++------ examples/rpi-pico-w/src/main.rs | 11 ++++ src/bus.rs | 100 +++++++++++++++++++++++--------- src/lib.rs | 8 ++- 4 files changed, 104 insertions(+), 49 deletions(-) diff --git a/examples/rpi-pico-w/build.rs b/examples/rpi-pico-w/build.rs index 3f915f93..d4c3ec89 100644 --- a/examples/rpi-pico-w/build.rs +++ b/examples/rpi-pico-w/build.rs @@ -14,23 +14,23 @@ use std::io::Write; use std::path::PathBuf; fn main() { - // Put `memory.x` in our output directory and ensure it's - // on the linker search path. - let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - File::create(out.join("memory.x")) - .unwrap() - .write_all(include_bytes!("memory.x")) - .unwrap(); - println!("cargo:rustc-link-search={}", out.display()); + // // Put `memory.x` in our output directory and ensure it's + // // on the linker search path. + // let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + // File::create(out.join("memory.x")) + // .unwrap() + // .write_all(include_bytes!("memory.x")) + // .unwrap(); + // println!("cargo:rustc-link-search={}", out.display()); - // By default, Cargo will re-run a build script whenever - // any file in the project changes. By specifying `memory.x` - // here, we ensure the build script is only re-run when - // `memory.x` is changed. - println!("cargo:rerun-if-changed=memory.x"); + // // By default, Cargo will re-run a build script whenever + // // any file in the project changes. By specifying `memory.x` + // // here, we ensure the build script is only re-run when + // // `memory.x` is changed. + // println!("cargo:rerun-if-changed=memory.x"); - println!("cargo:rustc-link-arg-bins=--nmagic"); - println!("cargo:rustc-link-arg-bins=-Tlink.x"); - println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); - println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + // println!("cargo:rustc-link-arg-bins=--nmagic"); + // println!("cargo:rustc-link-arg-bins=-Tlink.x"); + // println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + // println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); } diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index c706e121..f768af19 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs @@ -161,6 +161,17 @@ impl ErrorType for MySpi { type Error = Infallible; } +impl cyw43::SpiBusCyw43 for MySpi { + async fn cmd_write<'a>(&'a mut self, write: &'a [u32]) -> Result<(), Self::Error> { + self.write(write).await + } + + async fn cmd_read<'a>(&'a mut self, write: &'a [u32], read: &'a mut [u32]) -> Result<(), Self::Error> { + self.write(write).await?; + self.read(read).await + } +} + impl SpiBusFlush for MySpi { async fn flush(&mut self) -> Result<(), Self::Error> { Ok(()) diff --git a/src/bus.rs b/src/bus.rs index f64c0abb..1c8bb989 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -2,10 +2,23 @@ use core::slice; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; +use embedded_hal_1::spi::ErrorType; use embedded_hal_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice}; use crate::consts::*; +/// Custom Spi Trait that _only_ supports the bus operation of the cyw43 +pub trait SpiBusCyw43: ErrorType { + /// Issues a write command on the bus + /// Frist 32 bits of `word` are expected to be a cmd word + async fn cmd_write<'a>(&'a mut self, write: &'a [Word]) -> Result<(), Self::Error>; + + /// Issues a read command on the bus + /// `write` is expected to be a 32 bit cmd word + /// `read` will contain the response of the device + async fn cmd_read<'a>(&'a mut self, write: &'a [Word], read: &'a mut [Word]) -> Result<(), Self::Error>; +} + pub(crate) struct Bus { backplane_window: u32, pwr: PWR, @@ -16,7 +29,7 @@ impl Bus where PWR: OutputPin, SPI: SpiDevice, - SPI::Bus: SpiBusRead + SpiBusWrite, + SPI::Bus: SpiBusCyw43, { pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { Self { @@ -52,8 +65,9 @@ where let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); let len_in_u32 = (len_in_u8 as usize + 3) / 4; transaction!(&mut self.spi, |bus| async { - bus.write(&[cmd]).await?; - bus.read(&mut buf[..len_in_u32]).await?; + // bus.write(&[cmd]).await?; + // bus.read(&mut buf[..len_in_u32]).await?; + bus.cmd_read(slice::from_ref(&cmd), &mut buf[..len_in_u32]).await?; Ok(()) }) .await @@ -62,9 +76,16 @@ where pub async fn wlan_write(&mut self, buf: &[u32]) { let cmd = cmd_word(WRITE, INC_ADDR, FUNC_WLAN, 0, buf.len() as u32 * 4); + //TODO try to remove copy? + let mut cmd_buf = [0_u32; 513]; + cmd_buf[0] = cmd; + cmd_buf[1..][..buf.len()].copy_from_slice(buf); + transaction!(&mut self.spi, |bus| async { - bus.write(&[cmd]).await?; - bus.write(buf).await?; + // bus.write(&[cmd]).await?; + // bus.write(buf).await?; + + bus.cmd_write(&cmd_buf).await?; Ok(()) }) .await @@ -79,7 +100,7 @@ where // To simplify, enforce 4-align for now. assert!(addr % 4 == 0); - let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4]; + let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; while !data.is_empty() { // Ensure transfer doesn't cross a window boundary. @@ -93,20 +114,23 @@ where let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); transaction!(&mut self.spi, |bus| async { - bus.write(&[cmd]).await?; + // bus.write(&[cmd]).await?; - // 4-byte response delay. - let mut junk = [0; 1]; - bus.read(&mut junk).await?; + // // 4-byte response delay. + // let mut junk = [0; 1]; + // bus.read(&mut junk).await?; - // Read data - bus.read(&mut buf[..(len + 3) / 4]).await?; + // // Read data + // bus.read(&mut buf[..(len + 3) / 4]).await?; + + bus.cmd_read(slice::from_ref(&cmd), &mut buf[..(len + 3) / 4 + 1]) + .await?; Ok(()) }) .await .unwrap(); - data[..len].copy_from_slice(&slice8_mut(&mut buf)[..len]); + data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); // Advance ptr. addr += len as u32; @@ -121,7 +145,7 @@ where // To simplify, enforce 4-align for now. assert!(addr % 4 == 0); - let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4]; + let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; while !data.is_empty() { // Ensure transfer doesn't cross a window boundary. @@ -129,15 +153,19 @@ where let window_remaining = BACKPLANE_WINDOW_SIZE - window_offs as usize; let len = data.len().min(BACKPLANE_MAX_TRANSFER_SIZE).min(window_remaining); - slice8_mut(&mut buf)[..len].copy_from_slice(&data[..len]); + slice8_mut(&mut buf[1..])[..len].copy_from_slice(&data[..len]); self.backplane_set_window(addr).await; let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); + buf[0] = cmd; transaction!(&mut self.spi, |bus| async { - bus.write(&[cmd]).await?; - bus.write(&buf[..(len + 3) / 4]).await?; + // bus.write(&[cmd]).await?; + // bus.write(&buf[..(len + 3) / 4]).await?; + + bus.cmd_write(&buf[..(len + 3) / 4 + 1]).await?; + Ok(()) }) .await @@ -253,28 +281,36 @@ where async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { let cmd = cmd_word(READ, INC_ADDR, func, addr, len); - let mut buf = [0; 1]; + let mut buf = [0; 2]; + let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; transaction!(&mut self.spi, |bus| async { - bus.write(&[cmd]).await?; - if func == FUNC_BACKPLANE { - // 4-byte response delay. - bus.read(&mut buf).await?; - } - bus.read(&mut buf).await?; + // bus.write(&[cmd]).await?; + // if func == FUNC_BACKPLANE { + // // 4-byte response delay. + // bus.read(&mut buf).await?; + // } + // bus.read(&mut buf).await?; + + bus.cmd_read(slice::from_ref(&cmd), &mut buf[..len]).await?; Ok(()) }) .await .unwrap(); - buf[0] + if func == FUNC_BACKPLANE { + buf[1] + } else { + buf[0] + } } async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); transaction!(&mut self.spi, |bus| async { - bus.write(&[cmd, val]).await?; + // bus.write(&[cmd, val]).await?; + bus.cmd_write(&[cmd, val]).await?; Ok(()) }) .await @@ -283,11 +319,14 @@ where async fn read32_swapped(&mut self, addr: u32) -> u32 { let cmd = cmd_word(READ, INC_ADDR, FUNC_BUS, addr, 4); + let cmd = swap16(cmd); let mut buf = [0; 1]; transaction!(&mut self.spi, |bus| async { - bus.write(&[swap16(cmd)]).await?; - bus.read(&mut buf).await?; + // bus.write(&[swap16(cmd)]).await?; + // bus.read(&mut buf).await?; + + bus.cmd_read(slice::from_ref(&cmd), &mut buf).await?; Ok(()) }) .await @@ -298,9 +337,12 @@ where async fn write32_swapped(&mut self, addr: u32, val: u32) { let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); + let buf = [swap16(cmd), swap16(val)]; transaction!(&mut self.spi, |bus| async { - bus.write(&[swap16(cmd), swap16(val)]).await?; + // bus.write(&[swap16(cmd), swap16(val)]).await?; + + bus.cmd_write(&buf).await?; Ok(()) }) .await diff --git a/src/lib.rs b/src/lib.rs index 5733506a..7bf3992c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![no_std] #![no_main] -#![feature(type_alias_impl_trait, concat_bytes)] +#![allow(incomplete_features)] +#![feature(async_fn_in_trait, type_alias_impl_trait, concat_bytes)] #![deny(unused_must_use)] // This mod MUST go first, so that the others see its macros. @@ -24,6 +25,7 @@ use embedded_hal_1::digital::OutputPin; use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice}; use crate::bus::Bus; +pub use crate::bus::SpiBusCyw43; use crate::consts::*; use crate::events::Event; use crate::structs::*; @@ -512,7 +514,7 @@ pub async fn new<'a, PWR, SPI>( where PWR: OutputPin, SPI: SpiDevice, - SPI::Bus: SpiBusRead + SpiBusWrite, + SPI::Bus: SpiBusCyw43, { let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); let state_ch = ch_runner.state_runner(); @@ -551,7 +553,7 @@ impl<'a, PWR, SPI> Runner<'a, PWR, SPI> where PWR: OutputPin, SPI: SpiDevice, - SPI::Bus: SpiBusRead + SpiBusWrite, + SPI::Bus: SpiBusCyw43, { async fn init(&mut self, firmware: &[u8]) { self.bus.init().await; From 0ff606dfc151b1b3812087b7508fdf4bee3b240b Mon Sep 17 00:00:00 2001 From: kbleeke Date: Sun, 19 Feb 2023 16:31:35 +0100 Subject: [PATCH 2/7] Add pio transport to pico w example --- examples/rpi-pico-w/Cargo.toml | 40 +++++-- examples/rpi-pico-w/build.rs | 34 +++--- examples/rpi-pico-w/src/main.rs | 29 +++-- examples/rpi-pico-w/src/pio.rs | 190 ++++++++++++++++++++++++++++++++ src/bus.rs | 2 +- src/lib.rs | 2 +- 6 files changed, 263 insertions(+), 34 deletions(-) create mode 100644 examples/rpi-pico-w/src/pio.rs diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml index 99b82ca3..0d789a93 100644 --- a/examples/rpi-pico-w/Cargo.toml +++ b/examples/rpi-pico-w/Cargo.toml @@ -5,11 +5,31 @@ edition = "2021" [dependencies] -cyw43 = { path = "../../", features = ["defmt", "firmware-logs"]} -embassy-executor = { version = "0.1.0", features = ["defmt", "integrated-timers"] } -embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] } -embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] } -embassy-net = { version = "0.1.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "nightly"] } +cyw43 = { path = "../../", features = ["defmt", "firmware-logs"] } +embassy-executor = { version = "0.1.0", features = [ + "defmt", + "integrated-timers", +] } +embassy-time = { version = "0.1.0", features = [ + "defmt", + "defmt-timestamp-uptime", +] } +embassy-rp = { version = "0.1.0", features = [ + "defmt", + "unstable-traits", + "nightly", + "unstable-pac", + "pio", + "time-driver", +] } +embassy-net = { version = "0.1.0", features = [ + "defmt", + "tcp", + "dhcpv4", + "medium-ethernet", + "unstable-traits", + "nightly", +] } atomic-polyfill = "0.1.5" static_cell = "1.0" @@ -17,9 +37,15 @@ defmt = "0.3" defmt-rtt = "0.3" panic-probe = { version = "0.3", features = ["print-defmt"] } -cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]} +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" -futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } +futures = { version = "0.3.17", default-features = false, features = [ + "async-await", + "cfg-target-has-atomic", + "unstable", +] } +pio-proc = "0.2" +pio = "0.2.1" embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.9" } embedded-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 d4c3ec89..3f915f93 100644 --- a/examples/rpi-pico-w/build.rs +++ b/examples/rpi-pico-w/build.rs @@ -14,23 +14,23 @@ use std::io::Write; use std::path::PathBuf; fn main() { - // // Put `memory.x` in our output directory and ensure it's - // // on the linker search path. - // let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); - // File::create(out.join("memory.x")) - // .unwrap() - // .write_all(include_bytes!("memory.x")) - // .unwrap(); - // println!("cargo:rustc-link-search={}", out.display()); + // Put `memory.x` in our output directory and ensure it's + // on the linker search path. + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); - // // By default, Cargo will re-run a build script whenever - // // any file in the project changes. By specifying `memory.x` - // // here, we ensure the build script is only re-run when - // // `memory.x` is changed. - // println!("cargo:rerun-if-changed=memory.x"); + // By default, Cargo will re-run a build script whenever + // any file in the project changes. By specifying `memory.x` + // here, we ensure the build script is only re-run when + // `memory.x` is changed. + println!("cargo:rerun-if-changed=memory.x"); - // println!("cargo:rustc-link-arg-bins=--nmagic"); - // println!("cargo:rustc-link-arg-bins=-Tlink.x"); - // println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); - // println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tlink-rp.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); } diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index f768af19..3563d165 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs @@ -4,21 +4,25 @@ #![feature(async_fn_in_trait)] #![allow(incomplete_features)] +mod pio; + use core::convert::Infallible; +use core::str::from_utf8; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; use embassy_net::{Config, Stack, StackResources}; use embassy_rp::gpio::{Flex, Level, Output}; -use embassy_rp::peripherals::{PIN_23, PIN_24, PIN_25, PIN_29}; +use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_24, PIN_25, PIN_29}; +use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachineInstance, Sm0}; use embedded_hal_1::spi::ErrorType; use embedded_hal_async::spi::{ExclusiveDevice, SpiBusFlush, SpiBusRead, SpiBusWrite}; use embedded_io::asynch::Write; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use core::str::from_utf8; +use crate::pio::PioSpi; macro_rules! singleton { ($val:expr) => {{ @@ -30,7 +34,11 @@ macro_rules! singleton { #[embassy_executor::task] async fn wifi_task( - runner: cyw43::Runner<'static, Output<'static, PIN_23>, ExclusiveDevice>>, + runner: cyw43::Runner< + 'static, + Output<'static, PIN_23>, + ExclusiveDevice, DMA_CH0>, Output<'static, PIN_25>>, + >, ) -> ! { runner.run().await } @@ -59,12 +67,15 @@ async fn main(spawner: Spawner) { let pwr = Output::new(p.PIN_23, Level::Low); let cs = Output::new(p.PIN_25, Level::High); - let clk = Output::new(p.PIN_29, Level::Low); - let mut dio = Flex::new(p.PIN_24); - dio.set_low(); - dio.set_as_output(); + // let clk = Output::new(p.PIN_29, Level::Low); + // let mut dio = Flex::new(p.PIN_24); + // dio.set_low(); + // dio.set_as_output(); + // // let bus = MySpi { clk, dio }; - let bus = MySpi { clk, dio }; + let (_, sm, _, _, _) = p.PIO0.split(); + let dma = p.DMA_CH0; + let bus = PioSpi::new(sm, p.PIN_24, p.PIN_29, dma); let spi = ExclusiveDevice::new(bus, cs); let state = singleton!(cyw43::State::new()); @@ -110,6 +121,7 @@ async fn main(spawner: Spawner) { let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10))); + control.gpio_set(0, false).await; info!("Listening on TCP:1234..."); if let Err(e) = socket.accept(1234).await { warn!("accept error: {:?}", e); @@ -117,6 +129,7 @@ async fn main(spawner: Spawner) { } info!("Received connection from {:?}", socket.remote_endpoint()); + control.gpio_set(0, true).await; loop { 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 00000000..abb71b5d --- /dev/null +++ b/examples/rpi-pico-w/src/pio.rs @@ -0,0 +1,190 @@ +use core::slice; + +use cyw43::SpiBusCyw43; +use embassy_rp::dma::Channel; +use embassy_rp::gpio::{Pin, Pull}; +use embassy_rp::pio::{PioStateMachine, ShiftDirection}; +use embassy_rp::relocate::RelocatedProgram; +use embassy_rp::{pio_instr_util, Peripheral}; +use embedded_hal_1::spi::ErrorType; +use embedded_hal_async::spi::SpiBusFlush; +use pio::Wrap; +use pio_proc::pio_asm; + +pub struct PioSpi { + // cs: Output<'static, AnyPin>, + sm: SM, + dma: DMA, + wrap_target: u8, +} + +impl PioSpi +where + SM: PioStateMachine, + DMA: Channel, +{ + pub fn new( + mut sm: SM, + // cs: AnyPin, + dio: DIO, + clk: CLK, + dma: DMA, + ) -> Self + where + DIO: Pin, + CLK: Pin, + { + let program = pio_asm!( + ".side_set 1" + // "set pindirs, 1 side 0" + // "set pins, 0 side 0" + ".wrap_target" + "lp:", + "out pins, 1 side 0" + "jmp x-- lp side 1" + "set pindirs, 0 side 0" + // "nop side 1" + "lp2:" + "in pins, 1 side 0" + "jmp y-- lp2 side 1" + ".wrap" + ); + + let relocated = RelocatedProgram::new(&program.program); + + let mut pin_io = sm.make_pio_pin(dio); + pin_io.set_pull(Pull::Down); + pin_io.set_schmitt(true); + let pin_clk = sm.make_pio_pin(clk); + + sm.write_instr(relocated.origin() as usize, relocated.code()); + + // 16 Mhz + sm.set_clkdiv(0x07d0); + + // 8Mhz + sm.set_clkdiv(0x0a_00); + + // 1Mhz + // sm.set_clkdiv(0x7d_00); + + // slowest possible + // sm.set_clkdiv(0xffff_00); + + sm.set_autopull(true); + // sm.set_pull_threshold(32); + sm.set_autopush(true); + // sm.set_push_threshold(32); + + sm.set_out_pins(&[&pin_io]); + sm.set_in_base_pin(&pin_io); + + sm.set_set_pins(&[&pin_clk]); + pio_instr_util::set_pindir(&mut sm, 0b1); + sm.set_set_pins(&[&pin_io]); + pio_instr_util::set_pindir(&mut sm, 0b1); + + sm.set_sideset_base_pin(&pin_clk); + sm.set_sideset_count(1); + + sm.set_out_shift_dir(ShiftDirection::Left); + sm.set_in_shift_dir(ShiftDirection::Left); + + let Wrap { source, target } = relocated.wrap(); + sm.set_wrap(source, target); + + // pull low for startup + pio_instr_util::set_pin(&mut sm, 0); + + Self { + // cs: Output::new(cs, Level::High), + sm, + dma, + wrap_target: target, + } + } + + pub async fn write(&mut self, write: &[u32]) { + let write_bits = write.len() * 32 - 1; + let read_bits = 31; + + defmt::trace!("write={} read={}", write_bits, read_bits); + + let mut dma = Peripheral::into_ref(&mut self.dma); + pio_instr_util::set_x(&mut self.sm, write_bits as u32); + pio_instr_util::set_y(&mut self.sm, read_bits as u32); + pio_instr_util::set_pindir(&mut self.sm, 0b1); + pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); + + self.sm.set_enable(true); + + self.sm.dma_push(dma.reborrow(), write).await; + + let mut status = 0; + self.sm.dma_pull(dma, slice::from_mut(&mut status)).await; + defmt::trace!("{:#08x}", status); + + self.sm.set_enable(false); + } + + pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) { + let write_bits = 31; + let read_bits = read.len() * 32 - 1; + + defmt::trace!("write={} read={}", write_bits, read_bits); + + let mut dma = Peripheral::into_ref(&mut self.dma); + pio_instr_util::set_y(&mut self.sm, read_bits as u32); + pio_instr_util::set_x(&mut self.sm, write_bits as u32); + pio_instr_util::set_pindir(&mut self.sm, 0b1); + pio_instr_util::exec_jmp(&mut self.sm, self.wrap_target); + // self.cs.set_low(); + self.sm.set_enable(true); + + self.sm.dma_push(dma.reborrow(), slice::from_ref(&cmd)).await; + self.sm.dma_pull(dma, read).await; + + self.sm.set_enable(false); + } +} + +#[derive(Debug)] +pub enum PioError {} + +impl embedded_hal_async::spi::Error for PioError { + fn kind(&self) -> embedded_hal_1::spi::ErrorKind { + embedded_hal_1::spi::ErrorKind::Other + } +} + +impl ErrorType for PioSpi +where + SM: PioStateMachine, +{ + type Error = PioError; +} + +impl SpiBusFlush for PioSpi +where + SM: PioStateMachine, +{ + async fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} + +impl SpiBusCyw43 for PioSpi +where + SM: PioStateMachine, + DMA: Channel, +{ + async fn cmd_write<'a>(&'a mut self, write: &'a [u32]) -> Result<(), Self::Error> { + self.write(write).await; + Ok(()) + } + + async fn cmd_read<'a>(&'a mut self, write: &'a [u32], read: &'a mut [u32]) -> Result<(), Self::Error> { + self.cmd_read(write[0], read).await; + Ok(()) + } +} diff --git a/src/bus.rs b/src/bus.rs index 1c8bb989..aaa79b19 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -3,7 +3,7 @@ use core::slice; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; use embedded_hal_1::spi::ErrorType; -use embedded_hal_async::spi::{transaction, SpiBusRead, SpiBusWrite, SpiDevice}; +use embedded_hal_async::spi::{transaction, SpiDevice}; use crate::consts::*; diff --git a/src/lib.rs b/src/lib.rs index 7bf3992c..bcc3c59b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ use embassy_futures::yield_now; use embassy_net_driver_channel as ch; use embassy_time::{block_for, Duration, Timer}; use embedded_hal_1::digital::OutputPin; -use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice}; +use embedded_hal_async::spi::SpiDevice; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; From a6a2a035d57ced9a7a9bb2ef325885063ea83295 Mon Sep 17 00:00:00 2001 From: kbleeke Date: Sun, 19 Mar 2023 16:43:46 +0100 Subject: [PATCH 3/7] even faster pio speed are possible --- examples/rpi-pico-w/src/pio.rs | 22 +++++++++++++++------- rust-toolchain.toml | 2 +- src/bus.rs | 31 +++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs index abb71b5d..1bf304d5 100644 --- a/examples/rpi-pico-w/src/pio.rs +++ b/examples/rpi-pico-w/src/pio.rs @@ -2,7 +2,7 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::dma::Channel; -use embassy_rp::gpio::{Pin, Pull}; +use embassy_rp::gpio::{Drive, Pin, Pull, SlewRate}; use embassy_rp::pio::{PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; @@ -43,10 +43,11 @@ where "out pins, 1 side 0" "jmp x-- lp side 1" "set pindirs, 0 side 0" - // "nop side 1" + "nop side 1" "lp2:" - "in pins, 1 side 0" - "jmp y-- lp2 side 1" + "in pins, 1 side 1" + "jmp y-- lp2 side 0" + ".wrap" ); @@ -55,15 +56,22 @@ where let mut pin_io = sm.make_pio_pin(dio); pin_io.set_pull(Pull::Down); pin_io.set_schmitt(true); - let pin_clk = sm.make_pio_pin(clk); + pin_io.set_input_sync_bypass(true); + + let mut pin_clk = sm.make_pio_pin(clk); + pin_clk.set_drive_strength(Drive::_12mA); + pin_clk.set_slew_rate(SlewRate::Fast); sm.write_instr(relocated.origin() as usize, relocated.code()); + // 32 Mhz + sm.set_clkdiv(0x03E8); + // 16 Mhz - sm.set_clkdiv(0x07d0); + // sm.set_clkdiv(0x07d0); // 8Mhz - sm.set_clkdiv(0x0a_00); + // sm.set_clkdiv(0x0a_00); // 1Mhz // sm.set_clkdiv(0x7d_00); diff --git a/rust-toolchain.toml b/rust-toolchain.toml index ffbcbd6f..20c10c3f 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,7 +1,7 @@ # Before upgrading check that everything is available on all tier1 targets here: # https://rust-lang.github.io/rustup-components-history [toolchain] -channel = "nightly-2022-11-22" +channel = "nightly-2023-03-19" components = [ "rust-src", "rustfmt" ] targets = [ "thumbv6m-none-eabi", diff --git a/src/bus.rs b/src/bus.rs index aaa79b19..e4f9a69b 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -4,6 +4,7 @@ use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; use embedded_hal_1::spi::ErrorType; use embedded_hal_async::spi::{transaction, SpiDevice}; +use futures::FutureExt; use crate::consts::*; @@ -46,18 +47,40 @@ where self.pwr.set_high().unwrap(); Timer::after(Duration::from_millis(250)).await; - while self.read32_swapped(REG_BUS_TEST_RO).await != FEEDBEAD {} + while self + .read32_swapped(REG_BUS_TEST_RO) + .inspect(|v| defmt::trace!("{:#x}", v)) + .await + != FEEDBEAD + {} self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; - let val = self.read32_swapped(REG_BUS_TEST_RW).await; + let val = self + .read32_swapped(REG_BUS_TEST_RW) + .inspect(|v| defmt::trace!("{:#x}", v)) + .await; assert_eq!(val, TEST_PATTERN); + self.read32_swapped(REG_BUS_CTRL) + .inspect(|v| defmt::trace!("{:#010b}", (v & 0xff))) + .await; + // 32-bit word length, little endian (which is the default endianess). self.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED).await; - let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; + self.read8(FUNC_BUS, REG_BUS_CTRL) + .inspect(|v| defmt::trace!("{:#b}", v)) + .await; + + let val = self + .read32(FUNC_BUS, REG_BUS_TEST_RO) + .inspect(|v| defmt::trace!("{:#x}", v)) + .await; assert_eq!(val, FEEDBEAD); - let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; + let val = self + .read32(FUNC_BUS, REG_BUS_TEST_RW) + .inspect(|v| defmt::trace!("{:#x}", v)) + .await; assert_eq!(val, TEST_PATTERN); } From b4b8d829801e149c90f9f0fc85736be3549dff87 Mon Sep 17 00:00:00 2001 From: kbleeke Date: Tue, 21 Mar 2023 19:15:54 +0100 Subject: [PATCH 4/7] remove use of embedded-hal SPI traits. Instead just call our bus trait directly and push responsibility for implementing CS on the trait implementor --- Cargo.toml | 1 - examples/rpi-pico-w/Cargo.toml | 2 - examples/rpi-pico-w/src/main.rs | 62 ++++++++----------- examples/rpi-pico-w/src/pio.rs | 61 +++++-------------- src/bus.rs | 104 +++++--------------------------- src/lib.rs | 7 +-- 6 files changed, 59 insertions(+), 178 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6e323744..3bdeb0cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,5 +25,4 @@ cortex-m-rt = "0.7.0" futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.9" } -embedded-hal-async = { version = "0.2.0-alpha.0" } num_enum = { version = "0.5.7", default-features = false } diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml index 0d789a93..17b4214d 100644 --- a/examples/rpi-pico-w/Cargo.toml +++ b/examples/rpi-pico-w/Cargo.toml @@ -47,8 +47,6 @@ futures = { version = "0.3.17", default-features = false, features = [ pio-proc = "0.2" pio = "0.2.1" -embedded-hal-1 = { package = "embedded-hal", version = "1.0.0-alpha.9" } -embedded-hal-async = { version = "0.2.0-alpha.0" } embedded-io = { version = "0.4.0", features = ["async", "defmt"] } heapless = "0.7.15" diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index 3563d165..f30a20ba 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs @@ -1,4 +1,4 @@ -#![no_std] +#![no_std] #![no_main] #![feature(type_alias_impl_trait)] #![feature(async_fn_in_trait)] @@ -6,7 +6,7 @@ mod pio; -use core::convert::Infallible; +use core::slice; use core::str::from_utf8; use defmt::*; @@ -16,8 +16,6 @@ use embassy_net::{Config, Stack, StackResources}; use embassy_rp::gpio::{Flex, Level, Output}; use embassy_rp::peripherals::{DMA_CH0, PIN_23, PIN_24, PIN_25, PIN_29}; use embassy_rp::pio::{Pio0, PioPeripherial, PioStateMachineInstance, Sm0}; -use embedded_hal_1::spi::ErrorType; -use embedded_hal_async::spi::{ExclusiveDevice, SpiBusFlush, SpiBusRead, SpiBusWrite}; use embedded_io::asynch::Write; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; @@ -37,7 +35,7 @@ async fn wifi_task( runner: cyw43::Runner< 'static, Output<'static, PIN_23>, - ExclusiveDevice, DMA_CH0>, Output<'static, PIN_25>>, + PioSpi, DMA_CH0>, >, ) -> ! { runner.run().await @@ -75,8 +73,7 @@ async fn main(spawner: Spawner) { let (_, sm, _, _, _) = p.PIO0.split(); let dma = p.DMA_CH0; - let bus = PioSpi::new(sm, p.PIN_24, p.PIN_29, dma); - let spi = ExclusiveDevice::new(bus, cs); + let spi = PioSpi::new(sm, cs, p.PIN_24, p.PIN_29, dma); let state = singleton!(cyw43::State::new()); let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; @@ -146,7 +143,6 @@ async fn main(spawner: Spawner) { info!("rxd {}", from_utf8(&buf[..n]).unwrap()); - match socket.write_all(&buf[..n]).await { Ok(()) => {} Err(e) => { @@ -168,31 +164,13 @@ struct MySpi { /// - IRQ /// - strap to set to gSPI mode on boot. dio: Flex<'static, PIN_24>, + + /// Chip select + cs: Output<'static, PIN_25>, } -impl ErrorType for MySpi { - type Error = Infallible; -} - -impl cyw43::SpiBusCyw43 for MySpi { - async fn cmd_write<'a>(&'a mut self, write: &'a [u32]) -> Result<(), Self::Error> { - self.write(write).await - } - - async fn cmd_read<'a>(&'a mut self, write: &'a [u32], read: &'a mut [u32]) -> Result<(), Self::Error> { - self.write(write).await?; - self.read(read).await - } -} - -impl SpiBusFlush for MySpi { - async fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl SpiBusRead for MySpi { - async fn read(&mut self, words: &mut [u32]) -> Result<(), Self::Error> { +impl MySpi { + async fn read(&mut self, words: &mut [u32]) { self.dio.set_as_input(); for word in words { let mut w = 0; @@ -210,13 +188,9 @@ impl SpiBusRead for MySpi { } *word = w } - - Ok(()) } -} -impl SpiBusWrite for MySpi { - async fn write(&mut self, words: &[u32]) -> Result<(), Self::Error> { + async fn write(&mut self, words: &[u32]) { self.dio.set_as_output(); for word in words { let mut word = *word; @@ -238,6 +212,20 @@ impl SpiBusWrite for MySpi { self.clk.set_low(); self.dio.set_as_input(); - Ok(()) + } +} + +impl cyw43::SpiBusCyw43 for MySpi { + async fn cmd_write(&mut self, write: &[u32]) { + self.cs.set_low(); + self.write(write).await; + self.cs.set_high(); + } + + async fn cmd_read(&mut self, write: u32, read: &mut [u32]) { + self.cs.set_low(); + self.write(slice::from_ref(&write)).await; + self.read(read).await; + self.cs.set_high(); } } diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs index 1bf304d5..896fd045 100644 --- a/examples/rpi-pico-w/src/pio.rs +++ b/examples/rpi-pico-w/src/pio.rs @@ -2,34 +2,27 @@ use core::slice; use cyw43::SpiBusCyw43; use embassy_rp::dma::Channel; -use embassy_rp::gpio::{Drive, Pin, Pull, SlewRate}; +use embassy_rp::gpio::{Drive, Output, Pin, Pull, SlewRate}; use embassy_rp::pio::{PioStateMachine, ShiftDirection}; use embassy_rp::relocate::RelocatedProgram; use embassy_rp::{pio_instr_util, Peripheral}; -use embedded_hal_1::spi::ErrorType; -use embedded_hal_async::spi::SpiBusFlush; use pio::Wrap; use pio_proc::pio_asm; -pub struct PioSpi { - // cs: Output<'static, AnyPin>, +pub struct PioSpi { + cs: Output<'static, CS>, sm: SM, dma: DMA, wrap_target: u8, } -impl PioSpi +impl PioSpi where SM: PioStateMachine, DMA: Channel, + CS: Pin, { - pub fn new( - mut sm: SM, - // cs: AnyPin, - dio: DIO, - clk: CLK, - dma: DMA, - ) -> Self + pub fn new(mut sm: SM, cs: Output<'static, CS>, dio: DIO, clk: CLK, dma: DMA) -> Self where DIO: Pin, CLK: Pin, @@ -105,7 +98,7 @@ where pio_instr_util::set_pin(&mut sm, 0); Self { - // cs: Output::new(cs, Level::High), + cs, sm, dma, wrap_target: target, @@ -156,43 +149,21 @@ where } } -#[derive(Debug)] -pub enum PioError {} - -impl embedded_hal_async::spi::Error for PioError { - fn kind(&self) -> embedded_hal_1::spi::ErrorKind { - embedded_hal_1::spi::ErrorKind::Other - } -} - -impl ErrorType for PioSpi -where - SM: PioStateMachine, -{ - type Error = PioError; -} - -impl SpiBusFlush for PioSpi -where - SM: PioStateMachine, -{ - async fn flush(&mut self) -> Result<(), Self::Error> { - Ok(()) - } -} - -impl SpiBusCyw43 for PioSpi +impl SpiBusCyw43 for PioSpi where + CS: Pin, SM: PioStateMachine, DMA: Channel, { - async fn cmd_write<'a>(&'a mut self, write: &'a [u32]) -> Result<(), Self::Error> { + async fn cmd_write(&mut self, write: & [u32]) { + self.cs.set_low(); self.write(write).await; - Ok(()) + self.cs.set_high(); } - async fn cmd_read<'a>(&'a mut self, write: &'a [u32], read: &'a mut [u32]) -> Result<(), Self::Error> { - self.cmd_read(write[0], read).await; - Ok(()) + async fn cmd_read(&mut self, write: u32, read: & mut [u32]) { + self.cs.set_low(); + self.cmd_read(write, read).await; + self.cs.set_high(); } } diff --git a/src/bus.rs b/src/bus.rs index e4f9a69b..90990f35 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -2,22 +2,22 @@ use core::slice; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; -use embedded_hal_1::spi::ErrorType; -use embedded_hal_async::spi::{transaction, SpiDevice}; use futures::FutureExt; use crate::consts::*; /// Custom Spi Trait that _only_ supports the bus operation of the cyw43 -pub trait SpiBusCyw43: ErrorType { +/// Implementors are expected to hold the CS pin low during an operation. +pub trait SpiBusCyw43 { /// Issues a write command on the bus - /// Frist 32 bits of `word` are expected to be a cmd word - async fn cmd_write<'a>(&'a mut self, write: &'a [Word]) -> Result<(), Self::Error>; + /// First 32 bits of `word` are expected to be a cmd word + async fn cmd_write(&mut self, write: &[u32]); /// Issues a read command on the bus /// `write` is expected to be a 32 bit cmd word /// `read` will contain the response of the device - async fn cmd_read<'a>(&'a mut self, write: &'a [Word], read: &'a mut [Word]) -> Result<(), Self::Error>; + /// + async fn cmd_read(&mut self, write: u32, read: &mut [u32]); } pub(crate) struct Bus { @@ -29,8 +29,7 @@ pub(crate) struct Bus { impl Bus where PWR: OutputPin, - SPI: SpiDevice, - SPI::Bus: SpiBusCyw43, + SPI: SpiBusCyw43, { pub(crate) fn new(pwr: PWR, spi: SPI) -> Self { Self { @@ -87,14 +86,8 @@ where pub async fn wlan_read(&mut self, buf: &mut [u32], len_in_u8: u32) { let cmd = cmd_word(READ, INC_ADDR, FUNC_WLAN, 0, len_in_u8); let len_in_u32 = (len_in_u8 as usize + 3) / 4; - transaction!(&mut self.spi, |bus| async { - // bus.write(&[cmd]).await?; - // bus.read(&mut buf[..len_in_u32]).await?; - bus.cmd_read(slice::from_ref(&cmd), &mut buf[..len_in_u32]).await?; - Ok(()) - }) - .await - .unwrap(); + + self.spi.cmd_read(cmd, &mut buf[..len_in_u32]).await; } pub async fn wlan_write(&mut self, buf: &[u32]) { @@ -104,15 +97,7 @@ where cmd_buf[0] = cmd; cmd_buf[1..][..buf.len()].copy_from_slice(buf); - transaction!(&mut self.spi, |bus| async { - // bus.write(&[cmd]).await?; - // bus.write(buf).await?; - - bus.cmd_write(&cmd_buf).await?; - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_write(&cmd_buf).await; } #[allow(unused)] @@ -136,22 +121,7 @@ where let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); - transaction!(&mut self.spi, |bus| async { - // bus.write(&[cmd]).await?; - - // // 4-byte response delay. - // let mut junk = [0; 1]; - // bus.read(&mut junk).await?; - - // // Read data - // bus.read(&mut buf[..(len + 3) / 4]).await?; - - bus.cmd_read(slice::from_ref(&cmd), &mut buf[..(len + 3) / 4 + 1]) - .await?; - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await; data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); @@ -183,16 +153,7 @@ where let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); buf[0] = cmd; - transaction!(&mut self.spi, |bus| async { - // bus.write(&[cmd]).await?; - // bus.write(&buf[..(len + 3) / 4]).await?; - - bus.cmd_write(&buf[..(len + 3) / 4 + 1]).await?; - - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_write(&buf[..(len + 3) / 4 + 1]).await; // Advance ptr. addr += len as u32; @@ -307,19 +268,7 @@ where let mut buf = [0; 2]; let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; - transaction!(&mut self.spi, |bus| async { - // bus.write(&[cmd]).await?; - // if func == FUNC_BACKPLANE { - // // 4-byte response delay. - // bus.read(&mut buf).await?; - // } - // bus.read(&mut buf).await?; - - bus.cmd_read(slice::from_ref(&cmd), &mut buf[..len]).await?; - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_read(cmd, &mut buf[..len]).await; if func == FUNC_BACKPLANE { buf[1] @@ -331,13 +280,7 @@ where async fn writen(&mut self, func: u32, addr: u32, val: u32, len: u32) { let cmd = cmd_word(WRITE, INC_ADDR, func, addr, len); - transaction!(&mut self.spi, |bus| async { - // bus.write(&[cmd, val]).await?; - bus.cmd_write(&[cmd, val]).await?; - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_write(&[cmd, val]).await; } async fn read32_swapped(&mut self, addr: u32) -> u32 { @@ -345,15 +288,7 @@ where let cmd = swap16(cmd); let mut buf = [0; 1]; - transaction!(&mut self.spi, |bus| async { - // bus.write(&[swap16(cmd)]).await?; - // bus.read(&mut buf).await?; - - bus.cmd_read(slice::from_ref(&cmd), &mut buf).await?; - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_read(cmd, &mut buf).await; swap16(buf[0]) } @@ -362,14 +297,7 @@ where let cmd = cmd_word(WRITE, INC_ADDR, FUNC_BUS, addr, 4); let buf = [swap16(cmd), swap16(val)]; - transaction!(&mut self.spi, |bus| async { - // bus.write(&[swap16(cmd), swap16(val)]).await?; - - bus.cmd_write(&buf).await?; - Ok(()) - }) - .await - .unwrap(); + self.spi.cmd_write(&buf).await; } } diff --git a/src/lib.rs b/src/lib.rs index bcc3c59b..f0a7aaa0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,6 @@ use embassy_futures::yield_now; use embassy_net_driver_channel as ch; use embassy_time::{block_for, Duration, Timer}; use embedded_hal_1::digital::OutputPin; -use embedded_hal_async::spi::SpiDevice; use crate::bus::Bus; pub use crate::bus::SpiBusCyw43; @@ -513,8 +512,7 @@ pub async fn new<'a, PWR, SPI>( ) -> (NetDriver<'a>, Control<'a>, Runner<'a, PWR, SPI>) where PWR: OutputPin, - SPI: SpiDevice, - SPI::Bus: SpiBusCyw43, + SPI: SpiBusCyw43, { let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); let state_ch = ch_runner.state_runner(); @@ -552,8 +550,7 @@ where impl<'a, PWR, SPI> Runner<'a, PWR, SPI> where PWR: OutputPin, - SPI: SpiDevice, - SPI::Bus: SpiBusCyw43, + SPI: SpiBusCyw43, { async fn init(&mut self, firmware: &[u8]) { self.bus.init().await; From 3034e8fb458cae0ff84d1ca07b4a64bced815f0c Mon Sep 17 00:00:00 2001 From: kbleeke Date: Tue, 21 Mar 2023 19:26:01 +0100 Subject: [PATCH 5/7] document response delay quirks in bus code --- src/bus.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bus.rs b/src/bus.rs index 90990f35..262b9e0d 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -16,7 +16,8 @@ pub trait SpiBusCyw43 { /// Issues a read command on the bus /// `write` is expected to be a 32 bit cmd word /// `read` will contain the response of the device - /// + /// Backplane reads have a response delay that produces one extra unspecified word at the beginning of `read`. + /// Callers that want to read `n` word from the backplane, have to provide a slice that is `n+1` words long. async fn cmd_read(&mut self, write: u32, read: &mut [u32]); } @@ -108,6 +109,7 @@ where // To simplify, enforce 4-align for now. assert!(addr % 4 == 0); + // Backplane read buffer has one extra word for the response delay. let mut buf = [0u32; BACKPLANE_MAX_TRANSFER_SIZE / 4 + 1]; while !data.is_empty() { @@ -121,8 +123,10 @@ where let cmd = cmd_word(READ, INC_ADDR, FUNC_BACKPLANE, window_offs, len as u32); + // round `buf` to word boundary, add one extra word for the response delay self.spi.cmd_read(cmd, &mut buf[..(len + 3) / 4 + 1]).await; + // when writing out the data, we skip the response-delay byte data[..len].copy_from_slice(&slice8_mut(&mut buf[1..])[..len]); // Advance ptr. @@ -266,10 +270,12 @@ where async fn readn(&mut self, func: u32, addr: u32, len: u32) -> u32 { let cmd = cmd_word(READ, INC_ADDR, func, addr, len); let mut buf = [0; 2]; + // if we are reading from the backplane, we need an extra word for the response delay let len = if func == FUNC_BACKPLANE { 2 } else { 1 }; self.spi.cmd_read(cmd, &mut buf[..len]).await; + // if we read from the backplane, the result is in the second word, after the response delay if func == FUNC_BACKPLANE { buf[1] } else { From f82f931dc2b8df2338fb8331ad27d667811e5c09 Mon Sep 17 00:00:00 2001 From: kbleeke Date: Tue, 21 Mar 2023 19:30:45 +0100 Subject: [PATCH 6/7] revert formatting changes in Cargo.toml --- examples/rpi-pico-w/Cargo.toml | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml index 17b4214d..4a531c88 100644 --- a/examples/rpi-pico-w/Cargo.toml +++ b/examples/rpi-pico-w/Cargo.toml @@ -6,30 +6,10 @@ edition = "2021" [dependencies] cyw43 = { path = "../../", features = ["defmt", "firmware-logs"] } -embassy-executor = { version = "0.1.0", features = [ - "defmt", - "integrated-timers", -] } -embassy-time = { version = "0.1.0", features = [ - "defmt", - "defmt-timestamp-uptime", -] } -embassy-rp = { version = "0.1.0", features = [ - "defmt", - "unstable-traits", - "nightly", - "unstable-pac", - "pio", - "time-driver", -] } -embassy-net = { version = "0.1.0", features = [ - "defmt", - "tcp", - "dhcpv4", - "medium-ethernet", - "unstable-traits", - "nightly", -] } +embassy-executor = { version = "0.1.0", features = ["defmt", "integrated-timers"] } +embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] } +embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio"] } +embassy-net = { version = "0.1.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "nightly"] } atomic-polyfill = "0.1.5" static_cell = "1.0" @@ -39,11 +19,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] } cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } cortex-m-rt = "0.7.0" -futures = { version = "0.3.17", default-features = false, features = [ - "async-await", - "cfg-target-has-atomic", - "unstable", -] } +futures = { version = "0.3.17", default-features = false, features = ["async-await", "cfg-target-has-atomic", "unstable"] } pio-proc = "0.2" pio = "0.2.1" From 359b1c7fdb246c125e0b835eb58283a8a9a6a946 Mon Sep 17 00:00:00 2001 From: kbleeke Date: Tue, 21 Mar 2023 19:39:41 +0100 Subject: [PATCH 7/7] replace inspect() with direct calls to trace!() after awaiting --- examples/rpi-pico-w/src/pio.rs | 4 ++-- src/bus.rs | 28 ++++++++++------------------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs index 896fd045..8017f4f4 100644 --- a/examples/rpi-pico-w/src/pio.rs +++ b/examples/rpi-pico-w/src/pio.rs @@ -155,13 +155,13 @@ where SM: PioStateMachine, DMA: Channel, { - async fn cmd_write(&mut self, write: & [u32]) { + async fn cmd_write(&mut self, write: &[u32]) { self.cs.set_low(); self.write(write).await; self.cs.set_high(); } - async fn cmd_read(&mut self, write: u32, read: & mut [u32]) { + async fn cmd_read(&mut self, write: u32, read: &mut [u32]) { self.cs.set_low(); self.cmd_read(write, read).await; self.cs.set_high(); diff --git a/src/bus.rs b/src/bus.rs index 262b9e0d..f77b890d 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -55,32 +55,24 @@ where {} self.write32_swapped(REG_BUS_TEST_RW, TEST_PATTERN).await; - let val = self - .read32_swapped(REG_BUS_TEST_RW) - .inspect(|v| defmt::trace!("{:#x}", v)) - .await; + let val = self.read32_swapped(REG_BUS_TEST_RW).await; + defmt::trace!("{:#x}", val); assert_eq!(val, TEST_PATTERN); - self.read32_swapped(REG_BUS_CTRL) - .inspect(|v| defmt::trace!("{:#010b}", (v & 0xff))) - .await; + let val = self.read32_swapped(REG_BUS_CTRL).await; + defmt::trace!("{:#010b}", (val & 0xff)); // 32-bit word length, little endian (which is the default endianess). self.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED).await; - self.read8(FUNC_BUS, REG_BUS_CTRL) - .inspect(|v| defmt::trace!("{:#b}", v)) - .await; + let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; + defmt::trace!("{:#b}", val); - let val = self - .read32(FUNC_BUS, REG_BUS_TEST_RO) - .inspect(|v| defmt::trace!("{:#x}", v)) - .await; + let val = self.read32(FUNC_BUS, REG_BUS_TEST_RO).await; + defmt::trace!("{:#x}", val); assert_eq!(val, FEEDBEAD); - let val = self - .read32(FUNC_BUS, REG_BUS_TEST_RW) - .inspect(|v| defmt::trace!("{:#x}", v)) - .await; + let val = self.read32(FUNC_BUS, REG_BUS_TEST_RW).await; + defmt::trace!("{:#x}", val); assert_eq!(val, TEST_PATTERN); }