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]
|
||||
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" }
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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<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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
|
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 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::*;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue