From 20ea35fc9639487eaa21f1dcee6c32d8a66a0fbb Mon Sep 17 00:00:00 2001 From: kbleeke Date: Mon, 27 Mar 2023 18:04:48 +0200 Subject: Move pio driver to separate crate --- .vscode/settings.json | 1 + Cargo.toml | 6 ++ cyw43-pio/Cargo.toml | 13 +++ cyw43-pio/src/lib.rs | 185 ++++++++++++++++++++++++++++++++++++++++ examples/rpi-pico-w/Cargo.toml | 3 +- examples/rpi-pico-w/src/main.rs | 5 +- examples/rpi-pico-w/src/pio.rs | 179 -------------------------------------- 7 files changed, 207 insertions(+), 185 deletions(-) create mode 100644 cyw43-pio/Cargo.toml create mode 100644 cyw43-pio/src/lib.rs delete mode 100644 examples/rpi-pico-w/src/pio.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index dd479929e..344307695 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,7 @@ "rust-analyzer.check.noDefaultFeatures": true, "rust-analyzer.linkedProjects": [ "examples/rpi-pico-w/Cargo.toml", + "cyw43-pio/Cargo.toml", ], "rust-analyzer.server.extraEnv": { "WIFI_NETWORK": "foo", diff --git a/Cargo.toml b/Cargo.toml index a307a6cc3..04a47a3a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,3 +32,9 @@ embassy-time = { git = "https://github.com/embassy-rs/embassy", rev = "e3f8020c3 embassy-futures = { git = "https://github.com/embassy-rs/embassy", rev = "e3f8020c3bdf726dfa451b5b190f27191507a18f" } embassy-sync = { git = "https://github.com/embassy-rs/embassy", rev = "e3f8020c3bdf726dfa451b5b190f27191507a18f" } embassy-net-driver-channel = { git = "https://github.com/embassy-rs/embassy", rev = "e3f8020c3bdf726dfa451b5b190f27191507a18f" } +embassy-rp = { git = "https://github.com/embassy-rs/embassy", rev = "e3f8020c3bdf726dfa451b5b190f27191507a18f" } + +[workspace] +members = ["cyw43-pio"] +default-members = ["cyw43-pio", "."] +exclude = ["examples"] \ No newline at end of file diff --git a/cyw43-pio/Cargo.toml b/cyw43-pio/Cargo.toml new file mode 100644 index 000000000..2fc6b7591 --- /dev/null +++ b/cyw43-pio/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cyw43-pio" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cyw43 = { path = "../" } +embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver", "pio"] } +pio-proc = "0.2" +pio = "0.2.1" +defmt = "0.3" \ No newline at end of file diff --git a/cyw43-pio/src/lib.rs b/cyw43-pio/src/lib.rs new file mode 100644 index 000000000..2159796cd --- /dev/null +++ b/cyw43-pio/src/lib.rs @@ -0,0 +1,185 @@ +#![no_std] +#![allow(incomplete_features)] +#![feature(async_fn_in_trait)] + +use core::slice; + +use cyw43::SpiBusCyw43; +use embassy_rp::dma::Channel; +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 pio::Wrap; +use pio_proc::pio_asm; + +pub struct PioSpi { + cs: Output<'static, CS>, + sm: SM, + dma: DMA, + wrap_target: u8, +} + +impl PioSpi +where + SM: PioStateMachine, + DMA: Channel, + CS: Pin, +{ + pub fn new(mut sm: SM, cs: Output<'static, CS>, 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 1" + "jmp y-- lp2 side 0" + + "wait 1 pin 0 side 0" + "irq 0 side 0" + + ".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); + 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); + + // 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, + sm, + dma, + wrap_target: target, + } + } + + pub async fn write(&mut self, write: &[u32]) -> u32 { + self.sm.set_enable(false); + 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.reborrow(), slice::from_mut(&mut status)).await; + status + } + + pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 { + self.sm.set_enable(false); + let write_bits = 31; + let read_bits = read.len() * 32 + 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.reborrow(), read).await; + + let mut status = 0; + self.sm.dma_pull(dma.reborrow(), slice::from_mut(&mut status)).await; + status + } +} + +impl SpiBusCyw43 for PioSpi +where + CS: Pin, + SM: PioStateMachine, + DMA: Channel, +{ + async fn cmd_write(&mut self, write: &[u32]) -> u32 { + self.cs.set_low(); + let status = self.write(write).await; + self.cs.set_high(); + status + } + + async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32 { + self.cs.set_low(); + let status = self.cmd_read(write, read).await; + self.cs.set_high(); + status + } + + async fn wait_for_event(&mut self) { + self.sm.wait_irq(0).await; + self.sm.clear_irq(0); + } +} diff --git a/examples/rpi-pico-w/Cargo.toml b/examples/rpi-pico-w/Cargo.toml index 4a531c88c..41ee8a3c4 100644 --- a/examples/rpi-pico-w/Cargo.toml +++ b/examples/rpi-pico-w/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] cyw43 = { path = "../../", features = ["defmt", "firmware-logs"] } +cyw43-pio = { path = "../../cyw43-pio" } 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"] } @@ -20,8 +21,6 @@ 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"] } -pio-proc = "0.2" -pio = "0.2.1" 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 e3c59223b..4b1623be7 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs @@ -4,11 +4,10 @@ #![feature(async_fn_in_trait)] #![allow(incomplete_features)] -mod pio; - use core::slice; use core::str::from_utf8; +use cyw43_pio::PioSpi; use defmt::*; use embassy_executor::Spawner; use embassy_net::tcp::TcpSocket; @@ -20,8 +19,6 @@ use embedded_io::asynch::Write; use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -use crate::pio::PioSpi; - macro_rules! singleton { ($val:expr) => {{ type T = impl Sized; diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs deleted file mode 100644 index 846113060..000000000 --- a/examples/rpi-pico-w/src/pio.rs +++ /dev/null @@ -1,179 +0,0 @@ -use core::slice; - -use cyw43::SpiBusCyw43; -use embassy_rp::dma::Channel; -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 pio::Wrap; -use pio_proc::pio_asm; - -pub struct PioSpi { - cs: Output<'static, CS>, - sm: SM, - dma: DMA, - wrap_target: u8, -} - -impl PioSpi -where - SM: PioStateMachine, - DMA: Channel, - CS: Pin, -{ - pub fn new(mut sm: SM, cs: Output<'static, CS>, 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 1" - "jmp y-- lp2 side 0" - - "wait 1 pin 0 side 0" - "irq 0 side 0" - - ".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); - 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); - - // 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, - sm, - dma, - wrap_target: target, - } - } - - pub async fn write(&mut self, write: &[u32]) -> u32 { - self.sm.set_enable(false); - 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 status = self.sm.wait_pull().await; - status - } - - pub async fn cmd_read(&mut self, cmd: u32, read: &mut [u32]) -> u32 { - self.sm.set_enable(false); - let write_bits = 31; - let read_bits = read.len() * 32 + 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; - - let status = self.sm.wait_pull().await; - status - } -} - -impl SpiBusCyw43 for PioSpi -where - CS: Pin, - SM: PioStateMachine, - DMA: Channel, -{ - async fn cmd_write(&mut self, write: &[u32]) -> u32 { - self.cs.set_low(); - let status = self.write(write).await; - self.cs.set_high(); - status - } - - async fn cmd_read(&mut self, write: u32, read: &mut [u32]) -> u32 { - self.cs.set_low(); - let status = self.cmd_read(write, read).await; - self.cs.set_high(); - status - } - - async fn wait_for_event(&mut self) { - self.sm.wait_irq(0).await; - self.sm.clear_irq(0); - } -} -- cgit