From a2272dda08a2d1625eef0b79fcd80afc8a1e174a Mon Sep 17 00:00:00 2001 From: kbleeke Date: Thu, 2 Mar 2023 19:02:00 +0100 Subject: [PATCH 1/3] status and irq flags formatting with defmt --- src/consts.rs | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/src/consts.rs b/src/consts.rs index bee70660..140cb4b6 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,4 +1,5 @@ #![allow(unused)] + pub(crate) const FUNC_BUS: u32 = 0; pub(crate) const FUNC_BACKPLANE: u32 = 1; pub(crate) const FUNC_WLAN: u32 = 2; @@ -103,3 +104,149 @@ pub(crate) const WRITE: bool = true; pub(crate) const READ: bool = false; pub(crate) const INC_ADDR: bool = true; pub(crate) const FIXED_ADDR: bool = false; + +#[allow(dead_code)] +pub(crate) struct FormatStatus(pub u32); + +#[cfg(feature = "defmt")] +impl defmt::Format for FormatStatus { + fn format(&self, fmt: defmt::Formatter) { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + defmt::write!(fmt, " | {}", &stringify!($name)[7..]); + } + )* + }; + } + + implm!( + STATUS_DATA_NOT_AVAILABLE, + STATUS_UNDERFLOW, + STATUS_OVERFLOW, + STATUS_F2_INTR, + STATUS_F3_INTR, + STATUS_F2_RX_READY, + STATUS_F3_RX_READY, + STATUS_HOST_CMD_DATA_ERR, + STATUS_F2_PKT_AVAILABLE, + STATUS_F3_PKT_AVAILABLE + ); + } +} + +#[cfg(feature = "log")] +impl core::fmt::Debug for FormatStatus { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + core::write!(fmt, " | {}", &stringify!($name)[7..])?; + } + )* + }; + } + + implm!( + STATUS_DATA_NOT_AVAILABLE, + STATUS_UNDERFLOW, + STATUS_OVERFLOW, + STATUS_F2_INTR, + STATUS_F3_INTR, + STATUS_F2_RX_READY, + STATUS_F3_RX_READY, + STATUS_HOST_CMD_DATA_ERR, + STATUS_F2_PKT_AVAILABLE, + STATUS_F3_PKT_AVAILABLE + ); + Ok(()) + } +} + +#[cfg(feature = "log")] +impl core::fmt::Display for FormatStatus { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(self, f) + } +} + +#[allow(dead_code)] +pub(crate) struct FormatInterrupt(pub u16); + +#[cfg(feature = "defmt")] +impl defmt::Format for FormatInterrupt { + fn format(&self, fmt: defmt::Formatter) { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + defmt::write!(fmt, " | {}", &stringify!($name)[4..]); + } + )* + }; + } + + implm!( + IRQ_DATA_UNAVAILABLE, + IRQ_F2_F3_FIFO_RD_UNDERFLOW, + IRQ_F2_F3_FIFO_WR_OVERFLOW, + IRQ_COMMAND_ERROR, + IRQ_DATA_ERROR, + IRQ_F2_PACKET_AVAILABLE, + IRQ_F3_PACKET_AVAILABLE, + IRQ_F1_OVERFLOW, + IRQ_MISC_INTR0, + IRQ_MISC_INTR1, + IRQ_MISC_INTR2, + IRQ_MISC_INTR3, + IRQ_MISC_INTR4, + IRQ_F1_INTR, + IRQ_F2_INTR, + IRQ_F3_INTR + ); + } +} + +#[cfg(feature = "log")] +impl core::fmt::Debug for FormatInterrupt { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { + macro_rules! implm { + ($($name:ident),*) => { + $( + if self.0 & $name > 0 { + core::write!(fmt, " | {}", &stringify!($name)[7..])?; + } + )* + }; + } + + implm!( + IRQ_DATA_UNAVAILABLE, + IRQ_F2_F3_FIFO_RD_UNDERFLOW, + IRQ_F2_F3_FIFO_WR_OVERFLOW, + IRQ_COMMAND_ERROR, + IRQ_DATA_ERROR, + IRQ_F2_PACKET_AVAILABLE, + IRQ_F3_PACKET_AVAILABLE, + IRQ_F1_OVERFLOW, + IRQ_MISC_INTR0, + IRQ_MISC_INTR1, + IRQ_MISC_INTR2, + IRQ_MISC_INTR3, + IRQ_MISC_INTR4, + IRQ_F1_INTR, + IRQ_F2_INTR, + IRQ_F3_INTR + ); + Ok(()) + } +} + +#[cfg(feature = "log")] +impl core::fmt::Display for FormatInterrupt { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(self, f) + } +} From b58cc2aa239e4adba2c32462cc89133bb7d9f698 Mon Sep 17 00:00:00 2001 From: kbleeke Date: Thu, 2 Mar 2023 19:02:32 +0100 Subject: [PATCH 2/3] use irqs to wait for events --- examples/rpi-pico-w/src/main.rs | 6 ++ examples/rpi-pico-w/src/pio.rs | 17 ++++-- src/bus.rs | 14 ++++- src/consts.rs | 2 + src/ioctl.rs | 3 - src/runner.rs | 98 ++++++++++++++++++--------------- 6 files changed, 87 insertions(+), 53 deletions(-) diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index 43485137..97e2d6a6 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs @@ -227,4 +227,10 @@ impl cyw43::SpiBusCyw43 for MySpi { self.read(read).await; self.cs.set_high(); } + + async fn wait_for_event(&mut self) {} + + fn clear_event(&mut self) {} + + } diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs index 8017f4f4..6df22746 100644 --- a/examples/rpi-pico-w/src/pio.rs +++ b/examples/rpi-pico-w/src/pio.rs @@ -41,6 +41,9 @@ where "in pins, 1 side 1" "jmp y-- lp2 side 0" + "wait 1 pin 0 side 0" + "irq 0 side 0" + ".wrap" ); @@ -106,6 +109,7 @@ where } pub async fn write(&mut self, write: &[u32]) { + self.sm.set_enable(false); let write_bits = write.len() * 32 - 1; let read_bits = 31; @@ -124,11 +128,10 @@ where 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]) { + self.sm.set_enable(false); let write_bits = 31; let read_bits = read.len() * 32 - 1; @@ -144,8 +147,6 @@ where self.sm.dma_push(dma.reborrow(), slice::from_ref(&cmd)).await; self.sm.dma_pull(dma, read).await; - - self.sm.set_enable(false); } } @@ -166,4 +167,12 @@ where self.cmd_read(write, read).await; self.cs.set_high(); } + + async fn wait_for_event(&mut self) { + self.sm.wait_irq(0).await; + } + + fn clear_event(&mut self) { + self.sm.clear_irq(0); + } } diff --git a/src/bus.rs b/src/bus.rs index 7700a832..6ec5d0bd 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -19,6 +19,9 @@ pub trait SpiBusCyw43 { /// 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]); + + async fn wait_for_event(&mut self); + fn clear_event(&mut self); } pub(crate) struct Bus { @@ -63,7 +66,8 @@ where 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.write32_swapped(REG_BUS_CTRL, WORD_LENGTH_32 | HIGH_SPEED | INTERRUPT_HIGH | WAKE_UP) + .await; let val = self.read8(FUNC_BUS, REG_BUS_CTRL).await; trace!("{:#b}", val); @@ -297,6 +301,14 @@ where self.spi.cmd_write(&buf).await; } + + pub async fn wait_for_event(&mut self) { + self.spi.wait_for_event().await; + } + + pub fn clear_event(&mut self) { + self.spi.clear_event(); + } } fn swap16(x: u32) -> u32 { diff --git a/src/consts.rs b/src/consts.rs index 140cb4b6..70d6660e 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -14,6 +14,8 @@ pub(crate) const REG_BUS_TEST_RW: u32 = 0x18; pub(crate) const REG_BUS_RESP_DELAY: u32 = 0x1c; pub(crate) const WORD_LENGTH_32: u32 = 0x1; pub(crate) const HIGH_SPEED: u32 = 0x10; +pub(crate) const INTERRUPT_HIGH: u32 = 1 << 5; +pub(crate) const WAKE_UP: u32 = 1 << 7; // SPI_STATUS_REGISTER bits pub(crate) const STATUS_DATA_NOT_AVAILABLE: u32 = 0x00000001; diff --git a/src/ioctl.rs b/src/ioctl.rs index 6a746559..4a2eb252 100644 --- a/src/ioctl.rs +++ b/src/ioctl.rs @@ -75,7 +75,6 @@ impl IoctlState { pub async fn wait_pending(&self) -> PendingIoctl { let pending = poll_fn(|cx| { if let IoctlStateInner::Pending(pending) = self.state.get() { - warn!("found pending ioctl"); Poll::Ready(pending) } else { self.register_runner(cx.waker()); @@ -89,7 +88,6 @@ impl IoctlState { } pub async fn do_ioctl(&self, kind: IoctlType, cmd: u32, iface: u32, buf: &mut [u8]) -> usize { - warn!("doing ioctl"); self.state .set(IoctlStateInner::Pending(PendingIoctl { buf, kind, cmd, iface })); self.wake_runner(); @@ -98,7 +96,6 @@ impl IoctlState { pub fn ioctl_done(&self, response: &[u8]) { if let IoctlStateInner::Sent { buf } = self.state.get() { - warn!("ioctl complete"); // TODO fix this (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); diff --git a/src/runner.rs b/src/runner.rs index 4abccf48..a1de0770 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -122,7 +122,11 @@ where while self.bus.read8(FUNC_BACKPLANE, REG_BACKPLANE_CHIP_CLOCK_CSR).await & 0x80 == 0 {} // "Set up the interrupt mask and enable interrupts" - self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; + // self.bus.bp_write32(CHIP.sdiod_core_base_address + 0x24, 0xF0).await; + + self.bus + .write16(FUNC_BUS, REG_BUS_INTERRUPT_ENABLE, IRQ_F2_PACKET_AVAILABLE) + .await; // "Lower F2 Watermark to avoid DMA Hang in F2 when SD Clock is stopped." // Sounds scary... @@ -227,22 +231,22 @@ where #[cfg(feature = "firmware-logs")] self.log_read().await; - let ev = || async { - // TODO use IRQs - yield_now().await; - }; - if self.has_credit() { let ioctl = self.ioctl_state.wait_pending(); let tx = self.ch.tx_buf(); + let ev = self.bus.wait_for_event(); - match select3(ioctl, tx, ev()).await { - Either3::First(PendingIoctl { buf, kind, cmd, iface }) => { - warn!("ioctl"); - self.send_ioctl(kind, cmd, iface, unsafe { &*buf }).await; + match select3(ioctl, tx, ev).await { + Either3::First(PendingIoctl { + buf: iobuf, + kind, + cmd, + iface, + }) => { + self.send_ioctl(kind, cmd, iface, unsafe { &*iobuf }).await; + self.check_status(&mut buf).await; } Either3::Second(packet) => { - warn!("packet"); trace!("tx pkt {:02x}", Bytes(&packet[..packet.len().min(48)])); let mut buf = [0; 512]; @@ -284,50 +288,54 @@ where self.bus.wlan_write(&buf[..(total_len / 4)]).await; self.ch.tx_done(); + self.check_status(&mut buf).await; } Either3::Third(()) => { - // Receive stuff - let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; - - if irq & IRQ_F2_PACKET_AVAILABLE != 0 { - let mut status = 0xFFFF_FFFF; - while status == 0xFFFF_FFFF { - status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await; - } - - if status & STATUS_F2_PKT_AVAILABLE != 0 { - let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; - self.bus.wlan_read(&mut buf, len).await; - trace!("rx {:02x}", Bytes(&slice8_mut(&mut buf)[..(len as usize).min(48)])); - self.rx(&slice8_mut(&mut buf)[..len as usize]); - } - } + self.handle_irq(&mut buf).await; } } } else { warn!("TX stalled"); - ev().await; - - // Receive stuff - let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; - - if irq & IRQ_F2_PACKET_AVAILABLE != 0 { - let mut status = 0xFFFF_FFFF; - while status == 0xFFFF_FFFF { - status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await; - } - - if status & STATUS_F2_PKT_AVAILABLE != 0 { - let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; - self.bus.wlan_read(&mut buf, len).await; - trace!("rx {:02x}", Bytes(&slice8_mut(&mut buf)[..(len as usize).min(48)])); - self.rx(&slice8_mut(&mut buf)[..len as usize]); - } - } + self.bus.wait_for_event().await; + self.handle_irq(&mut buf).await; } } } + /// Wait for IRQ on F2 packet available + async fn handle_irq(&mut self, buf: &mut [u32; 512]) { + self.bus.clear_event(); + // Receive stuff + let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; + trace!("irq{}", FormatInterrupt(irq)); + + if irq & IRQ_F2_PACKET_AVAILABLE != 0 { + self.check_status(buf).await; + } + } + + /// Handle F2 events while status register is set + async fn check_status(&mut self, buf: &mut [u32; 512]) { + loop { + let mut status = 0xFFFF_FFFF; + while status == 0xFFFF_FFFF { + status = self.bus.read32(FUNC_BUS, REG_BUS_STATUS).await; + } + trace!("check status{}", FormatStatus(status)); + + if status & STATUS_F2_PKT_AVAILABLE != 0 { + let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT; + self.bus.wlan_read(buf, len).await; + trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)])); + self.rx(&slice8_mut(buf)[..len as usize]); + } else { + break; + } + + yield_now().await; + } + } + fn rx(&mut self, packet: &[u8]) { if packet.len() < SdpcmHeader::SIZE { warn!("packet too short, len={}", packet.len()); From 8926397f4592f22a5ed54f772a979578ca36628f Mon Sep 17 00:00:00 2001 From: kbleeke Date: Mon, 27 Mar 2023 14:37:39 +0200 Subject: [PATCH 3/3] address irq nits --- examples/rpi-pico-w/src/main.rs | 6 ------ examples/rpi-pico-w/src/pio.rs | 3 --- src/bus.rs | 12 ++++++------ src/runner.rs | 4 ---- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/examples/rpi-pico-w/src/main.rs b/examples/rpi-pico-w/src/main.rs index 97e2d6a6..43485137 100644 --- a/examples/rpi-pico-w/src/main.rs +++ b/examples/rpi-pico-w/src/main.rs @@ -227,10 +227,4 @@ impl cyw43::SpiBusCyw43 for MySpi { self.read(read).await; self.cs.set_high(); } - - async fn wait_for_event(&mut self) {} - - fn clear_event(&mut self) {} - - } diff --git a/examples/rpi-pico-w/src/pio.rs b/examples/rpi-pico-w/src/pio.rs index 6df22746..1cefb173 100644 --- a/examples/rpi-pico-w/src/pio.rs +++ b/examples/rpi-pico-w/src/pio.rs @@ -170,9 +170,6 @@ where async fn wait_for_event(&mut self) { self.sm.wait_irq(0).await; - } - - fn clear_event(&mut self) { self.sm.clear_irq(0); } } diff --git a/src/bus.rs b/src/bus.rs index 6ec5d0bd..d2a249f9 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,5 +1,6 @@ use core::slice; +use embassy_futures::yield_now; use embassy_time::{Duration, Timer}; use embedded_hal_1::digital::OutputPin; use futures::FutureExt; @@ -20,8 +21,11 @@ pub trait SpiBusCyw43 { /// 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]); - async fn wait_for_event(&mut self); - fn clear_event(&mut self); + /// Wait for events from the Device. A typical implementation would wait for the IRQ pin to be high. + /// The default implementation always reports ready, resulting in active polling of the device. + async fn wait_for_event(&mut self) { + yield_now().await; + } } pub(crate) struct Bus { @@ -305,10 +309,6 @@ where pub async fn wait_for_event(&mut self) { self.spi.wait_for_event().await; } - - pub fn clear_event(&mut self) { - self.spi.clear_event(); - } } fn swap16(x: u32) -> u32 { diff --git a/src/runner.rs b/src/runner.rs index a1de0770..abfac3ae 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1,7 +1,6 @@ use core::slice; use embassy_futures::select::{select3, Either3}; -use embassy_futures::yield_now; use embassy_net_driver_channel as ch; use embassy_sync::pubsub::PubSubBehavior; use embassy_time::{block_for, Duration, Timer}; @@ -304,7 +303,6 @@ where /// Wait for IRQ on F2 packet available async fn handle_irq(&mut self, buf: &mut [u32; 512]) { - self.bus.clear_event(); // Receive stuff let irq = self.bus.read16(FUNC_BUS, REG_BUS_INTERRUPT).await; trace!("irq{}", FormatInterrupt(irq)); @@ -331,8 +329,6 @@ where } else { break; } - - yield_now().await; } }