Merge remote-tracking branch 'origin/main' into nrf-pdm
This commit is contained in:
commit
42de1c3a06
8 changed files with 489 additions and 361 deletions
41
.gitattributes
vendored
Normal file
41
.gitattributes
vendored
Normal 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
17
.github/ci/crlf.sh
vendored
Executable 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
1
.github/ci/doc.sh
vendored
|
@ -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
|
||||||
|
|
|
@ -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"]
|
|
@ -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 {
|
||||||
|
|
|
@ -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?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {}
|
||||||
};
|
};
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue