Add pio transport to pico w example
This commit is contained in:
parent
d57fe0de86
commit
0ff606dfc1
6 changed files with 263 additions and 34 deletions
|
@ -5,11 +5,31 @@ edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cyw43 = { path = "../../", features = ["defmt", "firmware-logs"]}
|
cyw43 = { path = "../../", features = ["defmt", "firmware-logs"] }
|
||||||
embassy-executor = { version = "0.1.0", features = ["defmt", "integrated-timers"] }
|
embassy-executor = { version = "0.1.0", features = [
|
||||||
embassy-time = { version = "0.1.0", features = ["defmt", "defmt-timestamp-uptime"] }
|
"defmt",
|
||||||
embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac", "time-driver"] }
|
"integrated-timers",
|
||||||
embassy-net = { version = "0.1.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "unstable-traits", "nightly"] }
|
] }
|
||||||
|
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"
|
atomic-polyfill = "0.1.5"
|
||||||
static_cell = "1.0"
|
static_cell = "1.0"
|
||||||
|
|
||||||
|
@ -17,9 +37,15 @@ defmt = "0.3"
|
||||||
defmt-rtt = "0.3"
|
defmt-rtt = "0.3"
|
||||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
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"
|
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-1 = { package = "embedded-hal", version = "1.0.0-alpha.9" }
|
||||||
embedded-hal-async = { version = "0.2.0-alpha.0" }
|
embedded-hal-async = { version = "0.2.0-alpha.0" }
|
||||||
|
|
|
@ -14,23 +14,23 @@ use std::io::Write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// // Put `memory.x` in our output directory and ensure it's
|
// Put `memory.x` in our output directory and ensure it's
|
||||||
// // on the linker search path.
|
// on the linker search path.
|
||||||
// let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
// File::create(out.join("memory.x"))
|
File::create(out.join("memory.x"))
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .write_all(include_bytes!("memory.x"))
|
.write_all(include_bytes!("memory.x"))
|
||||||
// .unwrap();
|
.unwrap();
|
||||||
// println!("cargo:rustc-link-search={}", out.display());
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
|
||||||
// // By default, Cargo will re-run a build script whenever
|
// By default, Cargo will re-run a build script whenever
|
||||||
// // any file in the project changes. By specifying `memory.x`
|
// any file in the project changes. By specifying `memory.x`
|
||||||
// // here, we ensure the build script is only re-run when
|
// here, we ensure the build script is only re-run when
|
||||||
// // `memory.x` is changed.
|
// `memory.x` is changed.
|
||||||
// println!("cargo:rerun-if-changed=memory.x");
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
|
|
||||||
// println!("cargo:rustc-link-arg-bins=--nmagic");
|
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||||
// println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||||
// println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
|
println!("cargo:rustc-link-arg-bins=-Tlink-rp.x");
|
||||||
// println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,21 +4,25 @@
|
||||||
#![feature(async_fn_in_trait)]
|
#![feature(async_fn_in_trait)]
|
||||||
#![allow(incomplete_features)]
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
mod pio;
|
||||||
|
|
||||||
use core::convert::Infallible;
|
use core::convert::Infallible;
|
||||||
|
use core::str::from_utf8;
|
||||||
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use embassy_net::tcp::TcpSocket;
|
use embassy_net::tcp::TcpSocket;
|
||||||
use embassy_net::{Config, Stack, StackResources};
|
use embassy_net::{Config, Stack, StackResources};
|
||||||
use embassy_rp::gpio::{Flex, Level, Output};
|
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_1::spi::ErrorType;
|
||||||
use embedded_hal_async::spi::{ExclusiveDevice, SpiBusFlush, SpiBusRead, SpiBusWrite};
|
use embedded_hal_async::spi::{ExclusiveDevice, SpiBusFlush, SpiBusRead, SpiBusWrite};
|
||||||
use embedded_io::asynch::Write;
|
use embedded_io::asynch::Write;
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
use core::str::from_utf8;
|
use crate::pio::PioSpi;
|
||||||
|
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
($val:expr) => {{
|
($val:expr) => {{
|
||||||
|
@ -30,7 +34,11 @@ macro_rules! singleton {
|
||||||
|
|
||||||
#[embassy_executor::task]
|
#[embassy_executor::task]
|
||||||
async fn wifi_task(
|
async fn wifi_task(
|
||||||
runner: cyw43::Runner<'static, Output<'static, PIN_23>, ExclusiveDevice<MySpi, Output<'static, PIN_25>>>,
|
runner: cyw43::Runner<
|
||||||
|
'static,
|
||||||
|
Output<'static, PIN_23>,
|
||||||
|
ExclusiveDevice<PioSpi<PioStateMachineInstance<Pio0, Sm0>, DMA_CH0>, Output<'static, PIN_25>>,
|
||||||
|
>,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
runner.run().await
|
runner.run().await
|
||||||
}
|
}
|
||||||
|
@ -59,12 +67,15 @@ async fn main(spawner: Spawner) {
|
||||||
|
|
||||||
let pwr = Output::new(p.PIN_23, Level::Low);
|
let pwr = Output::new(p.PIN_23, Level::Low);
|
||||||
let cs = Output::new(p.PIN_25, Level::High);
|
let cs = Output::new(p.PIN_25, Level::High);
|
||||||
let clk = Output::new(p.PIN_29, Level::Low);
|
// let clk = Output::new(p.PIN_29, Level::Low);
|
||||||
let mut dio = Flex::new(p.PIN_24);
|
// let mut dio = Flex::new(p.PIN_24);
|
||||||
dio.set_low();
|
// dio.set_low();
|
||||||
dio.set_as_output();
|
// 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 spi = ExclusiveDevice::new(bus, cs);
|
||||||
|
|
||||||
let state = singleton!(cyw43::State::new());
|
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);
|
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
|
||||||
socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
|
socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
|
||||||
|
|
||||||
|
control.gpio_set(0, false).await;
|
||||||
info!("Listening on TCP:1234...");
|
info!("Listening on TCP:1234...");
|
||||||
if let Err(e) = socket.accept(1234).await {
|
if let Err(e) = socket.accept(1234).await {
|
||||||
warn!("accept error: {:?}", e);
|
warn!("accept error: {:?}", e);
|
||||||
|
@ -117,6 +129,7 @@ async fn main(spawner: Spawner) {
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("Received connection from {:?}", socket.remote_endpoint());
|
info!("Received connection from {:?}", socket.remote_endpoint());
|
||||||
|
control.gpio_set(0, true).await;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let n = match socket.read(&mut buf).await {
|
let n = match socket.read(&mut buf).await {
|
||||||
|
|
190
examples/rpi-pico-w/src/pio.rs
Normal file
190
examples/rpi-pico-w/src/pio.rs
Normal file
|
@ -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<SM, DMA> {
|
||||||
|
// cs: Output<'static, AnyPin>,
|
||||||
|
sm: SM,
|
||||||
|
dma: DMA,
|
||||||
|
wrap_target: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SM, DMA> PioSpi<SM, DMA>
|
||||||
|
where
|
||||||
|
SM: PioStateMachine,
|
||||||
|
DMA: Channel,
|
||||||
|
{
|
||||||
|
pub fn new<DIO, CLK>(
|
||||||
|
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<SM, DMA> ErrorType for PioSpi<SM, DMA>
|
||||||
|
where
|
||||||
|
SM: PioStateMachine,
|
||||||
|
{
|
||||||
|
type Error = PioError;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SM, DMA> SpiBusFlush for PioSpi<SM, DMA>
|
||||||
|
where
|
||||||
|
SM: PioStateMachine,
|
||||||
|
{
|
||||||
|
async fn flush(&mut self) -> Result<(), Self::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SM, DMA> SpiBusCyw43<u32> for PioSpi<SM, DMA>
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ use core::slice;
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
use embedded_hal_1::spi::ErrorType;
|
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::*;
|
use crate::consts::*;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ use embassy_futures::yield_now;
|
||||||
use embassy_net_driver_channel as ch;
|
use embassy_net_driver_channel as ch;
|
||||||
use embassy_time::{block_for, Duration, Timer};
|
use embassy_time::{block_for, Duration, Timer};
|
||||||
use embedded_hal_1::digital::OutputPin;
|
use embedded_hal_1::digital::OutputPin;
|
||||||
use embedded_hal_async::spi::{SpiBusRead, SpiBusWrite, SpiDevice};
|
use embedded_hal_async::spi::SpiDevice;
|
||||||
|
|
||||||
use crate::bus::Bus;
|
use crate::bus::Bus;
|
||||||
pub use crate::bus::SpiBusCyw43;
|
pub use crate::bus::SpiBusCyw43;
|
||||||
|
|
Loading…
Reference in a new issue