Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
298a880
WIP: factoring out wiznet SPI inteface
KingCol13 Mar 16, 2026
5b03474
WIP: QSPI PIO program
KingCol13 Mar 16, 2026
5a9aeff
WIP: W6300 QSPI example
KingCol13 Mar 16, 2026
ee92a0d
Remove extra qspi methods
KingCol13 Mar 19, 2026
3734bbe
WIP: QSPI traits
KingCol13 Mar 26, 2026
345fd5c
WIP: more work on QSPI traits
KingCol13 Mar 28, 2026
87bb727
Make QSPI traits async
KingCol13 Mar 28, 2026
6c29b55
Format code
KingCol13 Mar 28, 2026
d129f30
Reuse SPI error for QSPI
KingCol13 Mar 29, 2026
56c2d85
Add an adapter to use QSPI for Wiznet devices
KingCol13 Mar 29, 2026
5bd45f2
WIP: implementing PIO QSPI
KingCol13 Apr 3, 2026
861d654
Increase W6300 example QSPI frequency to 25MHz
KingCol13 Apr 5, 2026
8e56e5c
Format code
KingCol13 Apr 6, 2026
1288e69
Update embassy-net-wiznet README
KingCol13 Apr 6, 2026
021bdc9
Format again
KingCol13 Apr 6, 2026
1329166
Increase Wiznet W6300 buffer size to 32KiB
KingCol13 Apr 7, 2026
980d1e3
W6300: combine address and dummy phases
KingCol13 Apr 7, 2026
63dd0d8
Remove incorrect blocking PIO QSPI functions
KingCol13 Apr 8, 2026
9bbbf50
Correctly flush PIO QSPI operations with IRQ
KingCol13 Apr 9, 2026
115bbad
Combine PIO QSPI program and use exec_jmp
KingCol13 Apr 25, 2026
21e895a
Use dummy DMA rather than IRQ for PIO QSPI sync
KingCol13 Apr 25, 2026
ff498d2
Revert "Use dummy DMA rather than IRQ for PIO QSPI sync"
KingCol13 Apr 25, 2026
6dab875
PIO QSPI force push to FIFO for num_nibbles/bits
KingCol13 Apr 26, 2026
974c812
Revert "PIO QSPI force push to FIFO for num_nibbles/bits"
KingCol13 Apr 26, 2026
b62a360
PIO QSPI debloat async
KingCol13 Apr 26, 2026
aa227c5
Revert "PIO QSPI debloat async"
KingCol13 Apr 26, 2026
fc1cdab
PIO QSPI pre-encode jmp instructions
KingCol13 Apr 26, 2026
eec9e52
PIO QSPI remove nothing block
KingCol13 Apr 26, 2026
53fb307
PIO QSPI make the IRQ indicate readiness
KingCol13 Apr 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions embassy-embedded-hal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = [
] }
embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
embedded-hal-async = { version = "1.0" }
embedded-hal-bus = { version = "0.3.0" }
embedded-storage = "0.3.1"
embedded-storage-async = { version = "0.4.1" }
nb = "1.0.0"
Expand Down
1 change: 1 addition & 0 deletions embassy-embedded-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

pub mod adapter;
pub mod flash;
pub mod qspi;
pub mod shared_bus;

/// Set the configuration of a peripheral driver.
Expand Down
38 changes: 38 additions & 0 deletions embassy-embedded-hal/src/qspi/device_error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//! Module for QSPI device error
use core::fmt::{self, Debug, Display, Formatter};
use embedded_hal_async::spi::{Error, ErrorKind};

/// Error type for [`ExclusiveDevice`] operations.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum DeviceError<BUS, CS> {
/// An inner QSPI bus operation failed.
Qspi(BUS),
/// Asserting or deasserting CS failed.
Cs(CS),
}

impl<BUS: Display, CS: Display> Display for DeviceError<BUS, CS> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::Qspi(bus) => write!(f, "SPI bus error: {}", bus),
Self::Cs(cs) => write!(f, "SPI CS error: {}", cs),
}
}
}

impl<BUS: Debug + Display, CS: Debug + Display> core::error::Error for DeviceError<BUS, CS> {}

impl<BUS, CS> Error for DeviceError<BUS, CS>
where
BUS: Error + Debug,
CS: Debug,
{
#[inline]
fn kind(&self) -> ErrorKind {
match self {
Self::Qspi(e) => e.kind(),
Self::Cs(_) => ErrorKind::ChipSelectFault,
}
}
}
135 changes: 135 additions & 0 deletions embassy-embedded-hal/src/qspi/exclusive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//! QSPI bus sharing mechanisms.

use super::traits::{Operation, QspiBus, QspiDevice};
use embedded_hal_1::digital::OutputPin;
use embedded_hal_async::delay::DelayNs;
use embedded_hal_async::spi::ErrorType;

use super::device_error::DeviceError;

/// Dummy [`DelayNs`](embedded_hal::delay::DelayNs) implementation that panics on use.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct NoDelay;

/// [`QspiDevice`] implementation with exclusive access to the bus (not shared).
///
/// This is the most straightforward way of obtaining an [`QspiDevice`] from an [`QspiBus`],
/// ideal for when no sharing is required (only one SPI device is present on the bus).
pub struct ExclusiveDevice<BUS, CS, D> {
bus: BUS,
cs: CS,
delay: D,
}

impl<BUS, CS, D> ExclusiveDevice<BUS, CS, D> {
/// Create a new [`ExclusiveDevice`].
///
/// This sets the `cs` pin high, and returns an error if that fails. It is recommended
/// to set the pin high the moment it's configured as an output, to avoid glitches.
#[inline]
pub fn new(bus: BUS, mut cs: CS, delay: D) -> Result<Self, CS::Error>
where
CS: OutputPin,
{
cs.set_high()?;
Ok(Self { bus, cs, delay })
}

/// Returns a reference to the underlying bus object.
#[inline]
pub fn bus(&self) -> &BUS {
&self.bus
}

/// Returns a mutable reference to the underlying bus object.
#[inline]
pub fn bus_mut(&mut self) -> &mut BUS {
&mut self.bus
}
}

impl<BUS, CS> ExclusiveDevice<BUS, CS, NoDelay> {
/// Create a new [`ExclusiveDevice`] without support for in-transaction delays.
///
/// This sets the `cs` pin high, and returns an error if that fails. It is recommended
/// to set the pin high the moment it's configured as an output, to avoid glitches.
///
/// **Warning**: The returned instance *technically* doesn't comply with the `QspiDevice`
/// contract, which mandates delay support. It is relatively rare for drivers to use
/// in-transaction delays, so you might still want to use this method because it's more practical.
///
/// Note that a future version of the driver might start using delays, causing your
/// code to panic. This wouldn't be considered a breaking change from the driver side, because
/// drivers are allowed to assume `QspiDevice` implementations comply with the contract.
/// If you feel this risk outweighs the convenience of having `cargo` automatically upgrade
/// the driver crate, you might want to pin the driver's version.
///
/// # Panics
///
/// The returned device will panic if you try to execute a transaction
/// that contains any operations of type [`Operation::DelayNs`].
#[inline]
pub fn new_no_delay(bus: BUS, mut cs: CS) -> Result<Self, CS::Error>
where
CS: OutputPin,
{
cs.set_high()?;
Ok(Self {
bus,
cs,
delay: NoDelay,
})
}
}

impl<BUS, CS, D> ErrorType for ExclusiveDevice<BUS, CS, D>
where
BUS: ErrorType,
CS: OutputPin,
{
type Error = DeviceError<BUS::Error, CS::Error>;
}

impl<Word: Copy + 'static, BUS, CS, D> QspiDevice<Word> for ExclusiveDevice<BUS, CS, D>
where
BUS: QspiBus<Word>,
CS: OutputPin,
D: DelayNs,
{
#[inline]
async fn transaction(&mut self, operations: &mut [Operation<'_, Word>]) -> Result<(), Self::Error> {
self.cs.set_low().map_err(DeviceError::Cs)?;

let op_res = 'ops: {
for op in operations {
let res = match op {
Operation::Read(buf) => self.bus.read(buf).await,
Operation::Write(buf) => self.bus.write(buf).await,
Operation::WriteSingleLine(buf) => self.bus.write_single_line(buf).await,
Operation::DelayNs(ns) => match self.bus.flush().await {
Err(e) => Err(e),
Ok(()) => {
self.delay.delay_ns(*ns).await;
Ok(())
}
},
};
if let Err(e) = res {
break 'ops Err(e);
}
}
Ok(())
};

// On failure, it's important to still flush and deassert CS.
let flush_res = self.bus.flush().await;
let cs_res = self.cs.set_high();

op_res.map_err(DeviceError::Qspi)?;
flush_res.map_err(DeviceError::Qspi)?;
cs_res.map_err(DeviceError::Cs)?;

Ok(())
}
}
4 changes: 4 additions & 0 deletions embassy-embedded-hal/src/qspi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Utilities for Quad SPI
pub mod device_error;
pub mod exclusive;
pub mod traits;
Loading