Merge remote-tracking branch 'origin/main' into nrf-pdm

This commit is contained in:
Quentin Smith 2023-07-18 17:13:00 -04:00
commit 42de1c3a06
8 changed files with 489 additions and 361 deletions

41
.gitattributes vendored Normal file
View file

@ -0,0 +1,41 @@
* text=auto
*.adoc text
*.html text
*.in text
*.json text
*.md text
*.proto text
*.py text
*.rs text
*.service text
*.sh text
*.toml text
*.txt text
*.x text
*.yml text
*.raw binary
*.bin binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary
*.ez binary
*.bz2 binary
*.swp binary

17
.github/ci/crlf.sh vendored Executable file
View file

@ -0,0 +1,17 @@
#!/bin/bash
## on push branch~=gh-readonly-queue/main/.*
## on pull_request
set -euo pipefail
FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true))
if [ -z "$FILES_WITH_CRLF" ]; then
echo -e "No files with CRLF endings found."
exit 0
else
NR_FILES=$(echo "$FILES_WITH_CRLF" | wc -l)
echo -e "ERROR: Found ${NR_FILES} files with CRLF endings."
echo "$FILES_WITH_CRLF"
exit "$NR_FILES"
fi

1
.github/ci/doc.sh vendored
View file

@ -37,6 +37,7 @@ docserver-builder -i ./embassy-usb-logger -o webroot/crates/embassy-usb-logger/g
docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
docserver-builder -i ./embassy-net-w5500 -o webroot/crates/embassy-net-w5500/git.zup docserver-builder -i ./embassy-net-w5500 -o webroot/crates/embassy-net-w5500/git.zup
docserver-builder -i ./embassy-net-esp-hosted -o webroot/crates/embassy-net-esp-hosted/git.zup
docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static docserver-builder -i ./embassy-stm32-wpan -o webroot/crates/embassy-stm32-wpan/git.zup --output-static webroot/static
export KUBECONFIG=/ci/secrets/kubeconfig.yml export KUBECONFIG=/ci/secrets/kubeconfig.yml

View file

@ -18,3 +18,9 @@ embedded-hal-async = { version = "=0.2.0-alpha.2" }
noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] } noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] }
#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } #noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] }
heapless = "0.7.16" heapless = "0.7.16"
[package.metadata.embassy_docs]
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-esp-hosted-v$VERSION/embassy-net-esp-hosted/src/"
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-esp-hosted/src/"
target = "thumbv7em-none-eabi"
features = ["defmt"]

View file

@ -479,30 +479,78 @@ impl<D: Driver + 'static> Stack<D> {
} }
#[cfg(feature = "igmp")] #[cfg(feature = "igmp")]
impl<D: Driver + smoltcp::phy::Device + 'static> Stack<D> { impl<D: Driver + 'static> Stack<D> {
/// Join a multicast group. /// Join a multicast group.
pub fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> pub async fn join_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
where
T: Into<IpAddress>,
{
let addr = addr.into();
poll_fn(move |cx| self.poll_join_multicast_group(addr, cx)).await
}
/// Join a multicast group.
///
/// When the send queue is full, this method will return `Poll::Pending`
/// and register the current task to be notified when the queue has space available.
pub fn poll_join_multicast_group<T>(&self, addr: T, cx: &mut Context<'_>) -> Poll<Result<bool, MulticastError>>
where where
T: Into<IpAddress>, T: Into<IpAddress>,
{ {
let addr = addr.into(); let addr = addr.into();
self.with_mut(|s, i| { self.with_mut(|s, i| {
s.iface let mut smoldev = DriverAdapter {
.join_multicast_group(&mut i.device, addr, instant_to_smoltcp(Instant::now())) cx: Some(cx),
inner: &mut i.device,
};
match s
.iface
.join_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now()))
{
Ok(announce_sent) => Poll::Ready(Ok(announce_sent)),
Err(MulticastError::Exhausted) => Poll::Pending,
Err(other) => Poll::Ready(Err(other)),
}
}) })
} }
/// Leave a multicast group. /// Leave a multicast group.
pub fn leave_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError> pub async fn leave_multicast_group<T>(&self, addr: T) -> Result<bool, MulticastError>
where
T: Into<IpAddress>,
{
let addr = addr.into();
poll_fn(move |cx| self.poll_leave_multicast_group(addr, cx)).await
}
/// Leave a multicast group.
///
/// When the send queue is full, this method will return `Poll::Pending`
/// and register the current task to be notified when the queue has space available.
pub fn poll_leave_multicast_group<T>(&self, addr: T, cx: &mut Context<'_>) -> Poll<Result<bool, MulticastError>>
where where
T: Into<IpAddress>, T: Into<IpAddress>,
{ {
let addr = addr.into(); let addr = addr.into();
self.with_mut(|s, i| { self.with_mut(|s, i| {
s.iface let mut smoldev = DriverAdapter {
.leave_multicast_group(&mut i.device, addr, instant_to_smoltcp(Instant::now())) cx: Some(cx),
inner: &mut i.device,
};
match s
.iface
.leave_multicast_group(&mut smoldev, addr, instant_to_smoltcp(Instant::now()))
{
Ok(leave_sent) => Poll::Ready(Ok(leave_sent)),
Err(MulticastError::Exhausted) => Poll::Pending,
Err(other) => Poll::Ready(Err(other)),
}
}) })
} }
@ -531,11 +579,14 @@ impl<D: Driver + 'static> Inner<D> {
debug!(" IP address: {}", config.address); debug!(" IP address: {}", config.address);
s.iface.update_ip_addrs(|addrs| { s.iface.update_ip_addrs(|addrs| {
if addrs.is_empty() { if let Some((index, _)) = addrs
addrs.push(IpCidr::Ipv4(config.address)).unwrap(); .iter()
} else { .enumerate()
addrs[0] = IpCidr::Ipv4(config.address); .find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_)))
{
addrs.remove(index);
} }
addrs.push(IpCidr::Ipv4(config.address)).unwrap();
}); });
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
@ -570,11 +621,14 @@ impl<D: Driver + 'static> Inner<D> {
debug!(" IP address: {}", config.address); debug!(" IP address: {}", config.address);
s.iface.update_ip_addrs(|addrs| { s.iface.update_ip_addrs(|addrs| {
if addrs.is_empty() { if let Some((index, _)) = addrs
addrs.push(IpCidr::Ipv6(config.address)).unwrap(); .iter()
} else { .enumerate()
addrs[0] = IpCidr::Ipv6(config.address); .find(|(_, &addr)| matches!(addr, IpCidr::Ipv6(_)))
{
addrs.remove(index);
} }
addrs.push(IpCidr::Ipv6(config.address)).unwrap();
}); });
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
@ -642,13 +696,21 @@ impl<D: Driver + 'static> Inner<D> {
socket.set_retry_config(config.retry_config); socket.set_retry_config(config.retry_config);
} }
#[allow(unused)] // used only with dhcp #[cfg(feature = "dhcpv4")]
fn unapply_config(&mut self, s: &mut SocketStack) { fn unapply_config_v4(&mut self, s: &mut SocketStack) {
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
let medium = self.device.capabilities().medium; let medium = self.device.capabilities().medium;
debug!("Lost IP configuration"); debug!("Lost IP configuration");
s.iface.update_ip_addrs(|ip_addrs| ip_addrs.clear()); s.iface.update_ip_addrs(|ip_addrs| {
#[cfg(feature = "proto-ipv4")]
if let Some((index, _)) = ip_addrs
.iter()
.enumerate()
.find(|(_, &addr)| matches!(addr, IpCidr::Ipv4(_)))
{
ip_addrs.remove(index);
}
});
#[cfg(feature = "medium-ethernet")] #[cfg(feature = "medium-ethernet")]
if medium == Medium::Ethernet { if medium == Medium::Ethernet {
#[cfg(feature = "proto-ipv4")] #[cfg(feature = "proto-ipv4")]
@ -695,7 +757,7 @@ impl<D: Driver + 'static> Inner<D> {
if self.link_up { if self.link_up {
match socket.poll() { match socket.poll() {
None => {} None => {}
Some(dhcpv4::Event::Deconfigured) => self.unapply_config(s), Some(dhcpv4::Event::Deconfigured) => self.unapply_config_v4(s),
Some(dhcpv4::Event::Configured(config)) => { Some(dhcpv4::Event::Configured(config)) => {
let config = StaticConfigV4 { let config = StaticConfigV4 {
address: config.address, address: config.address,
@ -707,7 +769,7 @@ impl<D: Driver + 'static> Inner<D> {
} }
} else if old_link_up { } else if old_link_up {
socket.reset(); socket.reset();
self.unapply_config(s); self.unapply_config_v4(s);
} }
} }
//if old_link_up || self.link_up { //if old_link_up || self.link_up {

View file

@ -716,6 +716,9 @@ mod nightly {
async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> {
let addr: u16 = address.into(); let addr: u16 = address.into();
if operations.len() > 0 {
Self::setup(addr)?;
}
let mut iterator = operations.iter_mut(); let mut iterator = operations.iter_mut();
while let Some(op) = iterator.next() { while let Some(op) = iterator.next() {
@ -723,11 +726,9 @@ mod nightly {
match op { match op {
Operation::Read(buffer) => { Operation::Read(buffer) => {
Self::setup(addr)?;
self.read_async_internal(buffer, false, last).await?; self.read_async_internal(buffer, false, last).await?;
} }
Operation::Write(buffer) => { Operation::Write(buffer) => {
Self::setup(addr)?;
self.write_async_internal(buffer.into_iter().cloned(), last).await?; self.write_async_internal(buffer.into_iter().cloned(), last).await?;
} }
} }

View file

@ -45,20 +45,19 @@ use self::phy_consts::*;
pub struct GenericSMI { pub struct GenericSMI {
#[cfg(feature = "time")] #[cfg(feature = "time")]
poll_interval: Duration, poll_interval: Duration,
#[cfg(not(feature = "time"))]
_private: (),
} }
impl GenericSMI { impl GenericSMI {
#[cfg(feature = "time")]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
#[cfg(feature = "time")]
poll_interval: Duration::from_millis(500), poll_interval: Duration::from_millis(500),
#[cfg(not(feature = "time"))]
_private: (),
} }
} }
#[cfg(not(feature = "time"))]
pub fn new() -> Self {
Self {}
}
} }
unsafe impl PHY for GenericSMI { unsafe impl PHY for GenericSMI {
@ -102,6 +101,7 @@ unsafe impl PHY for GenericSMI {
/// Public functions for the PHY /// Public functions for the PHY
impl GenericSMI { impl GenericSMI {
#[cfg(feature = "time")]
pub fn set_poll_interval(&mut self, poll_interval: Duration) { pub fn set_poll_interval(&mut self, poll_interval: Duration) {
self.poll_interval = poll_interval self.poll_interval = poll_interval
} }

View file

@ -1,332 +1,332 @@
#![macro_use] #![macro_use]
pub mod enums; pub mod enums;
use embassy_hal_common::{into_ref, PeripheralRef}; use embassy_hal_common::{into_ref, PeripheralRef};
use enums::*; use enums::*;
use crate::dma::Transfer; use crate::dma::Transfer;
use crate::gpio::sealed::AFType; use crate::gpio::sealed::AFType;
use crate::gpio::AnyPin; use crate::gpio::AnyPin;
use crate::pac::quadspi::Quadspi as Regs; use crate::pac::quadspi::Quadspi as Regs;
use crate::rcc::RccPeripheral; use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral}; use crate::{peripherals, Peripheral};
pub struct TransferConfig { pub struct TransferConfig {
/// Instraction width (IMODE) /// Instraction width (IMODE)
pub iwidth: QspiWidth, pub iwidth: QspiWidth,
/// Address width (ADMODE) /// Address width (ADMODE)
pub awidth: QspiWidth, pub awidth: QspiWidth,
/// Data width (DMODE) /// Data width (DMODE)
pub dwidth: QspiWidth, pub dwidth: QspiWidth,
/// Instruction Id /// Instruction Id
pub instruction: u8, pub instruction: u8,
/// Flash memory address /// Flash memory address
pub address: Option<u32>, pub address: Option<u32>,
/// Number of dummy cycles (DCYC) /// Number of dummy cycles (DCYC)
pub dummy: DummyCycles, pub dummy: DummyCycles,
/// Length of data /// Length of data
pub data_len: Option<usize>, pub data_len: Option<usize>,
} }
impl Default for TransferConfig { impl Default for TransferConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
iwidth: QspiWidth::NONE, iwidth: QspiWidth::NONE,
awidth: QspiWidth::NONE, awidth: QspiWidth::NONE,
dwidth: QspiWidth::NONE, dwidth: QspiWidth::NONE,
instruction: 0, instruction: 0,
address: None, address: None,
dummy: DummyCycles::_0, dummy: DummyCycles::_0,
data_len: None, data_len: None,
} }
} }
} }
pub struct Config { pub struct Config {
/// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen. /// Flash memory size representend as 2^[0-32], as reasonable minimum 1KiB(9) was chosen.
/// If you need other value the whose predefined use `Other` variant. /// If you need other value the whose predefined use `Other` variant.
pub memory_size: MemorySize, pub memory_size: MemorySize,
/// Address size (8/16/24/32-bit) /// Address size (8/16/24/32-bit)
pub address_size: AddressSize, pub address_size: AddressSize,
/// Scalar factor for generating CLK [0-255] /// Scalar factor for generating CLK [0-255]
pub prescaler: u8, pub prescaler: u8,
/// Number of bytes to trigger FIFO threshold flag. /// Number of bytes to trigger FIFO threshold flag.
pub fifo_threshold: FIFOThresholdLevel, pub fifo_threshold: FIFOThresholdLevel,
/// Minimum number of cycles that chip select must be high between issued commands /// Minimum number of cycles that chip select must be high between issued commands
pub cs_high_time: ChipSelectHightTime, pub cs_high_time: ChipSelectHightTime,
} }
impl Default for Config { impl Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
memory_size: MemorySize::Other(0), memory_size: MemorySize::Other(0),
address_size: AddressSize::_24bit, address_size: AddressSize::_24bit,
prescaler: 128, prescaler: 128,
fifo_threshold: FIFOThresholdLevel::_17Bytes, fifo_threshold: FIFOThresholdLevel::_17Bytes,
cs_high_time: ChipSelectHightTime::_5Cycle, cs_high_time: ChipSelectHightTime::_5Cycle,
} }
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
pub struct Qspi<'d, T: Instance, Dma> { pub struct Qspi<'d, T: Instance, Dma> {
_peri: PeripheralRef<'d, T>, _peri: PeripheralRef<'d, T>,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
d0: Option<PeripheralRef<'d, AnyPin>>, d0: Option<PeripheralRef<'d, AnyPin>>,
d1: Option<PeripheralRef<'d, AnyPin>>, d1: Option<PeripheralRef<'d, AnyPin>>,
d2: Option<PeripheralRef<'d, AnyPin>>, d2: Option<PeripheralRef<'d, AnyPin>>,
d3: Option<PeripheralRef<'d, AnyPin>>, d3: Option<PeripheralRef<'d, AnyPin>>,
nss: Option<PeripheralRef<'d, AnyPin>>, nss: Option<PeripheralRef<'d, AnyPin>>,
dma: PeripheralRef<'d, Dma>, dma: PeripheralRef<'d, Dma>,
config: Config, config: Config,
} }
impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> { impl<'d, T: Instance, Dma> Qspi<'d, T, Dma> {
pub fn new( pub fn new(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: impl Peripheral<P = impl D0Pin<T>> + 'd, d0: impl Peripheral<P = impl D0Pin<T>> + 'd,
d1: impl Peripheral<P = impl D1Pin<T>> + 'd, d1: impl Peripheral<P = impl D1Pin<T>> + 'd,
d2: impl Peripheral<P = impl D2Pin<T>> + 'd, d2: impl Peripheral<P = impl D2Pin<T>> + 'd,
d3: impl Peripheral<P = impl D3Pin<T>> + 'd, d3: impl Peripheral<P = impl D3Pin<T>> + 'd,
sck: impl Peripheral<P = impl SckPin<T>> + 'd, sck: impl Peripheral<P = impl SckPin<T>> + 'd,
nss: impl Peripheral<P = impl NSSPin<T>> + 'd, nss: impl Peripheral<P = impl NSSPin<T>> + 'd,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(peri, d0, d1, d2, d3, sck, nss); into_ref!(peri, d0, d1, d2, d3, sck, nss);
sck.set_as_af(sck.af_num(), AFType::OutputPushPull); sck.set_as_af(sck.af_num(), AFType::OutputPushPull);
sck.set_speed(crate::gpio::Speed::VeryHigh); sck.set_speed(crate::gpio::Speed::VeryHigh);
nss.set_as_af(nss.af_num(), AFType::OutputPushPull); nss.set_as_af(nss.af_num(), AFType::OutputPushPull);
nss.set_speed(crate::gpio::Speed::VeryHigh); nss.set_speed(crate::gpio::Speed::VeryHigh);
d0.set_as_af(d0.af_num(), AFType::OutputPushPull); d0.set_as_af(d0.af_num(), AFType::OutputPushPull);
d0.set_speed(crate::gpio::Speed::VeryHigh); d0.set_speed(crate::gpio::Speed::VeryHigh);
d1.set_as_af(d1.af_num(), AFType::OutputPushPull); d1.set_as_af(d1.af_num(), AFType::OutputPushPull);
d1.set_speed(crate::gpio::Speed::VeryHigh); d1.set_speed(crate::gpio::Speed::VeryHigh);
d2.set_as_af(d2.af_num(), AFType::OutputPushPull); d2.set_as_af(d2.af_num(), AFType::OutputPushPull);
d2.set_speed(crate::gpio::Speed::VeryHigh); d2.set_speed(crate::gpio::Speed::VeryHigh);
d3.set_as_af(d3.af_num(), AFType::OutputPushPull); d3.set_as_af(d3.af_num(), AFType::OutputPushPull);
d3.set_speed(crate::gpio::Speed::VeryHigh); d3.set_speed(crate::gpio::Speed::VeryHigh);
Self::new_inner( Self::new_inner(
peri, peri,
Some(d0.map_into()), Some(d0.map_into()),
Some(d1.map_into()), Some(d1.map_into()),
Some(d2.map_into()), Some(d2.map_into()),
Some(d3.map_into()), Some(d3.map_into()),
Some(sck.map_into()), Some(sck.map_into()),
Some(nss.map_into()), Some(nss.map_into()),
dma, dma,
config, config,
) )
} }
fn new_inner( fn new_inner(
peri: impl Peripheral<P = T> + 'd, peri: impl Peripheral<P = T> + 'd,
d0: Option<PeripheralRef<'d, AnyPin>>, d0: Option<PeripheralRef<'d, AnyPin>>,
d1: Option<PeripheralRef<'d, AnyPin>>, d1: Option<PeripheralRef<'d, AnyPin>>,
d2: Option<PeripheralRef<'d, AnyPin>>, d2: Option<PeripheralRef<'d, AnyPin>>,
d3: Option<PeripheralRef<'d, AnyPin>>, d3: Option<PeripheralRef<'d, AnyPin>>,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
nss: Option<PeripheralRef<'d, AnyPin>>, nss: Option<PeripheralRef<'d, AnyPin>>,
dma: impl Peripheral<P = Dma> + 'd, dma: impl Peripheral<P = Dma> + 'd,
config: Config, config: Config,
) -> Self { ) -> Self {
into_ref!(peri, dma); into_ref!(peri, dma);
T::enable(); T::enable();
T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into())); T::REGS.cr().write(|w| w.set_fthres(config.fifo_threshold.into()));
while T::REGS.sr().read().busy() {} while T::REGS.sr().read().busy() {}
T::REGS.cr().write(|w| { T::REGS.cr().write(|w| {
w.set_prescaler(config.prescaler); w.set_prescaler(config.prescaler);
w.set_en(true); w.set_en(true);
}); });
T::REGS.dcr().write(|w| { T::REGS.dcr().write(|w| {
w.set_fsize(config.memory_size.into()); w.set_fsize(config.memory_size.into());
w.set_csht(config.cs_high_time.into()); w.set_csht(config.cs_high_time.into());
w.set_ckmode(false); w.set_ckmode(false);
}); });
Self { Self {
_peri: peri, _peri: peri,
sck, sck,
d0, d0,
d1, d1,
d2, d2,
d3, d3,
nss, nss,
dma, dma,
config, config,
} }
} }
pub fn command(&mut self, transaction: TransferConfig) { pub fn command(&mut self, transaction: TransferConfig) {
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) { pub fn blocking_read(&mut self, buf: &mut [u8], transaction: TransferConfig) {
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
let current_ar = T::REGS.ar().read().address(); let current_ar = T::REGS.ar().read().address();
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into()); v.set_fmode(QspiMode::IndirectRead.into());
}); });
T::REGS.ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(current_ar); v.set_address(current_ar);
}); });
for idx in 0..len { for idx in 0..len {
while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {} while !T::REGS.sr().read().tcf() && !T::REGS.sr().read().ftf() {}
buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() }; buf[idx] = unsafe { (T::REGS.dr().as_ptr() as *mut u8).read_volatile() };
} }
} }
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) { pub fn blocking_write(&mut self, buf: &[u8], transaction: TransferConfig) {
T::REGS.cr().modify(|v| v.set_dmaen(false)); T::REGS.cr().modify(|v| v.set_dmaen(false));
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into()); v.set_fmode(QspiMode::IndirectWrite.into());
}); });
for idx in 0..len { for idx in 0..len {
while !T::REGS.sr().read().ftf() {} while !T::REGS.sr().read().ftf() {}
unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) }; unsafe { (T::REGS.dr().as_ptr() as *mut u8).write_volatile(buf[idx]) };
} }
} }
while !T::REGS.sr().read().tcf() {} while !T::REGS.sr().read().tcf() {}
T::REGS.fcr().modify(|v| v.set_ctcf(true)); T::REGS.fcr().modify(|v| v.set_ctcf(true));
} }
pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig) pub fn blocking_read_dma(&mut self, buf: &mut [u8], transaction: TransferConfig)
where where
Dma: QuadDma<T>, Dma: QuadDma<T>,
{ {
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectRead.into()); v.set_fmode(QspiMode::IndirectRead.into());
}); });
let current_ar = T::REGS.ar().read().address(); let current_ar = T::REGS.ar().read().address();
T::REGS.ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(current_ar); v.set_address(current_ar);
}); });
let request = self.dma.request(); let request = self.dma.request();
let transfer = unsafe { let transfer = unsafe {
Transfer::new_read( Transfer::new_read(
&mut self.dma, &mut self.dma,
request, request,
T::REGS.dr().as_ptr() as *mut u8, T::REGS.dr().as_ptr() as *mut u8,
buf, buf,
Default::default(), Default::default(),
) )
}; };
T::REGS.cr().modify(|v| v.set_dmaen(true)); T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
} }
pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig) pub fn blocking_write_dma(&mut self, buf: &[u8], transaction: TransferConfig)
where where
Dma: QuadDma<T>, Dma: QuadDma<T>,
{ {
self.setup_transaction(QspiMode::IndirectWrite, &transaction); self.setup_transaction(QspiMode::IndirectWrite, &transaction);
T::REGS.ccr().modify(|v| { T::REGS.ccr().modify(|v| {
v.set_fmode(QspiMode::IndirectWrite.into()); v.set_fmode(QspiMode::IndirectWrite.into());
}); });
let request = self.dma.request(); let request = self.dma.request();
let transfer = unsafe { let transfer = unsafe {
Transfer::new_write( Transfer::new_write(
&mut self.dma, &mut self.dma,
request, request,
buf, buf,
T::REGS.dr().as_ptr() as *mut u8, T::REGS.dr().as_ptr() as *mut u8,
Default::default(), Default::default(),
) )
}; };
T::REGS.cr().modify(|v| v.set_dmaen(true)); T::REGS.cr().modify(|v| v.set_dmaen(true));
transfer.blocking_wait(); transfer.blocking_wait();
} }
fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) { fn setup_transaction(&mut self, fmode: QspiMode, transaction: &TransferConfig) {
T::REGS.fcr().modify(|v| { T::REGS.fcr().modify(|v| {
v.set_csmf(true); v.set_csmf(true);
v.set_ctcf(true); v.set_ctcf(true);
v.set_ctef(true); v.set_ctef(true);
v.set_ctof(true); v.set_ctof(true);
}); });
while T::REGS.sr().read().busy() {} while T::REGS.sr().read().busy() {}
if let Some(len) = transaction.data_len { if let Some(len) = transaction.data_len {
T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1)); T::REGS.dlr().write(|v| v.set_dl(len as u32 - 1));
} }
T::REGS.ccr().write(|v| { T::REGS.ccr().write(|v| {
v.set_fmode(fmode.into()); v.set_fmode(fmode.into());
v.set_imode(transaction.iwidth.into()); v.set_imode(transaction.iwidth.into());
v.set_instruction(transaction.instruction); v.set_instruction(transaction.instruction);
v.set_admode(transaction.awidth.into()); v.set_admode(transaction.awidth.into());
v.set_adsize(self.config.address_size.into()); v.set_adsize(self.config.address_size.into());
v.set_dmode(transaction.dwidth.into()); v.set_dmode(transaction.dwidth.into());
v.set_abmode(QspiWidth::NONE.into()); v.set_abmode(QspiWidth::NONE.into());
v.set_dcyc(transaction.dummy.into()); v.set_dcyc(transaction.dummy.into());
}); });
if let Some(addr) = transaction.address { if let Some(addr) = transaction.address {
T::REGS.ar().write(|v| { T::REGS.ar().write(|v| {
v.set_address(addr); v.set_address(addr);
}); });
} }
} }
} }
pub(crate) mod sealed { pub(crate) mod sealed {
use super::*; use super::*;
pub trait Instance { pub trait Instance {
const REGS: Regs; const REGS: Regs;
} }
} }
pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {} pub trait Instance: Peripheral<P = Self> + sealed::Instance + RccPeripheral {}
pin_trait!(SckPin, Instance); pin_trait!(SckPin, Instance);
pin_trait!(D0Pin, Instance); pin_trait!(D0Pin, Instance);
pin_trait!(D1Pin, Instance); pin_trait!(D1Pin, Instance);
pin_trait!(D2Pin, Instance); pin_trait!(D2Pin, Instance);
pin_trait!(D3Pin, Instance); pin_trait!(D3Pin, Instance);
pin_trait!(NSSPin, Instance); pin_trait!(NSSPin, Instance);
dma_trait!(QuadDma, Instance); dma_trait!(QuadDma, Instance);
foreach_peripheral!( foreach_peripheral!(
(quadspi, $inst:ident) => { (quadspi, $inst:ident) => {
impl sealed::Instance for peripherals::$inst { impl sealed::Instance for peripherals::$inst {
const REGS: Regs = crate::pac::$inst; const REGS: Regs = crate::pac::$inst;
} }
impl Instance for peripherals::$inst {} impl Instance for peripherals::$inst {}
}; };
); );