From f5d084552d9f44d24f020269cc605de0fb4d1041 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Sat, 17 Jun 2023 11:48:21 +0200
Subject: [PATCH 01/74] implement mwe of a DMA write() method for DAC
---
embassy-stm32/build.rs | 2 +
embassy-stm32/src/{dac.rs => dac/mod.rs} | 76 +++++++++++++++++++++---
2 files changed, 71 insertions(+), 7 deletions(-)
rename embassy-stm32/src/{dac.rs => dac/mod.rs} (76%)
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index 9e597f187..e2bd01d7b 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -699,6 +699,8 @@ fn main() {
// SDMMCv1 uses the same channel for both directions, so just implement for RX
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
+ (("dac", "CH1"), quote!(crate::dac::Dma)),
+ (("dac", "CH2"), quote!(crate::dac::Dma)),
]
.into();
diff --git a/embassy-stm32/src/dac.rs b/embassy-stm32/src/dac/mod.rs
similarity index 76%
rename from embassy-stm32/src/dac.rs
rename to embassy-stm32/src/dac/mod.rs
index 60e856c78..348d8bccd 100644
--- a/embassy-stm32/src/dac.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -2,6 +2,7 @@
use embassy_hal_common::{into_ref, PeripheralRef};
+use crate::dma::{slice_ptr_parts, word, Transfer};
use crate::pac::dac;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
@@ -97,39 +98,58 @@ pub enum Value {
Bit12(u16, Alignment),
}
-pub struct Dac<'d, T: Instance> {
+pub struct Dac<'d, T: Instance, Tx> {
channels: u8,
+ txdma: PeripheralRef<'d, Tx>,
_peri: PeripheralRef<'d, T>,
}
-impl<'d, T: Instance> Dac<'d, T> {
- pub fn new_1ch(peri: impl Peripheral
+ 'd, _ch1: impl Peripheral
> + 'd) -> Self {
+impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
+ pub fn new_1ch(
+ peri: impl Peripheral
+ 'd,
+ txdma: impl Peripheral
+ 'd,
+ _ch1: impl Peripheral
> + 'd,
+ ) -> Self {
into_ref!(peri);
- Self::new_inner(peri, 1)
+ Self::new_inner(peri, 1, txdma)
}
pub fn new_2ch(
peri: impl Peripheral
+ 'd,
+ txdma: impl Peripheral
+ 'd,
_ch1: impl Peripheral
> + 'd,
_ch2: impl Peripheral
> + 'd,
) -> Self {
into_ref!(peri);
- Self::new_inner(peri, 2)
+ Self::new_inner(peri, 2, txdma)
}
- fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self {
+ fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral
+ 'd) -> Self {
+ into_ref!(txdma);
T::enable();
T::reset();
unsafe {
+ T::regs().mcr().modify(|reg| {
+ for ch in 0..channels {
+ reg.set_mode(ch as usize, 0);
+ reg.set_mode(ch as usize, 0);
+ }
+ });
+
T::regs().cr().modify(|reg| {
for ch in 0..channels {
reg.set_en(ch as usize, true);
+ reg.set_ten(ch as usize, true);
}
});
}
- Self { channels, _peri: peri }
+ Self {
+ channels,
+ txdma,
+ _peri: peri,
+ }
}
/// Check the channel is configured
@@ -215,6 +235,47 @@ impl<'d, T: Instance> Dac<'d, T> {
}
Ok(())
}
+
+ /// TODO: Allow an array of Value instead of only u16, right-aligned
+ pub async fn write(&mut self, data: &[u16]) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ // TODO: Make this a parameter or get it from the struct or so...
+ const CHANNEL: usize = 0;
+
+ //debug!("Starting DAC");
+ unsafe {
+ T::regs().cr().modify(|w| {
+ w.set_en(CHANNEL, true);
+ w.set_dmaen(CHANNEL, true);
+ });
+ }
+
+ let tx_request = self.txdma.request();
+
+ // Use the 12 bit right-aligned register for now. TODO: distinguish values
+ let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16;
+
+ let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
+
+ //debug!("Awaiting tx_f");
+
+ tx_f.await;
+
+ // finish dma
+ unsafe {
+ // TODO: Do we need to check any status registers here?
+
+ T::regs().cr().modify(|w| {
+ // Disable the dac peripheral
+ //w.set_en(CHANNEL, false);
+ // Disable the DMA. TODO: Is this necessary?
+ //w.set_dmaen(CHANNEL, false);
+ });
+ }
+ Ok(())
+ }
}
pub(crate) mod sealed {
@@ -224,6 +285,7 @@ pub(crate) mod sealed {
}
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
+dma_trait!(Dma, Instance);
pub trait DacPin: crate::gpio::Pin + 'static {}
From 78a2ca8a0e5af3fe2c76a6cd025b74ea4322f6cf Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Sat, 17 Jun 2023 11:51:57 +0200
Subject: [PATCH 02/74] remove unnecessary use, disable DAC and DMA after
transfer
---
embassy-stm32/src/dac/mod.rs | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 348d8bccd..7b81ec1f2 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -2,7 +2,7 @@
use embassy_hal_common::{into_ref, PeripheralRef};
-use crate::dma::{slice_ptr_parts, word, Transfer};
+use crate::dma::Transfer;
use crate::pac::dac;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
@@ -269,9 +269,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
T::regs().cr().modify(|w| {
// Disable the dac peripheral
- //w.set_en(CHANNEL, false);
+ w.set_en(CHANNEL, false);
// Disable the DMA. TODO: Is this necessary?
- //w.set_dmaen(CHANNEL, false);
+ w.set_dmaen(CHANNEL, false);
});
}
Ok(())
From f8ee33abb9943d6fe57c126eeecb36db9935c4ba Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Sun, 18 Jun 2023 18:51:36 +0200
Subject: [PATCH 03/74] add half transfer interrupt and circular dma
---
embassy-stm32/src/dac/mod.rs | 17 ++++++++++++++---
embassy-stm32/src/dma/bdma.rs | 26 ++++++++++++++++++++++----
2 files changed, 36 insertions(+), 7 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 7b81ec1f2..525d45d72 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -2,7 +2,7 @@
use embassy_hal_common::{into_ref, PeripheralRef};
-use crate::dma::Transfer;
+use crate::dma::{Transfer, TransferOptions};
use crate::pac::dac;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
@@ -237,7 +237,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
}
/// TODO: Allow an array of Value instead of only u16, right-aligned
- pub async fn write(&mut self, data: &[u16]) -> Result<(), Error>
+ pub async fn write(&mut self, data: &[u16], circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
@@ -257,7 +257,18 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
// Use the 12 bit right-aligned register for now. TODO: distinguish values
let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16;
- let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) };
+ let tx_f = unsafe {
+ Transfer::new_write(
+ &mut self.txdma,
+ tx_request,
+ data,
+ tx_dst,
+ TransferOptions {
+ circular,
+ halt_transfer_ir: false,
+ },
+ )
+ };
//debug!("Awaiting tx_f");
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index c0a503e25..ca18047e7 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -1,6 +1,7 @@
#![macro_use]
use core::future::Future;
+use core::option;
use core::pin::Pin;
use core::sync::atomic::{fence, Ordering};
use core::task::{Context, Poll, Waker};
@@ -21,11 +22,17 @@ use crate::pac::bdma::{regs, vals};
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
-pub struct TransferOptions {}
+pub struct TransferOptions {
+ pub circular: bool,
+ pub halt_transfer_ir: bool,
+}
impl Default for TransferOptions {
fn default() -> Self {
- Self {}
+ Self {
+ circular: false,
+ halt_transfer_ir: false,
+ }
}
}
@@ -253,7 +260,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
mem_len: usize,
incr_mem: bool,
data_size: WordSize,
- _options: TransferOptions,
+ options: TransferOptions,
) -> Self {
let ch = channel.regs().ch(channel.num());
@@ -284,6 +291,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
w.set_dir(dir.into());
w.set_teie(true);
w.set_tcie(true);
+ w.set_htie(options.halt_transfer_ir);
+ if options.circular {
+ w.set_circ(vals::Circ::ENABLED);
+ debug!("Setting circular mode");
+ } else {
+ w.set_circ(vals::Circ::DISABLED);
+ }
+ w.set_pl(vals::Pl::VERYHIGH);
w.set_en(true);
});
@@ -314,8 +329,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
let en = unsafe { ch.cr().read() }.en();
+ let circular = unsafe { ch.cr().read() }.circ() == vals::Circ::ENABLED;
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
- en && !tcif
+ en && (circular || !tcif)
}
/// Gets the total remaining transfers for the channel
@@ -482,6 +498,8 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> {
let ch = self.channel.regs().ch(self.channel.num());
// Disable the channel. Keep the IEs enabled so the irqs still fire.
+ // If the channel is enabled and transfer is not completed, we need to perform
+ // two separate write access to the CR register to disable the channel.
unsafe {
ch.cr().write(|w| {
w.set_teie(true);
From e0747e937f06ed280594e17c97d19784410b6e85 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Mon, 19 Jun 2023 11:15:09 +0200
Subject: [PATCH 04/74] remove unsafe for circular dma reg access
---
embassy-stm32/src/dma/bdma.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index be4571440..3d315e20b 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -325,7 +325,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
pub fn is_running(&mut self) -> bool {
let ch = self.channel.regs().ch(self.channel.num());
let en = ch.cr().read().en();
- let circular = unsafe { ch.cr().read() }.circ() == vals::Circ::ENABLED;
+ let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
en && (circular || !tcif)
}
From fe7b72948ab5d3682f23e305f3eb7186cc308b1b Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Mon, 19 Jun 2023 13:42:25 +0200
Subject: [PATCH 05/74] add ValueArray type and respective write functions
---
embassy-stm32/src/dac/mod.rs | 206 +++++++++++++++++++++--------------
1 file changed, 124 insertions(+), 82 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 525d45d72..4384a7c34 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -98,6 +98,14 @@ pub enum Value {
Bit12(u16, Alignment),
}
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum ValueArray<'a> {
+ Bit8(&'a [u8]),
+ Bit12Left(&'a [u16]),
+ Bit12Right(&'a [u16]),
+}
+
pub struct Dac<'d, T: Instance, Tx> {
channels: u8,
txdma: PeripheralRef<'d, Tx>,
@@ -129,21 +137,19 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
T::enable();
T::reset();
- unsafe {
- T::regs().mcr().modify(|reg| {
- for ch in 0..channels {
- reg.set_mode(ch as usize, 0);
- reg.set_mode(ch as usize, 0);
- }
- });
+ T::regs().mcr().modify(|reg| {
+ for ch in 0..channels {
+ reg.set_mode(ch as usize, 0);
+ reg.set_mode(ch as usize, 0);
+ }
+ });
- T::regs().cr().modify(|reg| {
- for ch in 0..channels {
- reg.set_en(ch as usize, true);
- reg.set_ten(ch as usize, true);
- }
- });
- }
+ T::regs().cr().modify(|reg| {
+ for ch in 0..channels {
+ reg.set_en(ch as usize, true);
+ reg.set_ten(ch as usize, true);
+ }
+ });
Self {
channels,
@@ -161,13 +167,12 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
}
}
+ /// Set the enable register of the given channel
fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
self.check_channel_exists(ch)?;
- unsafe {
- T::regs().cr().modify(|reg| {
- reg.set_en(ch.index(), on);
- })
- }
+ T::regs().cr().modify(|reg| {
+ reg.set_en(ch.index(), on);
+ });
Ok(())
}
@@ -179,112 +184,149 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
self.set_channel_enable(ch, false)
}
+ /// Performs all register accesses necessary to select a new trigger for CH1
pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch1)?;
unwrap!(self.disable_channel(Channel::Ch1));
- unsafe {
- T::regs().cr().modify(|reg| {
- reg.set_tsel1(trigger.tsel());
- })
- }
+ T::regs().cr().modify(|reg| {
+ reg.set_tsel1(trigger.tsel());
+ });
Ok(())
}
+ /// Performs all register accesses necessary to select a new trigger for CH2
pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch2)?;
unwrap!(self.disable_channel(Channel::Ch2));
- unsafe {
- T::regs().cr().modify(|reg| {
- reg.set_tsel2(trigger.tsel());
- })
- }
+ T::regs().cr().modify(|reg| {
+ reg.set_tsel2(trigger.tsel());
+ });
Ok(())
}
+ /// Perform a software trigger on a given channel
pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
self.check_channel_exists(ch)?;
- unsafe {
- T::regs().swtrigr().write(|reg| {
- reg.set_swtrig(ch.index(), true);
- });
- }
+ T::regs().swtrigr().write(|reg| {
+ reg.set_swtrig(ch.index(), true);
+ });
Ok(())
}
+ /// Perform a software trigger on all channels
pub fn trigger_all(&mut self) {
- unsafe {
- T::regs().swtrigr().write(|reg| {
- reg.set_swtrig(Channel::Ch1.index(), true);
- reg.set_swtrig(Channel::Ch2.index(), true);
- })
- }
+ T::regs().swtrigr().write(|reg| {
+ reg.set_swtrig(Channel::Ch1.index(), true);
+ reg.set_swtrig(Channel::Ch2.index(), true);
+ });
}
pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
self.check_channel_exists(ch)?;
match value {
- Value::Bit8(v) => unsafe {
- T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v));
- },
- Value::Bit12(v, Alignment::Left) => unsafe {
- T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v));
- },
- Value::Bit12(v, Alignment::Right) => unsafe {
- T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v));
- },
+ Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
}
Ok(())
}
+ /// Write `data` to the DAC via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ ///
+ /// ## Current limitations
+ /// - Only CH1 Supported
+ ///
/// TODO: Allow an array of Value instead of only u16, right-aligned
- pub async fn write(&mut self, data: &[u16], circular: bool) -> Result<(), Error>
+ pub async fn write_8bit(&mut self, data_ch1: &[u8], circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ self.write_inner(ValueArray::Bit8(data_ch1), circular).await
+ }
+
+ pub async fn write_12bit_right_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ self.write_inner(ValueArray::Bit12Right(data_ch1), circular).await
+ }
+
+ pub async fn write_12bit_left_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ self.write_inner(ValueArray::Bit12Left(data_ch1), circular).await
+ }
+
+ async fn write_inner(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
// TODO: Make this a parameter or get it from the struct or so...
const CHANNEL: usize = 0;
- //debug!("Starting DAC");
- unsafe {
- T::regs().cr().modify(|w| {
- w.set_en(CHANNEL, true);
- w.set_dmaen(CHANNEL, true);
- });
- }
+ // Enable DAC and DMA
+ T::regs().cr().modify(|w| {
+ w.set_en(CHANNEL, true);
+ w.set_dmaen(CHANNEL, true);
+ });
let tx_request = self.txdma.request();
- // Use the 12 bit right-aligned register for now. TODO: distinguish values
- let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16;
-
- let tx_f = unsafe {
- Transfer::new_write(
- &mut self.txdma,
- tx_request,
- data,
- tx_dst,
- TransferOptions {
- circular,
- halt_transfer_ir: false,
- },
- )
+ // Initiate the correct type of DMA transfer depending on what data is passed
+ let tx_f = match data_ch1 {
+ ValueArray::Bit8(buf) => unsafe {
+ Transfer::new_write(
+ &mut self.txdma,
+ tx_request,
+ buf,
+ T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8,
+ TransferOptions {
+ circular,
+ halt_transfer_ir: false,
+ },
+ )
+ },
+ ValueArray::Bit12Left(buf) => unsafe {
+ Transfer::new_write(
+ &mut self.txdma,
+ tx_request,
+ buf,
+ T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16,
+ TransferOptions {
+ circular,
+ halt_transfer_ir: false,
+ },
+ )
+ },
+ ValueArray::Bit12Right(buf) => unsafe {
+ Transfer::new_write(
+ &mut self.txdma,
+ tx_request,
+ buf,
+ T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16,
+ TransferOptions {
+ circular,
+ halt_transfer_ir: false,
+ },
+ )
+ },
};
- //debug!("Awaiting tx_f");
-
tx_f.await;
// finish dma
- unsafe {
- // TODO: Do we need to check any status registers here?
+ // TODO: Do we need to check any status registers here?
+ T::regs().cr().modify(|w| {
+ // Disable the DAC peripheral
+ w.set_en(CHANNEL, false);
+ // Disable the DMA. TODO: Is this necessary?
+ w.set_dmaen(CHANNEL, false);
+ });
- T::regs().cr().modify(|w| {
- // Disable the dac peripheral
- w.set_en(CHANNEL, false);
- // Disable the DMA. TODO: Is this necessary?
- w.set_dmaen(CHANNEL, false);
- });
- }
Ok(())
}
}
From 218b102b2840c9786944aa6f613450c876b6110b Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Mon, 19 Jun 2023 13:46:17 +0200
Subject: [PATCH 06/74] remove Alignment and make Value and Value array look
the same
---
embassy-stm32/src/dac/mod.rs | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 4384a7c34..0fbf67673 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -84,25 +84,25 @@ impl Ch2Trigger {
}
}
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Alignment {
- Left,
- Right,
-}
-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Value {
+ // 8 bit value
Bit8(u8),
- Bit12(u16, Alignment),
+ // 12 bit value stored in a u16, left-aligned
+ Bit12Left(u16),
+ // 12 bit value stored in a u16, right-aligned
+ Bit12Right(u16),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum ValueArray<'a> {
+ // 8 bit values
Bit8(&'a [u8]),
+ // 12 bit value stored in a u16, left-aligned
Bit12Left(&'a [u16]),
+ // 12 bit values stored in a u16, right-aligned
Bit12Right(&'a [u16]),
}
@@ -225,8 +225,8 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
self.check_channel_exists(ch)?;
match value {
Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
- Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
- Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit12Right(v) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
}
Ok(())
}
From 88052480b14b8dd38e7c4ba179b7035390f59618 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Mon, 19 Jun 2023 13:50:17 +0200
Subject: [PATCH 07/74] fix typo, minor cleanup
---
embassy-stm32/src/dac/mod.rs | 13 +++++++------
embassy-stm32/src/dma/bdma.rs | 7 +++----
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 0fbf67673..704b77b37 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -275,42 +275,43 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
});
let tx_request = self.txdma.request();
+ let channel = &mut self.txdma;
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data_ch1 {
ValueArray::Bit8(buf) => unsafe {
Transfer::new_write(
- &mut self.txdma,
+ channel,
tx_request,
buf,
T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8,
TransferOptions {
circular,
- halt_transfer_ir: false,
+ half_transfer_ir: false,
},
)
},
ValueArray::Bit12Left(buf) => unsafe {
Transfer::new_write(
- &mut self.txdma,
+ channel,
tx_request,
buf,
T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16,
TransferOptions {
circular,
- halt_transfer_ir: false,
+ half_transfer_ir: false,
},
)
},
ValueArray::Bit12Right(buf) => unsafe {
Transfer::new_write(
- &mut self.txdma,
+ channel,
tx_request,
buf,
T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16,
TransferOptions {
circular,
- halt_transfer_ir: false,
+ half_transfer_ir: false,
},
)
},
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 3d315e20b..0ad20579a 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -1,7 +1,6 @@
#![macro_use]
use core::future::Future;
-use core::option;
use core::pin::Pin;
use core::sync::atomic::{fence, Ordering};
use core::task::{Context, Poll, Waker};
@@ -24,14 +23,14 @@ use crate::pac::bdma::{regs, vals};
#[non_exhaustive]
pub struct TransferOptions {
pub circular: bool,
- pub halt_transfer_ir: bool,
+ pub half_transfer_ir: bool,
}
impl Default for TransferOptions {
fn default() -> Self {
Self {
circular: false,
- halt_transfer_ir: false,
+ half_transfer_ir: false,
}
}
}
@@ -291,7 +290,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
w.set_dir(dir.into());
w.set_teie(true);
w.set_tcie(true);
- w.set_htie(options.halt_transfer_ir);
+ w.set_htie(options.half_transfer_ir);
if options.circular {
w.set_circ(vals::Circ::ENABLED);
debug!("Setting circular mode");
From 56ab6d9f143ecc3041ac9726e621eedea729ca4d Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Mon, 19 Jun 2023 13:54:22 +0200
Subject: [PATCH 08/74] remove write_X variants
---
embassy-stm32/src/dac/mod.rs | 26 +++-----------------------
1 file changed, 3 insertions(+), 23 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 704b77b37..f02adeed9 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -86,6 +86,7 @@ impl Ch2Trigger {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+/// Single 8 or 12 bit value that can be output by the DAC
pub enum Value {
// 8 bit value
Bit8(u8),
@@ -97,6 +98,7 @@ pub enum Value {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+/// Array variant of [`Value`]
pub enum ValueArray<'a> {
// 8 bit values
Bit8(&'a [u8]),
@@ -239,29 +241,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
/// ## Current limitations
/// - Only CH1 Supported
///
- /// TODO: Allow an array of Value instead of only u16, right-aligned
- pub async fn write_8bit(&mut self, data_ch1: &[u8], circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- self.write_inner(ValueArray::Bit8(data_ch1), circular).await
- }
-
- pub async fn write_12bit_right_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- self.write_inner(ValueArray::Bit12Right(data_ch1), circular).await
- }
-
- pub async fn write_12bit_left_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- self.write_inner(ValueArray::Bit12Left(data_ch1), circular).await
- }
-
- async fn write_inner(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ pub async fn write(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
From 8d0095c61808b88ad95349c7f24e91797d93dc83 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Thu, 22 Jun 2023 10:43:45 +0200
Subject: [PATCH 09/74] add option to enable/disable complete transfer
interrupt
---
embassy-stm32/src/dma/bdma.rs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 162ca9adb..32b75bb68 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -22,8 +22,12 @@ use crate::pac::bdma::{regs, vals};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub struct TransferOptions {
+ /// Enable circular DMA
pub circular: bool,
+ /// Enable half transfer interrupt
pub half_transfer_ir: bool,
+ /// Enable transfer complete interrupt
+ pub complete_transfer_ir: bool,
}
impl Default for TransferOptions {
@@ -31,6 +35,7 @@ impl Default for TransferOptions {
Self {
circular: false,
half_transfer_ir: false,
+ complete_transfer_ir: false,
}
}
}
@@ -289,7 +294,7 @@ impl<'a, C: Channel> Transfer<'a, C> {
}
w.set_dir(dir.into());
w.set_teie(true);
- w.set_tcie(true);
+ w.set_tcie(options.complete_transfer_ir);
w.set_htie(options.half_transfer_ir);
if options.circular {
w.set_circ(vals::Circ::ENABLED);
From 78736328a042e7c7f6565ed44ac301be22953f7a Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Thu, 22 Jun 2023 10:44:08 +0200
Subject: [PATCH 10/74] update docs and update to new dma interface
---
embassy-stm32/src/dac/mod.rs | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index f02adeed9..42646d20d 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -115,6 +115,7 @@ pub struct Dac<'d, T: Instance, Tx> {
}
impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
+ /// Create a new instance with one channel
pub fn new_1ch(
peri: impl Peripheral + 'd,
txdma: impl Peripheral
+ 'd,
@@ -124,6 +125,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
Self::new_inner(peri, 1, txdma)
}
+ /// Create a new instance with two channels
pub fn new_2ch(
peri: impl Peripheral
+ 'd,
txdma: impl Peripheral
+ 'd,
@@ -134,6 +136,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
Self::new_inner(peri, 2, txdma)
}
+ /// Perform initialisation steps for the DAC
fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral
+ 'd) -> Self {
into_ref!(txdma);
T::enable();
@@ -178,15 +181,17 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
Ok(())
}
+ /// Enable the DAC channel `ch`
pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
self.set_channel_enable(ch, true)
}
+ /// Disable the DAC channel `ch`
pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
self.set_channel_enable(ch, false)
}
- /// Performs all register accesses necessary to select a new trigger for CH1
+ /// Select a new trigger for CH1 (disables the channel)
pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch1)?;
unwrap!(self.disable_channel(Channel::Ch1));
@@ -196,7 +201,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
Ok(())
}
- /// Performs all register accesses necessary to select a new trigger for CH2
+ /// Select a new trigger for CH2 (disables the channel)
pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
self.check_channel_exists(Channel::Ch2)?;
unwrap!(self.disable_channel(Channel::Ch2));
@@ -206,7 +211,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
Ok(())
}
- /// Perform a software trigger on a given channel
+ /// Perform a software trigger on `ch`
pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
self.check_channel_exists(ch)?;
T::regs().swtrigr().write(|reg| {
@@ -223,6 +228,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
});
}
+ /// Set a value to be output by the DAC on trigger.
+ ///
+ /// The `value` is written to the corresponding "data holding register"
pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
self.check_channel_exists(ch)?;
match value {
@@ -237,6 +245,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
///
/// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
/// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// ## Current limitations
/// - Only CH1 Supported
@@ -255,7 +264,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
});
let tx_request = self.txdma.request();
- let channel = &mut self.txdma;
+ let channel = &self.txdma;
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data_ch1 {
@@ -268,6 +277,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
TransferOptions {
circular,
half_transfer_ir: false,
+ complete_transfer_ir: !circular,
},
)
},
@@ -280,6 +290,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
TransferOptions {
circular,
half_transfer_ir: false,
+ complete_transfer_ir: !circular,
},
)
},
@@ -292,6 +303,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
TransferOptions {
circular,
half_transfer_ir: false,
+ complete_transfer_ir: !circular,
},
)
},
From cd4f8f13a2c533f4e752c2e446661a6d86b19fe6 Mon Sep 17 00:00:00 2001
From: goueslati
Date: Thu, 22 Jun 2023 15:21:14 +0100
Subject: [PATCH 11/74] wpan: add BLE HCI
---
embassy-stm32-wpan/Cargo.toml | 4 +-
embassy-stm32-wpan/src/ble.rs | 19 +-
embassy-stm32-wpan/src/cmd.rs | 2 +-
embassy-stm32-wpan/src/evt.rs | 23 ++
embassy-stm32-wpan/src/lhci.rs | 111 +++++++++
embassy-stm32-wpan/src/lib.rs | 2 +
examples/stm32wb/.cargo/config.toml | 2 +-
examples/stm32wb/Cargo.toml | 6 +-
examples/stm32wb/src/bin/eddystone_beacon.rs | 249 +++++++++++++++++++
9 files changed, 412 insertions(+), 6 deletions(-)
create mode 100644 embassy-stm32-wpan/src/lhci.rs
create mode 100644 examples/stm32wb/src/bin/eddystone_beacon.rs
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index f9023ed79..fda4189ca 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -23,11 +23,13 @@ cortex-m = "0.7.6"
heapless = "0.7.16"
bit_field = "0.10.2"
+stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
+bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", optional = true }
[features]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
-ble = []
+ble = ["dep:bluetooth-hci-async"]
mac = []
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs
index 60e0cbdf8..297ee4cdf 100644
--- a/embassy-stm32-wpan/src/ble.rs
+++ b/embassy-stm32-wpan/src/ble.rs
@@ -1,6 +1,7 @@
use core::marker::PhantomData;
use embassy_stm32::ipcc::Ipcc;
+use hci::Opcode;
use crate::channels;
use crate::cmd::CmdPacket;
@@ -29,7 +30,7 @@ impl Ble {
Self { phantom: PhantomData }
}
/// `HW_IPCC_BLE_EvtNot`
- pub async fn read(&self) -> EvtBox {
+ pub async fn tl_read(&self) -> EvtBox {
Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) {
Some(EvtBox::new(node_ptr.cast()))
@@ -41,7 +42,7 @@ impl Ble {
}
/// `TL_BLE_SendCmd`
- pub async fn write(&self, opcode: u16, payload: &[u8]) {
+ pub async fn tl_write(&self, opcode: u16, payload: &[u8]) {
Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe {
CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload);
})
@@ -61,3 +62,17 @@ impl Ble {
.await;
}
}
+
+pub extern crate bluetooth_hci_async as hci;
+
+impl hci::Controller for Ble {
+ async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) {
+ self.tl_write(opcode.0, payload).await;
+ }
+
+ async fn controller_read(&self) -> &[u8] {
+ let evt_box = self.tl_read().await;
+
+ evt_box.serial()
+ }
+}
diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs
index c8056aaa7..8428b6ffc 100644
--- a/embassy-stm32-wpan/src/cmd.rs
+++ b/embassy-stm32-wpan/src/cmd.rs
@@ -52,7 +52,7 @@ impl CmdPacket {
p_cmd_serial,
CmdSerialStub {
ty: packet_type as u8,
- cmd_code: cmd_code,
+ cmd_code,
payload_len: payload.len() as u8,
},
);
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs
index 47bdc49bf..7a4738b7a 100644
--- a/embassy-stm32-wpan/src/evt.rs
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -1,6 +1,7 @@
use core::{ptr, slice};
use super::PacketHeader;
+use crate::consts::TL_EVT_HEADER_SIZE;
/**
* The payload of `Evt` for a command status event
@@ -105,6 +106,14 @@ impl EvtBox {
Self { ptr }
}
+ pub fn evt<'a>(&self) -> &'a [u8] {
+ unsafe {
+ let evt_packet = &(*self.ptr);
+
+ core::slice::from_raw_parts(evt_packet as *const _ as *const u8, core::mem::size_of::())
+ }
+ }
+
/// Returns information about the event
pub fn stub(&self) -> EvtStub {
unsafe {
@@ -124,6 +133,20 @@ impl EvtBox {
slice::from_raw_parts(p_payload, payload_len as usize)
}
}
+
+ /// writes an underlying [`EvtPacket`] into the provided buffer.
+ /// Returns the number of bytes that were written.
+ /// Returns an error if event kind is unknown or if provided buffer size is not enough.
+ pub fn serial<'a>(&self) -> &'a [u8] {
+ unsafe {
+ let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial;
+ let evt_serial_buf: *const u8 = evt_serial.cast();
+
+ let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE;
+
+ slice::from_raw_parts(evt_serial_buf, len)
+ }
+ }
}
impl Drop for EvtBox {
diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs
new file mode 100644
index 000000000..62116a695
--- /dev/null
+++ b/embassy-stm32-wpan/src/lhci.rs
@@ -0,0 +1,111 @@
+use crate::cmd::CmdPacket;
+use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE};
+use crate::evt::{CcEvt, EvtPacket, EvtSerial};
+use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable};
+use crate::TL_REF_TABLE;
+
+const TL_BLEEVT_CC_OPCODE: u8 = 0x0e;
+const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62;
+
+const PACKAGE_DATA_PTR: *const u8 = 0x1FFF_7500 as _;
+const UID64_PTR: *const u32 = 0x1FFF_7580 as _;
+
+#[derive(Debug, Copy, Clone)]
+#[repr(C, packed)]
+pub struct LhciC1DeviceInformationCcrp {
+ pub status: u8,
+ pub rev_id: u16,
+ pub dev_code_id: u16,
+ pub package_type: u8,
+ pub device_type_id: u8,
+ pub st_company_id: u32,
+ pub uid64: u32,
+
+ pub uid96_0: u32,
+ pub uid96_1: u32,
+ pub uid96_2: u32,
+
+ pub safe_boot_info_table: SafeBootInfoTable,
+ pub rss_info_table: RssInfoTable,
+ pub wireless_fw_info_table: WirelessFwInfoTable,
+
+ pub app_fw_inf: u32,
+}
+
+impl Default for LhciC1DeviceInformationCcrp {
+ fn default() -> Self {
+ let DeviceInfoTable {
+ safe_boot_info_table,
+ rss_info_table,
+ wireless_fw_info_table,
+ } = unsafe { &*(*TL_REF_TABLE.as_ptr()).device_info_table }.clone();
+
+ let device_id = stm32_device_signature::device_id();
+ let uid96_0 = (device_id[3] as u32) << 24
+ | (device_id[2] as u32) << 16
+ | (device_id[1] as u32) << 8
+ | device_id[0] as u32;
+ let uid96_1 = (device_id[7] as u32) << 24
+ | (device_id[6] as u32) << 16
+ | (device_id[5] as u32) << 8
+ | device_id[4] as u32;
+ let uid96_2 = (device_id[11] as u32) << 24
+ | (device_id[10] as u32) << 16
+ | (device_id[9] as u32) << 8
+ | device_id[8] as u32;
+
+ let package_type = unsafe { *PACKAGE_DATA_PTR };
+ let uid64 = unsafe { *UID64_PTR };
+ let st_company_id = unsafe { *UID64_PTR.offset(1) } >> 8 & 0x00FF_FFFF;
+ let device_type_id = (unsafe { *UID64_PTR.offset(1) } & 0x000000FF) as u8;
+
+ LhciC1DeviceInformationCcrp {
+ status: 0,
+ rev_id: 0,
+ dev_code_id: 0,
+ package_type,
+ device_type_id,
+ st_company_id,
+ uid64,
+ uid96_0,
+ uid96_1,
+ uid96_2,
+ safe_boot_info_table,
+ rss_info_table,
+ wireless_fw_info_table,
+ app_fw_inf: (1 << 8), // 0.0.1
+ }
+ }
+}
+
+impl LhciC1DeviceInformationCcrp {
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ pub fn write(&self, cmd_packet: &mut CmdPacket) {
+ let self_size = core::mem::size_of::();
+
+ unsafe {
+ let cmd_packet_ptr: *mut CmdPacket = cmd_packet;
+ let evet_packet_ptr: *mut EvtPacket = cmd_packet_ptr.cast();
+
+ let evt_serial: *mut EvtSerial = &mut (*evet_packet_ptr).evt_serial;
+ let evt_payload = (*evt_serial).evt.payload.as_mut_ptr();
+ let evt_cc: *mut CcEvt = evt_payload.cast();
+ let evt_cc_payload_buf = (*evt_cc).payload.as_mut_ptr();
+
+ (*evt_serial).kind = TlPacketType::LocRsp as u8;
+ (*evt_serial).evt.evt_code = TL_BLEEVT_CC_OPCODE;
+ (*evt_serial).evt.payload_len = TL_EVT_HEADER_SIZE as u8 + self_size as u8;
+
+ (*evt_cc).cmd_code = LHCI_OPCODE_C1_DEVICE_INF;
+ (*evt_cc).num_cmd = 1;
+
+ let self_ptr: *const LhciC1DeviceInformationCcrp = self;
+ let self_buf = self_ptr.cast();
+
+ core::ptr::copy(self_buf, evt_cc_payload_buf, self_size);
+ }
+ }
+}
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs
index 5aec9933c..bf0f0466e 100644
--- a/embassy-stm32-wpan/src/lib.rs
+++ b/embassy-stm32-wpan/src/lib.rs
@@ -1,4 +1,5 @@
#![no_std]
+#![cfg_attr(feature = "ble", feature(async_fn_in_trait))]
// This must go FIRST so that all the other modules see its macros.
pub mod fmt;
@@ -21,6 +22,7 @@ pub mod channels;
pub mod cmd;
pub mod consts;
pub mod evt;
+pub mod lhci;
#[cfg(feature = "mac")]
pub mod mac;
pub mod mm;
diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml
index d23fdc513..35317a297 100644
--- a/examples/stm32wb/.cargo/config.toml
+++ b/examples/stm32wb/.cargo/config.toml
@@ -1,6 +1,6 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# replace STM32WB55CCUx with your chip as listed in `probe-rs-cli chip list`
-# runner = "probe-rs-cli run --chip STM32WB55CCUx --speed 1000 --connect-under-reset"
+# runner = "probe-rs-cli run --chip STM32WB55RGVx --speed 1000 --connect-under-reset"
runner = "teleprobe local run --chip STM32WB55RG --elf"
[build]
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index e41424aad..726cd10d4 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -33,4 +33,8 @@ required-features = ["ble"]
[[bin]]
name = "tl_mbox_mac"
-required-features = ["mac"]
\ No newline at end of file
+required-features = ["mac"]
+
+[[bin]]
+name = "eddystone_beacon"
+required-features = ["ble"]
\ No newline at end of file
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
new file mode 100644
index 000000000..fdd5be4a2
--- /dev/null
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -0,0 +1,249 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+use core::time::Duration;
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::bind_interrupts;
+use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
+use embassy_stm32_wpan::ble::hci::host::uart::UartHci;
+use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
+use embassy_stm32_wpan::ble::hci::types::AdvertisingType;
+use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{
+ AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
+};
+use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands;
+use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
+use embassy_stm32_wpan::ble::hci::BdAddr;
+use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
+use embassy_stm32_wpan::TlMbox;
+use {defmt_rtt as _, panic_probe as _};
+
+bind_interrupts!(struct Irqs{
+ IPCC_C1_RX => ReceiveInterruptHandler;
+ IPCC_C1_TX => TransmitInterruptHandler;
+});
+
+const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
+
+#[embassy_executor::main]
+async fn main(_spawner: Spawner) {
+ /*
+ How to make this work:
+
+ - Obtain a NUCLEO-STM32WB55 from your preferred supplier.
+ - Download and Install STM32CubeProgrammer.
+ - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from
+ gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x
+ - Open STM32CubeProgrammer
+ - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware.
+ - Once complete, click connect to connect to the device.
+ - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services".
+ - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file
+ - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
+ - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the
+ stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address.
+ - Select that file, the memory address, "verify download", and then "Firmware Upgrade".
+ - Select "Start Wireless Stack".
+ - Disconnect from the device.
+ - In the examples folder for stm32wb, modify the memory.x file to match your target device.
+ - Run this example.
+
+ Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name.
+ */
+
+ let p = embassy_stm32::init(Default::default());
+ info!("Hello World!");
+
+ let config = Config::default();
+ let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
+
+ let sys_event = mbox.sys_subsystem.read().await;
+ info!("sys event: {}", sys_event.payload());
+
+ mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
+
+ info!("resetting BLE...");
+ mbox.ble_subsystem.reset().await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("config public address...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("config random address...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::random_address(get_random_addr()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("config identity root...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::identity_root(&get_irk()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("config encryption root...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("config tx power level...");
+ mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("GATT init...");
+ mbox.ble_subsystem.init_gatt().await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("GAP init...");
+ mbox.ble_subsystem
+ .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ // info!("set scan response...");
+ // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap();
+ // let response = mbox.ble_subsystem.read().await.unwrap();
+ // defmt::info!("{}", response);
+
+ info!("set discoverable...");
+ mbox.ble_subsystem
+ .set_discoverable(&DiscoverableParameters {
+ advertising_type: AdvertisingType::NonConnectableUndirected,
+ advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))),
+ address_type: OwnAddressType::Public,
+ filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
+ local_name: None,
+ advertising_data: &[],
+ conn_interval: (None, None),
+ })
+ .await
+ .unwrap();
+
+ let response = mbox.ble_subsystem.read().await;
+ defmt::info!("{}", response);
+
+ // remove some advertisement to decrease the packet size
+ info!("delete tx power ad type...");
+ mbox.ble_subsystem
+ .delete_ad_type(AdvertisingDataType::TxPowerLevel)
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("delete conn interval ad type...");
+ mbox.ble_subsystem
+ .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval)
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("update advertising data...");
+ mbox.ble_subsystem
+ .update_advertising_data(&eddystone_advertising_data())
+ .await
+ .unwrap();
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("update advertising data type...");
+ mbox.ble_subsystem
+ .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe])
+ .await
+ .unwrap();
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ info!("update advertising data flags...");
+ mbox.ble_subsystem
+ .update_advertising_data(&[
+ 2,
+ AdvertisingDataType::Flags as u8,
+ (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support
+ ])
+ .await
+ .unwrap();
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ defmt::info!("{}", response);
+
+ cortex_m::asm::wfi();
+}
+
+fn get_bd_addr() -> BdAddr {
+ let mut bytes = [0u8; 6];
+
+ let lhci_info = LhciC1DeviceInformationCcrp::new();
+ bytes[0] = (lhci_info.uid64 & 0xff) as u8;
+ bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
+ bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
+ bytes[3] = lhci_info.device_type_id;
+ bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
+ bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
+
+ BdAddr(bytes)
+}
+
+fn get_random_addr() -> BdAddr {
+ let mut bytes = [0u8; 6];
+
+ let lhci_info = LhciC1DeviceInformationCcrp::new();
+ bytes[0] = (lhci_info.uid64 & 0xff) as u8;
+ bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
+ bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
+ bytes[3] = 0;
+ bytes[4] = 0x6E;
+ bytes[5] = 0xED;
+
+ BdAddr(bytes)
+}
+
+const BLE_CFG_IRK: [u8; 16] = [
+ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+];
+const BLE_CFG_ERK: [u8; 16] = [
+ 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
+];
+
+fn get_irk() -> EncryptionKey {
+ EncryptionKey(BLE_CFG_IRK)
+}
+
+fn get_erk() -> EncryptionKey {
+ EncryptionKey(BLE_CFG_ERK)
+}
+
+fn eddystone_advertising_data() -> [u8; 24] {
+ const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com";
+
+ let mut service_data = [0u8; 24];
+ let url_len = EDDYSTONE_URL.len();
+
+ service_data[0] = 6 + url_len as u8;
+ service_data[1] = AdvertisingDataType::ServiceData as u8;
+
+ // 16-bit eddystone uuid
+ service_data[2] = 0xaa;
+ service_data[3] = 0xFE;
+
+ service_data[4] = 0x10; // URL frame type
+ service_data[5] = 22_i8 as u8; // calibrated TX power at 0m
+ service_data[6] = 0x03; // eddystone url prefix = https
+
+ service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL);
+
+ service_data
+}
From 810c6af77af037a658186f8b102980ee84164a05 Mon Sep 17 00:00:00 2001
From: goueslati
Date: Thu, 22 Jun 2023 15:31:45 +0100
Subject: [PATCH 12/74] fix build
---
examples/stm32wb/src/bin/tl_mbox_ble.rs | 4 ++--
examples/stm32wb/src/bin/tl_mbox_mac.rs | 6 +++---
tests/stm32/src/bin/tl_mbox.rs | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs
index 439bd01ac..a511e89aa 100644
--- a/examples/stm32wb/src/bin/tl_mbox_ble.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs
@@ -52,10 +52,10 @@ async fn main(_spawner: Spawner) {
mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
info!("starting ble...");
- mbox.ble_subsystem.write(0x0c, &[]).await;
+ mbox.ble_subsystem.tl_write(0x0c, &[]).await;
info!("waiting for ble...");
- let ble_event = mbox.ble_subsystem.read().await;
+ let ble_event = mbox.ble_subsystem.tl_read().await;
info!("ble event: {}", ble_event.payload());
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index a42939bbd..6c8653cf4 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -46,16 +46,16 @@ async fn main(_spawner: Spawner) {
let config = Config::default();
let mbox = TlMbox::init(p.IPCC, Irqs, config);
- let sys_event = mbox.sys_subsystem.read().await;
+ let sys_event = mbox.sys_subsystem.tl_read().await;
info!("sys event: {}", sys_event.payload());
mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
//
// info!("starting ble...");
- // mbox.ble_subsystem.write(0x0c, &[]).await;
+ // mbox.ble_subsystem.t_write(0x0c, &[]).await;
//
// info!("waiting for ble...");
- // let ble_event = mbox.ble_subsystem.read().await;
+ // let ble_event = mbox.ble_subsystem.tl_read().await;
//
// info!("ble event: {}", ble_event.payload());
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index f47a89b6f..f55c0292a 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -63,10 +63,10 @@ async fn main(spawner: Spawner) {
info!("subsystem initialization: {}", result);
info!("starting ble...");
- mbox.ble_subsystem.write(0x0c, &[]).await;
+ mbox.ble_subsystem.tl_write(0x0c, &[]).await;
info!("waiting for ble...");
- let ble_event = mbox.ble_subsystem.read().await;
+ let ble_event = mbox.ble_subsystem.tl_read().await;
info!("ble event {:x} : {:x}", ble_event.stub().kind, ble_event.payload());
From 3dbd58f40e07eb4b5d41a671aec0fe71ac8c4b34 Mon Sep 17 00:00:00 2001
From: goueslati
Date: Thu, 22 Jun 2023 15:59:03 +0100
Subject: [PATCH 13/74] fix unsound access in `EvtBox`
---
embassy-stm32-wpan/Cargo.toml | 2 +-
embassy-stm32-wpan/src/ble.rs | 5 +++--
embassy-stm32-wpan/src/evt.rs | 10 +---------
3 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index fda4189ca..3659d7135 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -24,7 +24,7 @@ heapless = "0.7.16"
bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
-bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", optional = true }
+bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true }
[features]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs
index 297ee4cdf..04acf0aff 100644
--- a/embassy-stm32-wpan/src/ble.rs
+++ b/embassy-stm32-wpan/src/ble.rs
@@ -70,9 +70,10 @@ impl hci::Controller for Ble {
self.tl_write(opcode.0, payload).await;
}
- async fn controller_read(&self) -> &[u8] {
+ async fn controller_read_into(&self, buf: &mut [u8]) {
let evt_box = self.tl_read().await;
+ let evt_serial = evt_box.serial();
- evt_box.serial()
+ buf[..evt_serial.len()].copy_from_slice(evt_serial);
}
}
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs
index 7a4738b7a..25249a13a 100644
--- a/embassy-stm32-wpan/src/evt.rs
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -106,14 +106,6 @@ impl EvtBox {
Self { ptr }
}
- pub fn evt<'a>(&self) -> &'a [u8] {
- unsafe {
- let evt_packet = &(*self.ptr);
-
- core::slice::from_raw_parts(evt_packet as *const _ as *const u8, core::mem::size_of::())
- }
- }
-
/// Returns information about the event
pub fn stub(&self) -> EvtStub {
unsafe {
@@ -137,7 +129,7 @@ impl EvtBox {
/// writes an underlying [`EvtPacket`] into the provided buffer.
/// Returns the number of bytes that were written.
/// Returns an error if event kind is unknown or if provided buffer size is not enough.
- pub fn serial<'a>(&self) -> &'a [u8] {
+ pub fn serial<'a>(&'a self) -> &'a [u8] {
unsafe {
let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial;
let evt_serial_buf: *const u8 = evt_serial.cast();
From 6c123596b7d48ee66ea93e8b1515e91231e9bced Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Fri, 9 Jun 2023 03:36:48 +0200
Subject: [PATCH 14/74] wip: esp-hosted net driver.
---
embassy-net-esp-hosted/Cargo.toml | 20 +
embassy-net-esp-hosted/src/control.rs | 141 +++++
.../src/esp_hosted_config.proto | 432 +++++++++++++
embassy-net-esp-hosted/src/fmt.rs | 257 ++++++++
embassy-net-esp-hosted/src/ioctl.rs | 119 ++++
embassy-net-esp-hosted/src/lib.rs | 300 +++++++++
embassy-net-esp-hosted/src/proto.rs | 598 ++++++++++++++++++
examples/nrf52840/Cargo.toml | 2 +
examples/nrf52840/src/bin/wifi_esp_hosted.rs | 143 +++++
9 files changed, 2012 insertions(+)
create mode 100644 embassy-net-esp-hosted/Cargo.toml
create mode 100644 embassy-net-esp-hosted/src/control.rs
create mode 100644 embassy-net-esp-hosted/src/esp_hosted_config.proto
create mode 100644 embassy-net-esp-hosted/src/fmt.rs
create mode 100644 embassy-net-esp-hosted/src/ioctl.rs
create mode 100644 embassy-net-esp-hosted/src/lib.rs
create mode 100644 embassy-net-esp-hosted/src/proto.rs
create mode 100644 examples/nrf52840/src/bin/wifi_esp_hosted.rs
diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml
new file mode 100644
index 000000000..a7e18ee09
--- /dev/null
+++ b/embassy-net-esp-hosted/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "embassy-net-esp-hosted"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+defmt = { version = "0.3", optional = true }
+log = { version = "0.4.14", optional = true }
+
+embassy-time = { version = "0.1.0", path = "../embassy-time" }
+embassy-sync = { version = "0.2.0", path = "../embassy-sync"}
+embassy-futures = { version = "0.1.0", path = "../embassy-futures"}
+embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"}
+
+embedded-hal = { version = "1.0.0-alpha.10" }
+embedded-hal-async = { version = "=0.2.0-alpha.1" }
+
+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"] }
+heapless = "0.7.16"
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
new file mode 100644
index 000000000..2381c6b84
--- /dev/null
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -0,0 +1,141 @@
+use ch::driver::LinkState;
+use defmt::Debug2Format;
+use embassy_net_driver_channel as ch;
+use heapless::String;
+
+use crate::ioctl::IoctlState;
+use crate::proto::{self, CtrlMsg};
+
+#[derive(Debug)]
+pub struct Error {
+ pub status: u32,
+}
+
+pub struct Control<'a> {
+ state_ch: ch::StateRunner<'a>,
+ ioctl_state: &'a IoctlState,
+}
+
+enum WifiMode {
+ None = 0,
+ Sta = 1,
+ Ap = 2,
+ ApSta = 3,
+}
+
+impl<'a> Control<'a> {
+ pub(crate) fn new(state_ch: ch::StateRunner<'a>, ioctl_state: &'a IoctlState) -> Self {
+ Self { state_ch, ioctl_state }
+ }
+
+ pub async fn init(&mut self) {
+ debug!("set wifi mode");
+ self.set_wifi_mode(WifiMode::Sta as _).await;
+ let mac_addr = self.get_mac_addr().await;
+ debug!("mac addr: {:02x}", mac_addr);
+ self.state_ch.set_ethernet_address(mac_addr);
+ }
+
+ pub async fn join(&mut self, ssid: &str, password: &str) {
+ let req = proto::CtrlMsg {
+ msg_id: proto::CtrlMsgId::ReqConnectAp as _,
+ msg_type: proto::CtrlMsgType::Req as _,
+ payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp {
+ ssid: String::from(ssid),
+ pwd: String::from(password),
+ bssid: String::new(),
+ listen_interval: 3,
+ is_wpa3_supported: false,
+ })),
+ };
+ let resp = self.ioctl(req).await;
+ let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
+ debug!("======= {:?}", Debug2Format(&resp));
+ assert_eq!(resp.resp, 0);
+ self.state_ch.set_link_state(LinkState::Up);
+ }
+
+ async fn get_mac_addr(&mut self) -> [u8; 6] {
+ let req = proto::CtrlMsg {
+ msg_id: proto::CtrlMsgId::ReqGetMacAddress as _,
+ msg_type: proto::CtrlMsgType::Req as _,
+ payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress(
+ proto::CtrlMsgReqGetMacAddress {
+ mode: WifiMode::Sta as _,
+ },
+ )),
+ };
+ let resp = self.ioctl(req).await;
+ let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
+ assert_eq!(resp.resp, 0);
+
+ // WHY IS THIS A STRING? WHYYYY
+ fn nibble_from_hex(b: u8) -> u8 {
+ match b {
+ b'0'..=b'9' => b - b'0',
+ b'a'..=b'f' => b + 0xa - b'a',
+ b'A'..=b'F' => b + 0xa - b'A',
+ _ => panic!("invalid hex digit {}", b),
+ }
+ }
+
+ let mac = resp.mac.as_bytes();
+ let mut res = [0; 6];
+ assert_eq!(mac.len(), 17);
+ for (i, b) in res.iter_mut().enumerate() {
+ *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1])
+ }
+ res
+ }
+
+ async fn get_wifi_mode(&mut self) -> u32 {
+ let req = proto::CtrlMsg {
+ msg_id: proto::CtrlMsgId::ReqGetWifiMode as _,
+ msg_type: proto::CtrlMsgType::Req as _,
+ payload: Some(proto::CtrlMsgPayload::ReqGetWifiMode(proto::CtrlMsgReqGetMode {})),
+ };
+ let resp = self.ioctl(req).await;
+ let proto::CtrlMsgPayload::RespGetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
+ assert_eq!(resp.resp, 0);
+ resp.mode
+ }
+
+ async fn set_wifi_mode(&mut self, mode: u32) {
+ let req = proto::CtrlMsg {
+ msg_id: proto::CtrlMsgId::ReqSetWifiMode as _,
+ msg_type: proto::CtrlMsgType::Req as _,
+ payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })),
+ };
+ let resp = self.ioctl(req).await;
+ let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
+ assert_eq!(resp.resp, 0);
+ }
+
+ async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg {
+ let mut buf = [0u8; 128];
+
+ let req_len = noproto::write(&req, &mut buf).unwrap();
+
+ struct CancelOnDrop<'a>(&'a IoctlState);
+
+ impl CancelOnDrop<'_> {
+ fn defuse(self) {
+ core::mem::forget(self);
+ }
+ }
+
+ impl Drop for CancelOnDrop<'_> {
+ fn drop(&mut self) {
+ self.0.cancel_ioctl();
+ }
+ }
+
+ let ioctl = CancelOnDrop(self.ioctl_state);
+
+ let resp_len = ioctl.0.do_ioctl(&mut buf, req_len).await;
+
+ ioctl.defuse();
+
+ noproto::read(&buf[..resp_len]).unwrap()
+ }
+}
diff --git a/embassy-net-esp-hosted/src/esp_hosted_config.proto b/embassy-net-esp-hosted/src/esp_hosted_config.proto
new file mode 100644
index 000000000..aa1bfde64
--- /dev/null
+++ b/embassy-net-esp-hosted/src/esp_hosted_config.proto
@@ -0,0 +1,432 @@
+syntax = "proto3";
+
+/* Enums similar to ESP IDF */
+enum Ctrl_VendorIEType {
+ Beacon = 0;
+ Probe_req = 1;
+ Probe_resp = 2;
+ Assoc_req = 3;
+ Assoc_resp = 4;
+}
+
+enum Ctrl_VendorIEID {
+ ID_0 = 0;
+ ID_1 = 1;
+}
+
+enum Ctrl_WifiMode {
+ NONE = 0;
+ STA = 1;
+ AP = 2;
+ APSTA = 3;
+}
+
+enum Ctrl_WifiBw {
+ BW_Invalid = 0;
+ HT20 = 1;
+ HT40 = 2;
+}
+
+enum Ctrl_WifiPowerSave {
+ PS_Invalid = 0;
+ MIN_MODEM = 1;
+ MAX_MODEM = 2;
+}
+
+enum Ctrl_WifiSecProt {
+ Open = 0;
+ WEP = 1;
+ WPA_PSK = 2;
+ WPA2_PSK = 3;
+ WPA_WPA2_PSK = 4;
+ WPA2_ENTERPRISE = 5;
+ WPA3_PSK = 6;
+ WPA2_WPA3_PSK = 7;
+}
+
+/* enums for Control path */
+enum Ctrl_Status {
+ Connected = 0;
+ Not_Connected = 1;
+ No_AP_Found = 2;
+ Connection_Fail = 3;
+ Invalid_Argument = 4;
+ Out_Of_Range = 5;
+}
+
+
+enum CtrlMsgType {
+ MsgType_Invalid = 0;
+ Req = 1;
+ Resp = 2;
+ Event = 3;
+ MsgType_Max = 4;
+}
+
+enum CtrlMsgId {
+ MsgId_Invalid = 0;
+
+ /** Request Msgs **/
+ Req_Base = 100;
+
+ Req_GetMACAddress = 101;
+ Req_SetMacAddress = 102;
+ Req_GetWifiMode = 103;
+ Req_SetWifiMode = 104;
+
+ Req_GetAPScanList = 105;
+ Req_GetAPConfig = 106;
+ Req_ConnectAP = 107;
+ Req_DisconnectAP = 108;
+
+ Req_GetSoftAPConfig = 109;
+ Req_SetSoftAPVendorSpecificIE = 110;
+ Req_StartSoftAP = 111;
+ Req_GetSoftAPConnectedSTAList = 112;
+ Req_StopSoftAP = 113;
+
+ Req_SetPowerSaveMode = 114;
+ Req_GetPowerSaveMode = 115;
+
+ Req_OTABegin = 116;
+ Req_OTAWrite = 117;
+ Req_OTAEnd = 118;
+
+ Req_SetWifiMaxTxPower = 119;
+ Req_GetWifiCurrTxPower = 120;
+
+ Req_ConfigHeartbeat = 121;
+ /* Add new control path command response before Req_Max
+ * and update Req_Max */
+ Req_Max = 122;
+
+ /** Response Msgs **/
+ Resp_Base = 200;
+
+ Resp_GetMACAddress = 201;
+ Resp_SetMacAddress = 202;
+ Resp_GetWifiMode = 203;
+ Resp_SetWifiMode = 204;
+
+ Resp_GetAPScanList = 205;
+ Resp_GetAPConfig = 206;
+ Resp_ConnectAP = 207;
+ Resp_DisconnectAP = 208;
+
+ Resp_GetSoftAPConfig = 209;
+ Resp_SetSoftAPVendorSpecificIE = 210;
+ Resp_StartSoftAP = 211;
+ Resp_GetSoftAPConnectedSTAList = 212;
+ Resp_StopSoftAP = 213;
+
+ Resp_SetPowerSaveMode = 214;
+ Resp_GetPowerSaveMode = 215;
+
+ Resp_OTABegin = 216;
+ Resp_OTAWrite = 217;
+ Resp_OTAEnd = 218;
+
+ Resp_SetWifiMaxTxPower = 219;
+ Resp_GetWifiCurrTxPower = 220;
+
+ Resp_ConfigHeartbeat = 221;
+ /* Add new control path command response before Resp_Max
+ * and update Resp_Max */
+ Resp_Max = 222;
+
+ /** Event Msgs **/
+ Event_Base = 300;
+ Event_ESPInit = 301;
+ Event_Heartbeat = 302;
+ Event_StationDisconnectFromAP = 303;
+ Event_StationDisconnectFromESPSoftAP = 304;
+ /* Add new control path command notification before Event_Max
+ * and update Event_Max */
+ Event_Max = 305;
+}
+
+/* internal supporting structures for CtrlMsg */
+message ScanResult {
+ bytes ssid = 1;
+ uint32 chnl = 2;
+ int32 rssi = 3;
+ bytes bssid = 4;
+ Ctrl_WifiSecProt sec_prot = 5;
+}
+
+message ConnectedSTAList {
+ bytes mac = 1;
+ int32 rssi = 2;
+}
+
+
+/* Control path structures */
+/** Req/Resp structure **/
+message CtrlMsg_Req_GetMacAddress {
+ int32 mode = 1;
+}
+
+message CtrlMsg_Resp_GetMacAddress {
+ bytes mac = 1;
+ int32 resp = 2;
+}
+
+message CtrlMsg_Req_GetMode {
+}
+
+message CtrlMsg_Resp_GetMode {
+ int32 mode = 1;
+ int32 resp = 2;
+}
+
+message CtrlMsg_Req_SetMode {
+ int32 mode = 1;
+}
+
+message CtrlMsg_Resp_SetMode {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_GetStatus {
+}
+
+message CtrlMsg_Resp_GetStatus {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_SetMacAddress {
+ bytes mac = 1;
+ int32 mode = 2;
+}
+
+message CtrlMsg_Resp_SetMacAddress {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_GetAPConfig {
+}
+
+message CtrlMsg_Resp_GetAPConfig {
+ bytes ssid = 1;
+ bytes bssid = 2;
+ int32 rssi = 3;
+ int32 chnl = 4;
+ Ctrl_WifiSecProt sec_prot = 5;
+ int32 resp = 6;
+}
+
+message CtrlMsg_Req_ConnectAP {
+ string ssid = 1;
+ string pwd = 2;
+ string bssid = 3;
+ bool is_wpa3_supported = 4;
+ int32 listen_interval = 5;
+}
+
+message CtrlMsg_Resp_ConnectAP {
+ int32 resp = 1;
+ bytes mac = 2;
+}
+
+message CtrlMsg_Req_GetSoftAPConfig {
+}
+
+message CtrlMsg_Resp_GetSoftAPConfig {
+ bytes ssid = 1;
+ bytes pwd = 2;
+ int32 chnl = 3;
+ Ctrl_WifiSecProt sec_prot = 4;
+ int32 max_conn = 5;
+ bool ssid_hidden = 6;
+ int32 bw = 7;
+ int32 resp = 8;
+}
+
+message CtrlMsg_Req_StartSoftAP {
+ string ssid = 1;
+ string pwd = 2;
+ int32 chnl = 3;
+ Ctrl_WifiSecProt sec_prot = 4;
+ int32 max_conn = 5;
+ bool ssid_hidden = 6;
+ int32 bw = 7;
+}
+
+message CtrlMsg_Resp_StartSoftAP {
+ int32 resp = 1;
+ bytes mac = 2;
+}
+
+message CtrlMsg_Req_ScanResult {
+}
+
+message CtrlMsg_Resp_ScanResult {
+ uint32 count = 1;
+ repeated ScanResult entries = 2;
+ int32 resp = 3;
+}
+
+message CtrlMsg_Req_SoftAPConnectedSTA {
+}
+
+message CtrlMsg_Resp_SoftAPConnectedSTA {
+ uint32 num = 1;
+ repeated ConnectedSTAList stations = 2;
+ int32 resp = 3;
+}
+
+message CtrlMsg_Req_OTABegin {
+}
+
+message CtrlMsg_Resp_OTABegin {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_OTAWrite {
+ bytes ota_data = 1;
+}
+
+message CtrlMsg_Resp_OTAWrite {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_OTAEnd {
+}
+
+message CtrlMsg_Resp_OTAEnd {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_VendorIEData {
+ int32 element_id = 1;
+ int32 length = 2;
+ bytes vendor_oui = 3;
+ int32 vendor_oui_type = 4;
+ bytes payload = 5;
+}
+
+message CtrlMsg_Req_SetSoftAPVendorSpecificIE {
+ bool enable = 1;
+ Ctrl_VendorIEType type = 2;
+ Ctrl_VendorIEID idx = 3;
+ CtrlMsg_Req_VendorIEData vendor_ie_data = 4;
+}
+
+message CtrlMsg_Resp_SetSoftAPVendorSpecificIE {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_SetWifiMaxTxPower {
+ int32 wifi_max_tx_power = 1;
+}
+
+message CtrlMsg_Resp_SetWifiMaxTxPower {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Req_GetWifiCurrTxPower {
+}
+
+message CtrlMsg_Resp_GetWifiCurrTxPower {
+ int32 wifi_curr_tx_power = 1;
+ int32 resp = 2;
+}
+
+message CtrlMsg_Req_ConfigHeartbeat {
+ bool enable = 1;
+ int32 duration = 2;
+}
+
+message CtrlMsg_Resp_ConfigHeartbeat {
+ int32 resp = 1;
+}
+
+/** Event structure **/
+message CtrlMsg_Event_ESPInit {
+ bytes init_data = 1;
+}
+
+message CtrlMsg_Event_Heartbeat {
+ int32 hb_num = 1;
+}
+
+message CtrlMsg_Event_StationDisconnectFromAP {
+ int32 resp = 1;
+}
+
+message CtrlMsg_Event_StationDisconnectFromESPSoftAP {
+ int32 resp = 1;
+ bytes mac = 2;
+}
+
+message CtrlMsg {
+ /* msg_type could be req, resp or Event */
+ CtrlMsgType msg_type = 1;
+
+ /* msg id */
+ CtrlMsgId msg_id = 2;
+
+ /* union of all msg ids */
+ oneof payload {
+ /** Requests **/
+ CtrlMsg_Req_GetMacAddress req_get_mac_address = 101;
+ CtrlMsg_Req_SetMacAddress req_set_mac_address = 102;
+ CtrlMsg_Req_GetMode req_get_wifi_mode = 103;
+ CtrlMsg_Req_SetMode req_set_wifi_mode = 104;
+
+ CtrlMsg_Req_ScanResult req_scan_ap_list = 105;
+ CtrlMsg_Req_GetAPConfig req_get_ap_config = 106;
+ CtrlMsg_Req_ConnectAP req_connect_ap = 107;
+ CtrlMsg_Req_GetStatus req_disconnect_ap = 108;
+
+ CtrlMsg_Req_GetSoftAPConfig req_get_softap_config = 109;
+ CtrlMsg_Req_SetSoftAPVendorSpecificIE req_set_softap_vendor_specific_ie = 110;
+ CtrlMsg_Req_StartSoftAP req_start_softap = 111;
+ CtrlMsg_Req_SoftAPConnectedSTA req_softap_connected_stas_list = 112;
+ CtrlMsg_Req_GetStatus req_stop_softap = 113;
+
+ CtrlMsg_Req_SetMode req_set_power_save_mode = 114;
+ CtrlMsg_Req_GetMode req_get_power_save_mode = 115;
+
+ CtrlMsg_Req_OTABegin req_ota_begin = 116;
+ CtrlMsg_Req_OTAWrite req_ota_write = 117;
+ CtrlMsg_Req_OTAEnd req_ota_end = 118;
+
+ CtrlMsg_Req_SetWifiMaxTxPower req_set_wifi_max_tx_power = 119;
+ CtrlMsg_Req_GetWifiCurrTxPower req_get_wifi_curr_tx_power = 120;
+ CtrlMsg_Req_ConfigHeartbeat req_config_heartbeat = 121;
+
+ /** Responses **/
+ CtrlMsg_Resp_GetMacAddress resp_get_mac_address = 201;
+ CtrlMsg_Resp_SetMacAddress resp_set_mac_address = 202;
+ CtrlMsg_Resp_GetMode resp_get_wifi_mode = 203;
+ CtrlMsg_Resp_SetMode resp_set_wifi_mode = 204;
+
+ CtrlMsg_Resp_ScanResult resp_scan_ap_list = 205;
+ CtrlMsg_Resp_GetAPConfig resp_get_ap_config = 206;
+ CtrlMsg_Resp_ConnectAP resp_connect_ap = 207;
+ CtrlMsg_Resp_GetStatus resp_disconnect_ap = 208;
+
+ CtrlMsg_Resp_GetSoftAPConfig resp_get_softap_config = 209;
+ CtrlMsg_Resp_SetSoftAPVendorSpecificIE resp_set_softap_vendor_specific_ie = 210;
+ CtrlMsg_Resp_StartSoftAP resp_start_softap = 211;
+ CtrlMsg_Resp_SoftAPConnectedSTA resp_softap_connected_stas_list = 212;
+ CtrlMsg_Resp_GetStatus resp_stop_softap = 213;
+
+ CtrlMsg_Resp_SetMode resp_set_power_save_mode = 214;
+ CtrlMsg_Resp_GetMode resp_get_power_save_mode = 215;
+
+ CtrlMsg_Resp_OTABegin resp_ota_begin = 216;
+ CtrlMsg_Resp_OTAWrite resp_ota_write = 217;
+ CtrlMsg_Resp_OTAEnd resp_ota_end = 218;
+ CtrlMsg_Resp_SetWifiMaxTxPower resp_set_wifi_max_tx_power = 219;
+ CtrlMsg_Resp_GetWifiCurrTxPower resp_get_wifi_curr_tx_power = 220;
+ CtrlMsg_Resp_ConfigHeartbeat resp_config_heartbeat = 221;
+
+ /** Notifications **/
+ CtrlMsg_Event_ESPInit event_esp_init = 301;
+ CtrlMsg_Event_Heartbeat event_heartbeat = 302;
+ CtrlMsg_Event_StationDisconnectFromAP event_station_disconnect_from_AP = 303;
+ CtrlMsg_Event_StationDisconnectFromESPSoftAP event_station_disconnect_from_ESP_SoftAP = 304;
+ }
+}
diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs
new file mode 100644
index 000000000..91984bde1
--- /dev/null
+++ b/embassy-net-esp-hosted/src/fmt.rs
@@ -0,0 +1,257 @@
+#![macro_use]
+#![allow(unused_macros)]
+
+use core::fmt::{Debug, Display, LowerHex};
+
+#[cfg(all(feature = "defmt", feature = "log"))]
+compile_error!("You may not enable both `defmt` and `log` features.");
+
+macro_rules! assert {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::assert!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::assert!($($x)*);
+ }
+ };
+}
+
+macro_rules! assert_eq {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::assert_eq!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::assert_eq!($($x)*);
+ }
+ };
+}
+
+macro_rules! assert_ne {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::assert_ne!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::assert_ne!($($x)*);
+ }
+ };
+}
+
+macro_rules! debug_assert {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::debug_assert!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::debug_assert!($($x)*);
+ }
+ };
+}
+
+macro_rules! debug_assert_eq {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::debug_assert_eq!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::debug_assert_eq!($($x)*);
+ }
+ };
+}
+
+macro_rules! debug_assert_ne {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::debug_assert_ne!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::debug_assert_ne!($($x)*);
+ }
+ };
+}
+
+macro_rules! todo {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::todo!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::todo!($($x)*);
+ }
+ };
+}
+
+#[cfg(not(feature = "defmt"))]
+macro_rules! unreachable {
+ ($($x:tt)*) => {
+ ::core::unreachable!($($x)*)
+ };
+}
+
+#[cfg(feature = "defmt")]
+macro_rules! unreachable {
+ ($($x:tt)*) => {
+ ::defmt::unreachable!($($x)*);
+ };
+}
+
+macro_rules! panic {
+ ($($x:tt)*) => {
+ {
+ #[cfg(not(feature = "defmt"))]
+ ::core::panic!($($x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::panic!($($x)*);
+ }
+ };
+}
+
+macro_rules! trace {
+ ($s:literal $(, $x:expr)* $(,)?) => {
+ {
+ #[cfg(feature = "log")]
+ ::log::trace!($s $(, $x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::trace!($s $(, $x)*);
+ #[cfg(not(any(feature = "log", feature="defmt")))]
+ let _ = ($( & $x ),*);
+ }
+ };
+}
+
+macro_rules! debug {
+ ($s:literal $(, $x:expr)* $(,)?) => {
+ {
+ #[cfg(feature = "log")]
+ ::log::debug!($s $(, $x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::debug!($s $(, $x)*);
+ #[cfg(not(any(feature = "log", feature="defmt")))]
+ let _ = ($( & $x ),*);
+ }
+ };
+}
+
+macro_rules! info {
+ ($s:literal $(, $x:expr)* $(,)?) => {
+ {
+ #[cfg(feature = "log")]
+ ::log::info!($s $(, $x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::info!($s $(, $x)*);
+ #[cfg(not(any(feature = "log", feature="defmt")))]
+ let _ = ($( & $x ),*);
+ }
+ };
+}
+
+macro_rules! warn {
+ ($s:literal $(, $x:expr)* $(,)?) => {
+ {
+ #[cfg(feature = "log")]
+ ::log::warn!($s $(, $x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::warn!($s $(, $x)*);
+ #[cfg(not(any(feature = "log", feature="defmt")))]
+ let _ = ($( & $x ),*);
+ }
+ };
+}
+
+macro_rules! error {
+ ($s:literal $(, $x:expr)* $(,)?) => {
+ {
+ #[cfg(feature = "log")]
+ ::log::error!($s $(, $x)*);
+ #[cfg(feature = "defmt")]
+ ::defmt::error!($s $(, $x)*);
+ #[cfg(not(any(feature = "log", feature="defmt")))]
+ let _ = ($( & $x ),*);
+ }
+ };
+}
+
+#[cfg(feature = "defmt")]
+macro_rules! unwrap {
+ ($($x:tt)*) => {
+ ::defmt::unwrap!($($x)*)
+ };
+}
+
+#[cfg(not(feature = "defmt"))]
+macro_rules! unwrap {
+ ($arg:expr) => {
+ match $crate::fmt::Try::into_result($arg) {
+ ::core::result::Result::Ok(t) => t,
+ ::core::result::Result::Err(e) => {
+ ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
+ }
+ }
+ };
+ ($arg:expr, $($msg:expr),+ $(,)? ) => {
+ match $crate::fmt::Try::into_result($arg) {
+ ::core::result::Result::Ok(t) => t,
+ ::core::result::Result::Err(e) => {
+ ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
+ }
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub struct NoneError;
+
+pub trait Try {
+ type Ok;
+ type Error;
+ fn into_result(self) -> Result;
+}
+
+impl Try for Option {
+ type Ok = T;
+ type Error = NoneError;
+
+ #[inline]
+ fn into_result(self) -> Result {
+ self.ok_or(NoneError)
+ }
+}
+
+impl Try for Result {
+ type Ok = T;
+ type Error = E;
+
+ #[inline]
+ fn into_result(self) -> Self {
+ self
+ }
+}
+
+pub struct Bytes<'a>(pub &'a [u8]);
+
+impl<'a> Debug for Bytes<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{:#02x?}", self.0)
+ }
+}
+
+impl<'a> Display for Bytes<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{:#02x?}", self.0)
+ }
+}
+
+impl<'a> LowerHex for Bytes<'a> {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{:#02x?}", self.0)
+ }
+}
+
+#[cfg(feature = "defmt")]
+impl<'a> defmt::Format for Bytes<'a> {
+ fn format(&self, fmt: defmt::Formatter) {
+ defmt::write!(fmt, "{:02x}", self.0)
+ }
+}
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
new file mode 100644
index 000000000..59bdabf37
--- /dev/null
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -0,0 +1,119 @@
+use core::cell::{Cell, RefCell};
+use core::future::poll_fn;
+use core::task::{Poll, Waker};
+
+use embassy_sync::waitqueue::WakerRegistration;
+
+use crate::fmt::Bytes;
+
+#[derive(Clone, Copy)]
+pub struct PendingIoctl {
+ pub buf: *mut [u8],
+ pub req_len: usize,
+}
+
+#[derive(Clone, Copy)]
+enum IoctlStateInner {
+ Pending(PendingIoctl),
+ Sent { buf: *mut [u8] },
+ Done { resp_len: usize },
+}
+
+struct Wakers {
+ control: WakerRegistration,
+ runner: WakerRegistration,
+}
+
+impl Default for Wakers {
+ fn default() -> Self {
+ Self {
+ control: WakerRegistration::new(),
+ runner: WakerRegistration::new(),
+ }
+ }
+}
+
+pub struct IoctlState {
+ state: Cell,
+ wakers: RefCell,
+}
+
+impl IoctlState {
+ pub fn new() -> Self {
+ Self {
+ state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
+ wakers: Default::default(),
+ }
+ }
+
+ fn wake_control(&self) {
+ self.wakers.borrow_mut().control.wake();
+ }
+
+ fn register_control(&self, waker: &Waker) {
+ self.wakers.borrow_mut().control.register(waker);
+ }
+
+ fn wake_runner(&self) {
+ self.wakers.borrow_mut().runner.wake();
+ }
+
+ fn register_runner(&self, waker: &Waker) {
+ self.wakers.borrow_mut().runner.register(waker);
+ }
+
+ pub async fn wait_complete(&self) -> usize {
+ poll_fn(|cx| {
+ if let IoctlStateInner::Done { resp_len } = self.state.get() {
+ Poll::Ready(resp_len)
+ } else {
+ self.register_control(cx.waker());
+ Poll::Pending
+ }
+ })
+ .await
+ }
+
+ pub async fn wait_pending(&self) -> PendingIoctl {
+ let pending = poll_fn(|cx| {
+ if let IoctlStateInner::Pending(pending) = self.state.get() {
+ Poll::Ready(pending)
+ } else {
+ self.register_runner(cx.waker());
+ Poll::Pending
+ }
+ })
+ .await;
+
+ self.state.set(IoctlStateInner::Sent { buf: pending.buf });
+ pending
+ }
+
+ pub fn cancel_ioctl(&self) {
+ self.state.set(IoctlStateInner::Done { resp_len: 0 });
+ }
+
+ pub async fn do_ioctl(&self, buf: &mut [u8], req_len: usize) -> usize {
+ debug!("IOCTL Request: {:02x}", Bytes(&buf[..req_len]));
+
+ self.state.set(IoctlStateInner::Pending(PendingIoctl { buf, req_len }));
+ self.wake_runner();
+ self.wait_complete().await
+ }
+
+ pub fn ioctl_done(&self, response: &[u8]) {
+ if let IoctlStateInner::Sent { buf } = self.state.get() {
+ debug!("IOCTL Response: {:02x}", Bytes(response));
+
+ // TODO fix this
+ (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
+
+ self.state.set(IoctlStateInner::Done {
+ resp_len: response.len(),
+ });
+ self.wake_control();
+ } else {
+ warn!("IOCTL Response but no pending Ioctl");
+ }
+ }
+}
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
new file mode 100644
index 000000000..2cf05a7df
--- /dev/null
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -0,0 +1,300 @@
+#![no_std]
+
+use control::Control;
+use embassy_futures::select::{select3, Either3};
+use embassy_net_driver_channel as ch;
+use embassy_time::{Duration, Instant, Timer};
+use embedded_hal::digital::{InputPin, OutputPin};
+use embedded_hal_async::digital::Wait;
+use embedded_hal_async::spi::SpiDevice;
+use ioctl::IoctlState;
+
+use crate::ioctl::PendingIoctl;
+
+mod proto;
+
+// must be first
+mod fmt;
+
+mod control;
+mod ioctl;
+
+const MTU: usize = 1514;
+
+macro_rules! impl_bytes {
+ ($t:ident) => {
+ impl $t {
+ pub const SIZE: usize = core::mem::size_of::();
+
+ #[allow(unused)]
+ pub fn to_bytes(&self) -> [u8; Self::SIZE] {
+ unsafe { core::mem::transmute(*self) }
+ }
+
+ #[allow(unused)]
+ pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
+ let alignment = core::mem::align_of::();
+ assert_eq!(
+ bytes.as_ptr().align_offset(alignment),
+ 0,
+ "{} is not aligned",
+ core::any::type_name::()
+ );
+ unsafe { core::mem::transmute(bytes) }
+ }
+
+ #[allow(unused)]
+ pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
+ let alignment = core::mem::align_of::();
+ assert_eq!(
+ bytes.as_ptr().align_offset(alignment),
+ 0,
+ "{} is not aligned",
+ core::any::type_name::()
+ );
+
+ unsafe { core::mem::transmute(bytes) }
+ }
+ }
+ };
+}
+
+#[repr(C, packed)]
+#[derive(Clone, Copy, Debug, Default)]
+struct PayloadHeader {
+ /// InterfaceType on lower 4 bits, number on higher 4 bits.
+ if_type_and_num: u8,
+
+ /// Flags.
+ ///
+ /// bit 0: more fragments.
+ flags: u8,
+
+ len: u16,
+ offset: u16,
+ checksum: u16,
+ seq_num: u16,
+ reserved2: u8,
+
+ /// Packet type for HCI or PRIV interface, reserved otherwise
+ hci_priv_packet_type: u8,
+}
+impl_bytes!(PayloadHeader);
+
+#[repr(u8)]
+enum InterfaceType {
+ Sta = 0,
+ Ap = 1,
+ Serial = 2,
+ Hci = 3,
+ Priv = 4,
+ Test = 5,
+}
+
+const MAX_SPI_BUFFER_SIZE: usize = 1600;
+
+pub struct State {
+ ioctl_state: IoctlState,
+ ch: ch::State,
+}
+
+impl State {
+ pub fn new() -> Self {
+ Self {
+ ioctl_state: IoctlState::new(),
+ ch: ch::State::new(),
+ }
+ }
+}
+
+pub type NetDriver<'a> = ch::Device<'a, MTU>;
+
+pub async fn new<'a, SPI, IN, OUT>(
+ state: &'a mut State,
+ spi: SPI,
+ handshake: IN,
+ ready: IN,
+ reset: OUT,
+) -> (NetDriver<'a>, Control<'a>, Runner<'a, SPI, IN, OUT>)
+where
+ SPI: SpiDevice,
+ IN: InputPin + Wait,
+ OUT: OutputPin,
+{
+ let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]);
+ let state_ch = ch_runner.state_runner();
+
+ let mut runner = Runner {
+ ch: ch_runner,
+ ioctl_state: &state.ioctl_state,
+ next_seq: 1,
+ handshake,
+ ready,
+ reset,
+ spi,
+ };
+ runner.init().await;
+
+ (device, Control::new(state_ch, &state.ioctl_state), runner)
+}
+
+pub struct Runner<'a, SPI, IN, OUT> {
+ ch: ch::Runner<'a, MTU>,
+ ioctl_state: &'a IoctlState,
+
+ next_seq: u16,
+
+ spi: SPI,
+ handshake: IN,
+ ready: IN,
+ reset: OUT,
+}
+
+impl<'a, SPI, IN, OUT> Runner<'a, SPI, IN, OUT>
+where
+ SPI: SpiDevice,
+ IN: InputPin + Wait,
+ OUT: OutputPin,
+{
+ async fn init(&mut self) {}
+
+ pub async fn run(mut self) -> ! {
+ debug!("resetting...");
+ self.reset.set_low().unwrap();
+ Timer::after(Duration::from_millis(100)).await;
+ self.reset.set_high().unwrap();
+ Timer::after(Duration::from_millis(1000)).await;
+
+ let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
+ let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE];
+
+ loop {
+ self.handshake.wait_for_high().await.unwrap();
+
+ let ioctl = self.ioctl_state.wait_pending();
+ let tx = self.ch.tx_buf();
+ let ev = async { self.ready.wait_for_high().await.unwrap() };
+
+ match select3(ioctl, tx, ev).await {
+ Either3::First(PendingIoctl { buf, req_len }) => {
+ tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02");
+ tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes());
+ tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]);
+
+ let mut header = PayloadHeader {
+ if_type_and_num: InterfaceType::Serial as _,
+ len: (req_len + 14) as _,
+ offset: PayloadHeader::SIZE as _,
+ seq_num: self.next_seq,
+ ..Default::default()
+ };
+ self.next_seq = self.next_seq.wrapping_add(1);
+
+ // Calculate checksum
+ tx_buf[0..12].copy_from_slice(&header.to_bytes());
+ header.checksum = checksum(&tx_buf[..26 + req_len]);
+ tx_buf[0..12].copy_from_slice(&header.to_bytes());
+
+ debug!("====== SENDING IOCTL");
+ }
+ Either3::Second(packet) => {
+ tx_buf[12..][..packet.len()].copy_from_slice(packet);
+
+ let mut header = PayloadHeader {
+ if_type_and_num: InterfaceType::Sta as _,
+ len: packet.len() as _,
+ offset: PayloadHeader::SIZE as _,
+ seq_num: self.next_seq,
+ ..Default::default()
+ };
+ self.next_seq = self.next_seq.wrapping_add(1);
+
+ // Calculate checksum
+ tx_buf[0..12].copy_from_slice(&header.to_bytes());
+ header.checksum = checksum(&tx_buf[..12 + packet.len()]);
+ tx_buf[0..12].copy_from_slice(&header.to_bytes());
+
+ self.ch.tx_done();
+ }
+ Either3::Third(()) => {
+ tx_buf[..PayloadHeader::SIZE].fill(0);
+ }
+ }
+
+ if tx_buf[0] != 0 {
+ trace!("tx: {:02x}", &tx_buf[..40]);
+ }
+
+ self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
+ let delay_until = Instant::now() + Duration::from_millis(1);
+ self.handle_rx(&mut rx_buf);
+ Timer::at(delay_until).await;
+ }
+ }
+
+ fn handle_rx(&mut self, buf: &mut [u8]) {
+ trace!("rx: {:02x}", &buf[..40]);
+
+ let buf_len = buf.len();
+ let h = PayloadHeader::from_bytes_mut((&mut buf[..PayloadHeader::SIZE]).try_into().unwrap());
+
+ if h.len == 0 || h.offset as usize != PayloadHeader::SIZE {
+ return;
+ }
+
+ let payload_len = h.len as usize;
+ if buf_len < PayloadHeader::SIZE + payload_len {
+ warn!("rx: len too big");
+ return;
+ }
+
+ let if_type_and_num = h.if_type_and_num;
+ let want_checksum = h.checksum;
+ h.checksum = 0;
+ let got_checksum = checksum(&buf[..PayloadHeader::SIZE + payload_len]);
+ if want_checksum != got_checksum {
+ warn!("rx: bad checksum. Got {:04x}, want {:04x}", got_checksum, want_checksum);
+ return;
+ }
+
+ let payload = &mut buf[PayloadHeader::SIZE..][..payload_len];
+
+ match if_type_and_num & 0x0f {
+ // STA
+ 0 => match self.ch.try_rx_buf() {
+ Some(buf) => {
+ buf[..payload.len()].copy_from_slice(payload);
+ self.ch.rx_done(payload.len())
+ }
+ None => warn!("failed to push rxd packet to the channel."),
+ },
+ // serial
+ 2 => {
+ debug!("serial rx: {:02x}", payload);
+ if payload.len() < 14 {
+ warn!("serial rx: too short");
+ return;
+ }
+ if &payload[..12] != b"\x01\x08\x00ctrlResp\x02" {
+ warn!("serial rx: bad tlv");
+ return;
+ }
+ let len = u16::from_le_bytes(payload[12..14].try_into().unwrap()) as usize;
+ if payload.len() < 14 + len {
+ warn!("serial rx: too short 2");
+ return;
+ }
+ self.ioctl_state.ioctl_done(&payload[14..][..len]);
+ }
+ _ => warn!("unknown iftype {}", if_type_and_num),
+ }
+ }
+}
+
+fn checksum(buf: &[u8]) -> u16 {
+ let mut res = 0u16;
+ for &b in buf {
+ res = res.wrapping_add(b as _);
+ }
+ res
+}
diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs
new file mode 100644
index 000000000..e105e393c
--- /dev/null
+++ b/embassy-net-esp-hosted/src/proto.rs
@@ -0,0 +1,598 @@
+use heapless::{String, Vec};
+
+/// internal supporting structures for CtrlMsg
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct ScanResult {
+ #[noproto(tag = "1")]
+ pub ssid: String<32>,
+ #[noproto(tag = "2")]
+ pub chnl: u32,
+ #[noproto(tag = "3")]
+ pub rssi: u32,
+ #[noproto(tag = "4")]
+ pub bssid: String<32>,
+ #[noproto(tag = "5")]
+ pub sec_prot: CtrlWifiSecProt,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct ConnectedStaList {
+ #[noproto(tag = "1")]
+ pub mac: String<32>,
+ #[noproto(tag = "2")]
+ pub rssi: u32,
+}
+/// * Req/Resp structure *
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqGetMacAddress {
+ #[noproto(tag = "1")]
+ pub mode: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespGetMacAddress {
+ #[noproto(tag = "1")]
+ pub mac: String<32>,
+ #[noproto(tag = "2")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqGetMode {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespGetMode {
+ #[noproto(tag = "1")]
+ pub mode: u32,
+ #[noproto(tag = "2")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqSetMode {
+ #[noproto(tag = "1")]
+ pub mode: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespSetMode {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqGetStatus {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespGetStatus {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqSetMacAddress {
+ #[noproto(tag = "1")]
+ pub mac: String<32>,
+ #[noproto(tag = "2")]
+ pub mode: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespSetMacAddress {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqGetApConfig {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespGetApConfig {
+ #[noproto(tag = "1")]
+ pub ssid: String<32>,
+ #[noproto(tag = "2")]
+ pub bssid: String<32>,
+ #[noproto(tag = "3")]
+ pub rssi: u32,
+ #[noproto(tag = "4")]
+ pub chnl: u32,
+ #[noproto(tag = "5")]
+ pub sec_prot: CtrlWifiSecProt,
+ #[noproto(tag = "6")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqConnectAp {
+ #[noproto(tag = "1")]
+ pub ssid: String<32>,
+ #[noproto(tag = "2")]
+ pub pwd: String<32>,
+ #[noproto(tag = "3")]
+ pub bssid: String<32>,
+ #[noproto(tag = "4")]
+ pub is_wpa3_supported: bool,
+ #[noproto(tag = "5")]
+ pub listen_interval: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespConnectAp {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+ #[noproto(tag = "2")]
+ pub mac: String<32>,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqGetSoftApConfig {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespGetSoftApConfig {
+ #[noproto(tag = "1")]
+ pub ssid: String<32>,
+ #[noproto(tag = "2")]
+ pub pwd: String<32>,
+ #[noproto(tag = "3")]
+ pub chnl: u32,
+ #[noproto(tag = "4")]
+ pub sec_prot: CtrlWifiSecProt,
+ #[noproto(tag = "5")]
+ pub max_conn: u32,
+ #[noproto(tag = "6")]
+ pub ssid_hidden: bool,
+ #[noproto(tag = "7")]
+ pub bw: u32,
+ #[noproto(tag = "8")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqStartSoftAp {
+ #[noproto(tag = "1")]
+ pub ssid: String<32>,
+ #[noproto(tag = "2")]
+ pub pwd: String<32>,
+ #[noproto(tag = "3")]
+ pub chnl: u32,
+ #[noproto(tag = "4")]
+ pub sec_prot: CtrlWifiSecProt,
+ #[noproto(tag = "5")]
+ pub max_conn: u32,
+ #[noproto(tag = "6")]
+ pub ssid_hidden: bool,
+ #[noproto(tag = "7")]
+ pub bw: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespStartSoftAp {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+ #[noproto(tag = "2")]
+ pub mac: String<32>,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqScanResult {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespScanResult {
+ #[noproto(tag = "1")]
+ pub count: u32,
+ #[noproto(repeated, tag = "2")]
+ pub entries: Vec,
+ #[noproto(tag = "3")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqSoftApConnectedSta {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespSoftApConnectedSta {
+ #[noproto(tag = "1")]
+ pub num: u32,
+ #[noproto(repeated, tag = "2")]
+ pub stations: Vec,
+ #[noproto(tag = "3")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqOtaBegin {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespOtaBegin {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqOtaWrite {
+ #[noproto(tag = "1")]
+ pub ota_data: Vec,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespOtaWrite {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqOtaEnd {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespOtaEnd {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqVendorIeData {
+ #[noproto(tag = "1")]
+ pub element_id: u32,
+ #[noproto(tag = "2")]
+ pub length: u32,
+ #[noproto(tag = "3")]
+ pub vendor_oui: Vec,
+ #[noproto(tag = "4")]
+ pub vendor_oui_type: u32,
+ #[noproto(tag = "5")]
+ pub payload: Vec,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
+ #[noproto(tag = "1")]
+ pub enable: bool,
+ #[noproto(tag = "2")]
+ pub r#type: CtrlVendorIeType,
+ #[noproto(tag = "3")]
+ pub idx: CtrlVendorIeid,
+ #[noproto(optional, tag = "4")]
+ pub vendor_ie_data: Option,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespSetSoftApVendorSpecificIe {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqSetWifiMaxTxPower {
+ #[noproto(tag = "1")]
+ pub wifi_max_tx_power: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespSetWifiMaxTxPower {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqGetWifiCurrTxPower {}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespGetWifiCurrTxPower {
+ #[noproto(tag = "1")]
+ pub wifi_curr_tx_power: u32,
+ #[noproto(tag = "2")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgReqConfigHeartbeat {
+ #[noproto(tag = "1")]
+ pub enable: bool,
+ #[noproto(tag = "2")]
+ pub duration: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgRespConfigHeartbeat {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+/// * Event structure *
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgEventEspInit {
+ #[noproto(tag = "1")]
+ pub init_data: Vec,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgEventHeartbeat {
+ #[noproto(tag = "1")]
+ pub hb_num: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgEventStationDisconnectFromAp {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
+ #[noproto(tag = "1")]
+ pub resp: u32,
+ #[noproto(tag = "2")]
+ pub mac: String<32>,
+}
+
+#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+pub struct CtrlMsg {
+ /// msg_type could be req, resp or Event
+ #[noproto(tag = "1")]
+ pub msg_type: CtrlMsgType,
+ /// msg id
+ #[noproto(tag = "2")]
+ pub msg_id: CtrlMsgId,
+ /// union of all msg ids
+ #[noproto(
+ oneof,
+ tags = "101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 301, 302, 303, 304"
+ )]
+ pub payload: Option,
+}
+
+/// union of all msg ids
+#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)]
+pub enum CtrlMsgPayload {
+ /// * Requests *
+ #[noproto(tag = "101")]
+ ReqGetMacAddress(CtrlMsgReqGetMacAddress),
+ #[noproto(tag = "102")]
+ ReqSetMacAddress(CtrlMsgReqSetMacAddress),
+ #[noproto(tag = "103")]
+ ReqGetWifiMode(CtrlMsgReqGetMode),
+ #[noproto(tag = "104")]
+ ReqSetWifiMode(CtrlMsgReqSetMode),
+ #[noproto(tag = "105")]
+ ReqScanApList(CtrlMsgReqScanResult),
+ #[noproto(tag = "106")]
+ ReqGetApConfig(CtrlMsgReqGetApConfig),
+ #[noproto(tag = "107")]
+ ReqConnectAp(CtrlMsgReqConnectAp),
+ #[noproto(tag = "108")]
+ ReqDisconnectAp(CtrlMsgReqGetStatus),
+ #[noproto(tag = "109")]
+ ReqGetSoftapConfig(CtrlMsgReqGetSoftApConfig),
+ #[noproto(tag = "110")]
+ ReqSetSoftapVendorSpecificIe(CtrlMsgReqSetSoftApVendorSpecificIe),
+ #[noproto(tag = "111")]
+ ReqStartSoftap(CtrlMsgReqStartSoftAp),
+ #[noproto(tag = "112")]
+ ReqSoftapConnectedStasList(CtrlMsgReqSoftApConnectedSta),
+ #[noproto(tag = "113")]
+ ReqStopSoftap(CtrlMsgReqGetStatus),
+ #[noproto(tag = "114")]
+ ReqSetPowerSaveMode(CtrlMsgReqSetMode),
+ #[noproto(tag = "115")]
+ ReqGetPowerSaveMode(CtrlMsgReqGetMode),
+ #[noproto(tag = "116")]
+ ReqOtaBegin(CtrlMsgReqOtaBegin),
+ #[noproto(tag = "117")]
+ ReqOtaWrite(CtrlMsgReqOtaWrite),
+ #[noproto(tag = "118")]
+ ReqOtaEnd(CtrlMsgReqOtaEnd),
+ #[noproto(tag = "119")]
+ ReqSetWifiMaxTxPower(CtrlMsgReqSetWifiMaxTxPower),
+ #[noproto(tag = "120")]
+ ReqGetWifiCurrTxPower(CtrlMsgReqGetWifiCurrTxPower),
+ #[noproto(tag = "121")]
+ ReqConfigHeartbeat(CtrlMsgReqConfigHeartbeat),
+ /// * Responses *
+ #[noproto(tag = "201")]
+ RespGetMacAddress(CtrlMsgRespGetMacAddress),
+ #[noproto(tag = "202")]
+ RespSetMacAddress(CtrlMsgRespSetMacAddress),
+ #[noproto(tag = "203")]
+ RespGetWifiMode(CtrlMsgRespGetMode),
+ #[noproto(tag = "204")]
+ RespSetWifiMode(CtrlMsgRespSetMode),
+ #[noproto(tag = "205")]
+ RespScanApList(CtrlMsgRespScanResult),
+ #[noproto(tag = "206")]
+ RespGetApConfig(CtrlMsgRespGetApConfig),
+ #[noproto(tag = "207")]
+ RespConnectAp(CtrlMsgRespConnectAp),
+ #[noproto(tag = "208")]
+ RespDisconnectAp(CtrlMsgRespGetStatus),
+ #[noproto(tag = "209")]
+ RespGetSoftapConfig(CtrlMsgRespGetSoftApConfig),
+ #[noproto(tag = "210")]
+ RespSetSoftapVendorSpecificIe(CtrlMsgRespSetSoftApVendorSpecificIe),
+ #[noproto(tag = "211")]
+ RespStartSoftap(CtrlMsgRespStartSoftAp),
+ #[noproto(tag = "212")]
+ RespSoftapConnectedStasList(CtrlMsgRespSoftApConnectedSta),
+ #[noproto(tag = "213")]
+ RespStopSoftap(CtrlMsgRespGetStatus),
+ #[noproto(tag = "214")]
+ RespSetPowerSaveMode(CtrlMsgRespSetMode),
+ #[noproto(tag = "215")]
+ RespGetPowerSaveMode(CtrlMsgRespGetMode),
+ #[noproto(tag = "216")]
+ RespOtaBegin(CtrlMsgRespOtaBegin),
+ #[noproto(tag = "217")]
+ RespOtaWrite(CtrlMsgRespOtaWrite),
+ #[noproto(tag = "218")]
+ RespOtaEnd(CtrlMsgRespOtaEnd),
+ #[noproto(tag = "219")]
+ RespSetWifiMaxTxPower(CtrlMsgRespSetWifiMaxTxPower),
+ #[noproto(tag = "220")]
+ RespGetWifiCurrTxPower(CtrlMsgRespGetWifiCurrTxPower),
+ #[noproto(tag = "221")]
+ RespConfigHeartbeat(CtrlMsgRespConfigHeartbeat),
+ /// * Notifications *
+ #[noproto(tag = "301")]
+ EventEspInit(CtrlMsgEventEspInit),
+ #[noproto(tag = "302")]
+ EventHeartbeat(CtrlMsgEventHeartbeat),
+ #[noproto(tag = "303")]
+ EventStationDisconnectFromAp(CtrlMsgEventStationDisconnectFromAp),
+ #[noproto(tag = "304")]
+ EventStationDisconnectFromEspSoftAp(CtrlMsgEventStationDisconnectFromEspSoftAp),
+}
+
+/// Enums similar to ESP IDF
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlVendorIeType {
+ #[default]
+ Beacon = 0,
+ ProbeReq = 1,
+ ProbeResp = 2,
+ AssocReq = 3,
+ AssocResp = 4,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlVendorIeid {
+ #[default]
+ Id0 = 0,
+ Id1 = 1,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlWifiMode {
+ #[default]
+ None = 0,
+ Sta = 1,
+ Ap = 2,
+ Apsta = 3,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlWifiBw {
+ #[default]
+ BwInvalid = 0,
+ Ht20 = 1,
+ Ht40 = 2,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlWifiPowerSave {
+ #[default]
+ PsInvalid = 0,
+ MinModem = 1,
+ MaxModem = 2,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlWifiSecProt {
+ #[default]
+ Open = 0,
+ Wep = 1,
+ WpaPsk = 2,
+ Wpa2Psk = 3,
+ WpaWpa2Psk = 4,
+ Wpa2Enterprise = 5,
+ Wpa3Psk = 6,
+ Wpa2Wpa3Psk = 7,
+}
+
+/// enums for Control path
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlStatus {
+ #[default]
+ Connected = 0,
+ NotConnected = 1,
+ NoApFound = 2,
+ ConnectionFail = 3,
+ InvalidArgument = 4,
+ OutOfRange = 5,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlMsgType {
+ #[default]
+ MsgTypeInvalid = 0,
+ Req = 1,
+ Resp = 2,
+ Event = 3,
+ MsgTypeMax = 4,
+}
+
+#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
+#[repr(u32)]
+pub enum CtrlMsgId {
+ #[default]
+ MsgIdInvalid = 0,
+ /// * Request Msgs *
+ ReqBase = 100,
+ ReqGetMacAddress = 101,
+ ReqSetMacAddress = 102,
+ ReqGetWifiMode = 103,
+ ReqSetWifiMode = 104,
+ ReqGetApScanList = 105,
+ ReqGetApConfig = 106,
+ ReqConnectAp = 107,
+ ReqDisconnectAp = 108,
+ ReqGetSoftApConfig = 109,
+ ReqSetSoftApVendorSpecificIe = 110,
+ ReqStartSoftAp = 111,
+ ReqGetSoftApConnectedStaList = 112,
+ ReqStopSoftAp = 113,
+ ReqSetPowerSaveMode = 114,
+ ReqGetPowerSaveMode = 115,
+ ReqOtaBegin = 116,
+ ReqOtaWrite = 117,
+ ReqOtaEnd = 118,
+ ReqSetWifiMaxTxPower = 119,
+ ReqGetWifiCurrTxPower = 120,
+ ReqConfigHeartbeat = 121,
+ /// Add new control path command response before Req_Max
+ /// and update Req_Max
+ ReqMax = 122,
+ /// * Response Msgs *
+ RespBase = 200,
+ RespGetMacAddress = 201,
+ RespSetMacAddress = 202,
+ RespGetWifiMode = 203,
+ RespSetWifiMode = 204,
+ RespGetApScanList = 205,
+ RespGetApConfig = 206,
+ RespConnectAp = 207,
+ RespDisconnectAp = 208,
+ RespGetSoftApConfig = 209,
+ RespSetSoftApVendorSpecificIe = 210,
+ RespStartSoftAp = 211,
+ RespGetSoftApConnectedStaList = 212,
+ RespStopSoftAp = 213,
+ RespSetPowerSaveMode = 214,
+ RespGetPowerSaveMode = 215,
+ RespOtaBegin = 216,
+ RespOtaWrite = 217,
+ RespOtaEnd = 218,
+ RespSetWifiMaxTxPower = 219,
+ RespGetWifiCurrTxPower = 220,
+ RespConfigHeartbeat = 221,
+ /// Add new control path command response before Resp_Max
+ /// and update Resp_Max
+ RespMax = 222,
+ /// * Event Msgs *
+ EventBase = 300,
+ EventEspInit = 301,
+ EventHeartbeat = 302,
+ EventStationDisconnectFromAp = 303,
+ EventStationDisconnectFromEspSoftAp = 304,
+ /// Add new control path command notification before Event_Max
+ /// and update Event_Max
+ EventMax = 305,
+}
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 6627b7861..7c9d48bad 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -22,6 +22,7 @@ embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["ti
lora-phy = { version = "1", optional = true }
lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
+embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
defmt = "0.3"
defmt-rtt = "0.4"
@@ -35,3 +36,4 @@ rand = { version = "0.8.4", default-features = false }
embedded-storage = "0.3.0"
usbd-hid = "0.6.0"
serde = { version = "1.0.136", default-features = false }
+embedded-hal-async = "0.2.0-alpha.1"
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
new file mode 100644
index 000000000..401dbd33c
--- /dev/null
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -0,0 +1,143 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+use defmt::{info, unwrap, warn};
+use embassy_executor::Spawner;
+use embassy_net::tcp::TcpSocket;
+use embassy_net::{Stack, StackResources};
+use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
+use embassy_nrf::rng::Rng;
+use embassy_nrf::spim::{self, Spim};
+use embassy_nrf::{bind_interrupts, peripherals};
+use embassy_time::{Duration, Timer};
+use embedded_hal_async::spi::ExclusiveDevice;
+use embedded_io::asynch::Write;
+use static_cell::make_static;
+use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
+
+bind_interrupts!(struct Irqs {
+ SPIM3 => spim::InterruptHandler;
+ RNG => embassy_nrf::rng::InterruptHandler;
+});
+
+#[embassy_executor::task]
+async fn wifi_task(
+ runner: hosted::Runner<
+ 'static,
+ ExclusiveDevice, Output<'static, peripherals::P0_31>>,
+ Input<'static, AnyPin>,
+ Output<'static, peripherals::P1_03>,
+ >,
+) -> ! {
+ runner.run().await
+}
+
+#[embassy_executor::task]
+async fn net_task(stack: &'static Stack>) -> ! {
+ stack.run().await
+}
+
+#[embassy_executor::main]
+async fn main(spawner: Spawner) {
+ info!("Hello World!");
+
+ let p = embassy_nrf::init(Default::default());
+
+ let miso = p.P0_28;
+ let sck = p.P0_29;
+ let mosi = p.P0_30;
+ let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
+ let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
+ let ready = Input::new(p.P1_02.degrade(), Pull::None);
+ let reset = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
+
+ let mut config = spim::Config::default();
+ config.frequency = spim::Frequency::M1;
+ config.mode = spim::MODE_2; // !!!
+ let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
+ let spi = ExclusiveDevice::new(spi, cs);
+
+ let (device, mut control, runner) = embassy_net_esp_hosted::new(
+ make_static!(embassy_net_esp_hosted::State::new()),
+ spi,
+ handshake,
+ ready,
+ reset,
+ )
+ .await;
+
+ unwrap!(spawner.spawn(wifi_task(runner)));
+
+ // TODO: wait for ESP_INIT event instead of hardcoding delay.
+ Timer::after(Duration::from_secs(3)).await;
+
+ control.init().await;
+ control.join(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await;
+
+ let config = embassy_net::Config::dhcpv4(Default::default());
+ // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
+ // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
+ // dns_servers: Vec::new(),
+ // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
+ // });
+
+ // Generate random seed
+ let mut rng = Rng::new(p.RNG, Irqs);
+ let mut seed = [0; 8];
+ rng.blocking_fill_bytes(&mut seed);
+ let seed = u64::from_le_bytes(seed);
+
+ // Init network stack
+ let stack = &*make_static!(Stack::new(
+ device,
+ config,
+ make_static!(StackResources::<2>::new()),
+ seed
+ ));
+
+ unwrap!(spawner.spawn(net_task(stack)));
+
+ // And now we can use it!
+
+ let mut rx_buffer = [0; 4096];
+ let mut tx_buffer = [0; 4096];
+ let mut buf = [0; 4096];
+
+ loop {
+ let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
+ socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
+
+ info!("Listening on TCP:1234...");
+ if let Err(e) = socket.accept(1234).await {
+ warn!("accept error: {:?}", e);
+ continue;
+ }
+
+ info!("Received connection from {:?}", socket.remote_endpoint());
+
+ loop {
+ let n = match socket.read(&mut buf).await {
+ Ok(0) => {
+ warn!("read EOF");
+ break;
+ }
+ Ok(n) => n,
+ Err(e) => {
+ warn!("read error: {:?}", e);
+ break;
+ }
+ };
+
+ info!("rxd {:02x}", &buf[..n]);
+
+ match socket.write_all(&buf[..n]).await {
+ Ok(()) => {}
+ Err(e) => {
+ warn!("write error: {:?}", e);
+ break;
+ }
+ };
+ }
+ }
+}
From ec2c095a76a0f55a031093e98a5283cff0daa576 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 18:13:19 +0200
Subject: [PATCH 15/74] esp-hosted: print events.
---
embassy-net-esp-hosted/src/control.rs | 7 +++-
embassy-net-esp-hosted/src/ioctl.rs | 4 +-
embassy-net-esp-hosted/src/lib.rs | 36 ++++++++++++++----
embassy-net-esp-hosted/src/proto.rs | 54 +++++++++++++++++++++++++++
4 files changed, 90 insertions(+), 11 deletions(-)
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index 2381c6b84..ec51933b3 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -112,6 +112,8 @@ impl<'a> Control<'a> {
}
async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg {
+ debug!("ioctl req: {:?}", &req);
+
let mut buf = [0u8; 128];
let req_len = noproto::write(&req, &mut buf).unwrap();
@@ -136,6 +138,9 @@ impl<'a> Control<'a> {
ioctl.defuse();
- noproto::read(&buf[..resp_len]).unwrap()
+ let res = noproto::read(&buf[..resp_len]).unwrap();
+ debug!("ioctl resp: {:?}", &res);
+
+ res
}
}
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
index 59bdabf37..689dd2a88 100644
--- a/embassy-net-esp-hosted/src/ioctl.rs
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -94,7 +94,7 @@ impl IoctlState {
}
pub async fn do_ioctl(&self, buf: &mut [u8], req_len: usize) -> usize {
- debug!("IOCTL Request: {:02x}", Bytes(&buf[..req_len]));
+ trace!("ioctl req bytes: {:02x}", Bytes(&buf[..req_len]));
self.state.set(IoctlStateInner::Pending(PendingIoctl { buf, req_len }));
self.wake_runner();
@@ -103,7 +103,7 @@ impl IoctlState {
pub fn ioctl_done(&self, response: &[u8]) {
if let IoctlStateInner::Sent { buf } = self.state.get() {
- debug!("IOCTL Response: {:02x}", Bytes(response));
+ trace!("ioctl resp bytes: {:02x}", Bytes(response));
// TODO fix this
(unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 2cf05a7df..084009966 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -8,6 +8,7 @@ use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::SpiDevice;
use ioctl::IoctlState;
+use proto::CtrlMsg;
use crate::ioctl::PendingIoctl;
@@ -194,8 +195,6 @@ where
tx_buf[0..12].copy_from_slice(&header.to_bytes());
header.checksum = checksum(&tx_buf[..26 + req_len]);
tx_buf[0..12].copy_from_slice(&header.to_bytes());
-
- debug!("====== SENDING IOCTL");
}
Either3::Second(packet) => {
tx_buf[12..][..packet.len()].copy_from_slice(packet);
@@ -270,25 +269,46 @@ where
},
// serial
2 => {
- debug!("serial rx: {:02x}", payload);
+ trace!("serial rx: {:02x}", payload);
if payload.len() < 14 {
warn!("serial rx: too short");
return;
}
- if &payload[..12] != b"\x01\x08\x00ctrlResp\x02" {
- warn!("serial rx: bad tlv");
- return;
- }
+
+ let isEvent = match &payload[..12] {
+ b"\x01\x08\x00ctrlResp\x02" => false,
+ b"\x01\x08\x00ctrlEvnt\x02" => true,
+ _ => {
+ warn!("serial rx: bad tlv");
+ return;
+ }
+ };
+
let len = u16::from_le_bytes(payload[12..14].try_into().unwrap()) as usize;
if payload.len() < 14 + len {
warn!("serial rx: too short 2");
return;
}
- self.ioctl_state.ioctl_done(&payload[14..][..len]);
+ let data = &payload[14..][..len];
+
+ if isEvent {
+ self.handle_event(data);
+ } else {
+ self.ioctl_state.ioctl_done(data);
+ }
}
_ => warn!("unknown iftype {}", if_type_and_num),
}
}
+
+ fn handle_event(&self, data: &[u8]) {
+ let Ok(event) = noproto::read::(data) else {
+ warn!("failed to parse event");
+ return
+ };
+
+ debug!("event: {:?}", &event);
+ }
}
fn checksum(buf: &[u8]) -> u16 {
diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs
index e105e393c..8ceb1579d 100644
--- a/embassy-net-esp-hosted/src/proto.rs
+++ b/embassy-net-esp-hosted/src/proto.rs
@@ -3,6 +3,7 @@ use heapless::{String, Vec};
/// internal supporting structures for CtrlMsg
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ScanResult {
#[noproto(tag = "1")]
pub ssid: String<32>,
@@ -17,6 +18,7 @@ pub struct ScanResult {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ConnectedStaList {
#[noproto(tag = "1")]
pub mac: String<32>,
@@ -26,12 +28,14 @@ pub struct ConnectedStaList {
/// * Req/Resp structure *
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetMacAddress {
#[noproto(tag = "1")]
pub mode: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetMacAddress {
#[noproto(tag = "1")]
pub mac: String<32>,
@@ -40,9 +44,11 @@ pub struct CtrlMsgRespGetMacAddress {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetMode {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetMode {
#[noproto(tag = "1")]
pub mode: u32,
@@ -51,27 +57,32 @@ pub struct CtrlMsgRespGetMode {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetMode {
#[noproto(tag = "1")]
pub mode: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetMode {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetStatus {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetStatus {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetMacAddress {
#[noproto(tag = "1")]
pub mac: String<32>,
@@ -80,15 +91,18 @@ pub struct CtrlMsgReqSetMacAddress {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetMacAddress {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetApConfig {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetApConfig {
#[noproto(tag = "1")]
pub ssid: String<32>,
@@ -105,6 +119,7 @@ pub struct CtrlMsgRespGetApConfig {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqConnectAp {
#[noproto(tag = "1")]
pub ssid: String<32>,
@@ -119,6 +134,7 @@ pub struct CtrlMsgReqConnectAp {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespConnectAp {
#[noproto(tag = "1")]
pub resp: u32,
@@ -127,9 +143,11 @@ pub struct CtrlMsgRespConnectAp {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetSoftApConfig {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetSoftApConfig {
#[noproto(tag = "1")]
pub ssid: String<32>,
@@ -150,6 +168,7 @@ pub struct CtrlMsgRespGetSoftApConfig {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqStartSoftAp {
#[noproto(tag = "1")]
pub ssid: String<32>,
@@ -168,6 +187,7 @@ pub struct CtrlMsgReqStartSoftAp {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespStartSoftAp {
#[noproto(tag = "1")]
pub resp: u32,
@@ -176,9 +196,11 @@ pub struct CtrlMsgRespStartSoftAp {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqScanResult {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespScanResult {
#[noproto(tag = "1")]
pub count: u32,
@@ -189,9 +211,11 @@ pub struct CtrlMsgRespScanResult {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSoftApConnectedSta {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSoftApConnectedSta {
#[noproto(tag = "1")]
pub num: u32,
@@ -202,36 +226,43 @@ pub struct CtrlMsgRespSoftApConnectedSta {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaBegin {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaBegin {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaWrite {
#[noproto(tag = "1")]
pub ota_data: Vec,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaWrite {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqOtaEnd {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespOtaEnd {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqVendorIeData {
#[noproto(tag = "1")]
pub element_id: u32,
@@ -246,6 +277,7 @@ pub struct CtrlMsgReqVendorIeData {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
#[noproto(tag = "1")]
pub enable: bool,
@@ -258,27 +290,32 @@ pub struct CtrlMsgReqSetSoftApVendorSpecificIe {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetSoftApVendorSpecificIe {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqSetWifiMaxTxPower {
#[noproto(tag = "1")]
pub wifi_max_tx_power: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespSetWifiMaxTxPower {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqGetWifiCurrTxPower {}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespGetWifiCurrTxPower {
#[noproto(tag = "1")]
pub wifi_curr_tx_power: u32,
@@ -287,6 +324,7 @@ pub struct CtrlMsgRespGetWifiCurrTxPower {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgReqConfigHeartbeat {
#[noproto(tag = "1")]
pub enable: bool,
@@ -295,6 +333,7 @@ pub struct CtrlMsgReqConfigHeartbeat {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgRespConfigHeartbeat {
#[noproto(tag = "1")]
pub resp: u32,
@@ -302,24 +341,28 @@ pub struct CtrlMsgRespConfigHeartbeat {
/// * Event structure *
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventEspInit {
#[noproto(tag = "1")]
pub init_data: Vec,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventHeartbeat {
#[noproto(tag = "1")]
pub hb_num: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventStationDisconnectFromAp {
#[noproto(tag = "1")]
pub resp: u32,
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
#[noproto(tag = "1")]
pub resp: u32,
@@ -328,6 +371,7 @@ pub struct CtrlMsgEventStationDisconnectFromEspSoftAp {
}
#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct CtrlMsg {
/// msg_type could be req, resp or Event
#[noproto(tag = "1")]
@@ -345,6 +389,7 @@ pub struct CtrlMsg {
/// union of all msg ids
#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgPayload {
/// * Requests *
#[noproto(tag = "101")]
@@ -446,6 +491,7 @@ pub enum CtrlMsgPayload {
/// Enums similar to ESP IDF
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlVendorIeType {
#[default]
Beacon = 0,
@@ -457,6 +503,7 @@ pub enum CtrlVendorIeType {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlVendorIeid {
#[default]
Id0 = 0,
@@ -465,6 +512,7 @@ pub enum CtrlVendorIeid {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiMode {
#[default]
None = 0,
@@ -475,6 +523,7 @@ pub enum CtrlWifiMode {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiBw {
#[default]
BwInvalid = 0,
@@ -484,6 +533,7 @@ pub enum CtrlWifiBw {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiPowerSave {
#[default]
PsInvalid = 0,
@@ -493,6 +543,7 @@ pub enum CtrlWifiPowerSave {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlWifiSecProt {
#[default]
Open = 0,
@@ -508,6 +559,7 @@ pub enum CtrlWifiSecProt {
/// enums for Control path
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlStatus {
#[default]
Connected = 0,
@@ -520,6 +572,7 @@ pub enum CtrlStatus {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgType {
#[default]
MsgTypeInvalid = 0,
@@ -531,6 +584,7 @@ pub enum CtrlMsgType {
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)]
#[repr(u32)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum CtrlMsgId {
#[default]
MsgIdInvalid = 0,
From 082f1ab494587e02d405cad8f186d48943acf16d Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 18:55:29 +0200
Subject: [PATCH 16/74] esp-hosted: nicer names for shared state struct.
---
embassy-net-esp-hosted/src/control.rs | 16 ++---
embassy-net-esp-hosted/src/ioctl.rs | 93 +++++++++++----------------
embassy-net-esp-hosted/src/lib.rs | 16 ++---
3 files changed, 53 insertions(+), 72 deletions(-)
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index ec51933b3..c98d0ebf4 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -3,7 +3,7 @@ use defmt::Debug2Format;
use embassy_net_driver_channel as ch;
use heapless::String;
-use crate::ioctl::IoctlState;
+use crate::ioctl::Shared;
use crate::proto::{self, CtrlMsg};
#[derive(Debug)]
@@ -13,7 +13,7 @@ pub struct Error {
pub struct Control<'a> {
state_ch: ch::StateRunner<'a>,
- ioctl_state: &'a IoctlState,
+ shared: &'a Shared,
}
enum WifiMode {
@@ -24,8 +24,8 @@ enum WifiMode {
}
impl<'a> Control<'a> {
- pub(crate) fn new(state_ch: ch::StateRunner<'a>, ioctl_state: &'a IoctlState) -> Self {
- Self { state_ch, ioctl_state }
+ pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self {
+ Self { state_ch, shared }
}
pub async fn init(&mut self) {
@@ -118,7 +118,7 @@ impl<'a> Control<'a> {
let req_len = noproto::write(&req, &mut buf).unwrap();
- struct CancelOnDrop<'a>(&'a IoctlState);
+ struct CancelOnDrop<'a>(&'a Shared);
impl CancelOnDrop<'_> {
fn defuse(self) {
@@ -128,13 +128,13 @@ impl<'a> Control<'a> {
impl Drop for CancelOnDrop<'_> {
fn drop(&mut self) {
- self.0.cancel_ioctl();
+ self.0.ioctl_cancel();
}
}
- let ioctl = CancelOnDrop(self.ioctl_state);
+ let ioctl = CancelOnDrop(self.shared);
- let resp_len = ioctl.0.do_ioctl(&mut buf, req_len).await;
+ let resp_len = ioctl.0.ioctl(&mut buf, req_len).await;
ioctl.defuse();
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
index 689dd2a88..7cbe80b2a 100644
--- a/embassy-net-esp-hosted/src/ioctl.rs
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -13,105 +13,86 @@ pub struct PendingIoctl {
}
#[derive(Clone, Copy)]
-enum IoctlStateInner {
+enum IoctlState {
Pending(PendingIoctl),
Sent { buf: *mut [u8] },
Done { resp_len: usize },
}
-struct Wakers {
- control: WakerRegistration,
- runner: WakerRegistration,
+pub struct Shared(RefCell);
+
+struct SharedInner {
+ ioctl: IoctlState,
+ control_waker: WakerRegistration,
+ runner_waker: WakerRegistration,
}
-impl Default for Wakers {
- fn default() -> Self {
- Self {
- control: WakerRegistration::new(),
- runner: WakerRegistration::new(),
- }
- }
-}
-
-pub struct IoctlState {
- state: Cell,
- wakers: RefCell,
-}
-
-impl IoctlState {
+impl Shared {
pub fn new() -> Self {
- Self {
- state: Cell::new(IoctlStateInner::Done { resp_len: 0 }),
- wakers: Default::default(),
- }
+ Self(RefCell::new(SharedInner {
+ ioctl: IoctlState::Done { resp_len: 0 },
+ control_waker: WakerRegistration::new(),
+ runner_waker: WakerRegistration::new(),
+ }))
}
- fn wake_control(&self) {
- self.wakers.borrow_mut().control.wake();
- }
-
- fn register_control(&self, waker: &Waker) {
- self.wakers.borrow_mut().control.register(waker);
- }
-
- fn wake_runner(&self) {
- self.wakers.borrow_mut().runner.wake();
- }
-
- fn register_runner(&self, waker: &Waker) {
- self.wakers.borrow_mut().runner.register(waker);
- }
-
- pub async fn wait_complete(&self) -> usize {
+ pub async fn ioctl_wait_complete(&self) -> usize {
poll_fn(|cx| {
- if let IoctlStateInner::Done { resp_len } = self.state.get() {
+ let mut this = self.0.borrow_mut();
+ if let IoctlState::Done { resp_len } = this.ioctl {
Poll::Ready(resp_len)
} else {
- self.register_control(cx.waker());
+ this.control_waker.register(cx.waker());
Poll::Pending
}
})
.await
}
- pub async fn wait_pending(&self) -> PendingIoctl {
+ pub async fn ioctl_wait_pending(&self) -> PendingIoctl {
let pending = poll_fn(|cx| {
- if let IoctlStateInner::Pending(pending) = self.state.get() {
+ let mut this = self.0.borrow_mut();
+ if let IoctlState::Pending(pending) = this.ioctl {
Poll::Ready(pending)
} else {
- self.register_runner(cx.waker());
+ this.runner_waker.register(cx.waker());
Poll::Pending
}
})
.await;
- self.state.set(IoctlStateInner::Sent { buf: pending.buf });
+ self.0.borrow_mut().ioctl = IoctlState::Sent { buf: pending.buf };
pending
}
- pub fn cancel_ioctl(&self) {
- self.state.set(IoctlStateInner::Done { resp_len: 0 });
+ pub fn ioctl_cancel(&self) {
+ self.0.borrow_mut().ioctl = IoctlState::Done { resp_len: 0 };
}
- pub async fn do_ioctl(&self, buf: &mut [u8], req_len: usize) -> usize {
+ pub async fn ioctl(&self, buf: &mut [u8], req_len: usize) -> usize {
trace!("ioctl req bytes: {:02x}", Bytes(&buf[..req_len]));
- self.state.set(IoctlStateInner::Pending(PendingIoctl { buf, req_len }));
- self.wake_runner();
- self.wait_complete().await
+ {
+ let mut this = self.0.borrow_mut();
+ this.ioctl = IoctlState::Pending(PendingIoctl { buf, req_len });
+ this.runner_waker.wake();
+ }
+
+ self.ioctl_wait_complete().await
}
pub fn ioctl_done(&self, response: &[u8]) {
- if let IoctlStateInner::Sent { buf } = self.state.get() {
+ let mut this = self.0.borrow_mut();
+ if let IoctlState::Sent { buf } = this.ioctl {
trace!("ioctl resp bytes: {:02x}", Bytes(response));
// TODO fix this
(unsafe { &mut *buf }[..response.len()]).copy_from_slice(response);
- self.state.set(IoctlStateInner::Done {
+ this.ioctl = IoctlState::Done {
resp_len: response.len(),
- });
- self.wake_control();
+ };
+ this.control_waker.wake();
} else {
warn!("IOCTL Response but no pending Ioctl");
}
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 084009966..700a5221c 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -7,7 +7,7 @@ use embassy_time::{Duration, Instant, Timer};
use embedded_hal::digital::{InputPin, OutputPin};
use embedded_hal_async::digital::Wait;
use embedded_hal_async::spi::SpiDevice;
-use ioctl::IoctlState;
+use ioctl::Shared;
use proto::CtrlMsg;
use crate::ioctl::PendingIoctl;
@@ -95,14 +95,14 @@ enum InterfaceType {
const MAX_SPI_BUFFER_SIZE: usize = 1600;
pub struct State {
- ioctl_state: IoctlState,
+ shared: Shared,
ch: ch::State,
}
impl State {
pub fn new() -> Self {
Self {
- ioctl_state: IoctlState::new(),
+ shared: Shared::new(),
ch: ch::State::new(),
}
}
@@ -127,7 +127,7 @@ where
let mut runner = Runner {
ch: ch_runner,
- ioctl_state: &state.ioctl_state,
+ shared: &state.shared,
next_seq: 1,
handshake,
ready,
@@ -136,12 +136,12 @@ where
};
runner.init().await;
- (device, Control::new(state_ch, &state.ioctl_state), runner)
+ (device, Control::new(state_ch, &state.shared), runner)
}
pub struct Runner<'a, SPI, IN, OUT> {
ch: ch::Runner<'a, MTU>,
- ioctl_state: &'a IoctlState,
+ shared: &'a Shared,
next_seq: u16,
@@ -172,7 +172,7 @@ where
loop {
self.handshake.wait_for_high().await.unwrap();
- let ioctl = self.ioctl_state.wait_pending();
+ let ioctl = self.shared.ioctl_wait_pending();
let tx = self.ch.tx_buf();
let ev = async { self.ready.wait_for_high().await.unwrap() };
@@ -294,7 +294,7 @@ where
if isEvent {
self.handle_event(data);
} else {
- self.ioctl_state.ioctl_done(data);
+ self.shared.ioctl_done(data);
}
}
_ => warn!("unknown iftype {}", if_type_and_num),
From 764b43e82c7b61c21621c1fd9f5fd2f6a3dc419c Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 19:05:20 +0200
Subject: [PATCH 17/74] esp-hosted: wait for esp firmware init.
---
embassy-net-esp-hosted/src/control.rs | 3 +++
embassy-net-esp-hosted/src/ioctl.rs | 23 ++++++++++++++++++++
embassy-net-esp-hosted/src/lib.rs | 11 ++++++++++
examples/nrf52840/src/bin/wifi_esp_hosted.rs | 3 ---
4 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index c98d0ebf4..a2a65bc31 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -29,6 +29,9 @@ impl<'a> Control<'a> {
}
pub async fn init(&mut self) {
+ debug!("wait for init event...");
+ self.shared.init_wait().await;
+
debug!("set wifi mode");
self.set_wifi_mode(WifiMode::Sta as _).await;
let mac_addr = self.get_mac_addr().await;
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
index 7cbe80b2a..607b7b627 100644
--- a/embassy-net-esp-hosted/src/ioctl.rs
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -23,6 +23,7 @@ pub struct Shared(RefCell);
struct SharedInner {
ioctl: IoctlState,
+ is_init: bool,
control_waker: WakerRegistration,
runner_waker: WakerRegistration,
}
@@ -31,6 +32,7 @@ impl Shared {
pub fn new() -> Self {
Self(RefCell::new(SharedInner {
ioctl: IoctlState::Done { resp_len: 0 },
+ is_init: false,
control_waker: WakerRegistration::new(),
runner_waker: WakerRegistration::new(),
}))
@@ -97,4 +99,25 @@ impl Shared {
warn!("IOCTL Response but no pending Ioctl");
}
}
+
+ // // // // // // // // // // // // // // // // // // // //
+
+ pub fn init_done(&self) {
+ let mut this = self.0.borrow_mut();
+ this.is_init = true;
+ this.control_waker.wake();
+ }
+
+ pub async fn init_wait(&self) {
+ poll_fn(|cx| {
+ let mut this = self.0.borrow_mut();
+ if this.is_init {
+ Poll::Ready(())
+ } else {
+ this.control_waker.register(cx.waker());
+ Poll::Pending
+ }
+ })
+ .await
+ }
}
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 700a5221c..ff7bed2b7 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -11,6 +11,7 @@ use ioctl::Shared;
use proto::CtrlMsg;
use crate::ioctl::PendingIoctl;
+use crate::proto::CtrlMsgPayload;
mod proto;
@@ -308,6 +309,16 @@ where
};
debug!("event: {:?}", &event);
+
+ let Some(payload) = &event.payload else {
+ warn!("event without payload?");
+ return
+ };
+
+ match payload {
+ CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(),
+ _ => {}
+ }
}
}
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index 401dbd33c..b75756f76 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -69,9 +69,6 @@ async fn main(spawner: Spawner) {
unwrap!(spawner.spawn(wifi_task(runner)));
- // TODO: wait for ESP_INIT event instead of hardcoding delay.
- Timer::after(Duration::from_secs(3)).await;
-
control.init().await;
control.join(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await;
From 1ed909ea74bfff75bd91b35739a44c5128271571 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 19:08:09 +0200
Subject: [PATCH 18/74] esp-hosted: fix warnings.
---
embassy-net-esp-hosted/src/control.rs | 14 ++------------
embassy-net-esp-hosted/src/ioctl.rs | 4 ++--
embassy-net-esp-hosted/src/lib.rs | 5 +++--
examples/nrf52840/src/bin/wifi_esp_hosted.rs | 1 -
4 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs
index a2a65bc31..fce82ade7 100644
--- a/embassy-net-esp-hosted/src/control.rs
+++ b/embassy-net-esp-hosted/src/control.rs
@@ -16,6 +16,7 @@ pub struct Control<'a> {
shared: &'a Shared,
}
+#[allow(unused)]
enum WifiMode {
None = 0,
Sta = 1,
@@ -34,6 +35,7 @@ impl<'a> Control<'a> {
debug!("set wifi mode");
self.set_wifi_mode(WifiMode::Sta as _).await;
+
let mac_addr = self.get_mac_addr().await;
debug!("mac addr: {:02x}", mac_addr);
self.state_ch.set_ethernet_address(mac_addr);
@@ -91,18 +93,6 @@ impl<'a> Control<'a> {
res
}
- async fn get_wifi_mode(&mut self) -> u32 {
- let req = proto::CtrlMsg {
- msg_id: proto::CtrlMsgId::ReqGetWifiMode as _,
- msg_type: proto::CtrlMsgType::Req as _,
- payload: Some(proto::CtrlMsgPayload::ReqGetWifiMode(proto::CtrlMsgReqGetMode {})),
- };
- let resp = self.ioctl(req).await;
- let proto::CtrlMsgPayload::RespGetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") };
- assert_eq!(resp.resp, 0);
- resp.mode
- }
-
async fn set_wifi_mode(&mut self, mode: u32) {
let req = proto::CtrlMsg {
msg_id: proto::CtrlMsgId::ReqSetWifiMode as _,
diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs
index 607b7b627..e2a6815aa 100644
--- a/embassy-net-esp-hosted/src/ioctl.rs
+++ b/embassy-net-esp-hosted/src/ioctl.rs
@@ -1,6 +1,6 @@
-use core::cell::{Cell, RefCell};
+use core::cell::RefCell;
use core::future::poll_fn;
-use core::task::{Poll, Waker};
+use core::task::Poll;
use embassy_sync::waitqueue::WakerRegistration;
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index ff7bed2b7..2a4601ce4 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -83,6 +83,7 @@ struct PayloadHeader {
}
impl_bytes!(PayloadHeader);
+#[allow(unused)]
#[repr(u8)]
enum InterfaceType {
Sta = 0,
@@ -276,7 +277,7 @@ where
return;
}
- let isEvent = match &payload[..12] {
+ let is_event = match &payload[..12] {
b"\x01\x08\x00ctrlResp\x02" => false,
b"\x01\x08\x00ctrlEvnt\x02" => true,
_ => {
@@ -292,7 +293,7 @@ where
}
let data = &payload[14..][..len];
- if isEvent {
+ if is_event {
self.handle_event(data);
} else {
self.shared.ioctl_done(data);
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index b75756f76..cea45c5c8 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -10,7 +10,6 @@ use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
use embassy_nrf::rng::Rng;
use embassy_nrf::spim::{self, Spim};
use embassy_nrf::{bind_interrupts, peripherals};
-use embassy_time::{Duration, Timer};
use embedded_hal_async::spi::ExclusiveDevice;
use embedded_io::asynch::Write;
use static_cell::make_static;
From 0d02298ea628b9d2154fd05db7975f62b8d12edb Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 22 Jun 2023 15:30:26 +0200
Subject: [PATCH 19/74] esp-hosted: fix build on stable.
---
examples/nrf52840/Cargo.toml | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml
index 7c9d48bad..8c4175966 100644
--- a/examples/nrf52840/Cargo.toml
+++ b/examples/nrf52840/Cargo.toml
@@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0"
[features]
default = ["nightly"]
-nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", "static_cell/nightly",
- "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"]
+nightly = [
+ "embedded-hal-async",
+ "embassy-executor/nightly",
+ "embassy-nrf/nightly",
+ "embassy-net/nightly",
+ "embassy-net-esp-hosted",
+ "embassy-nrf/unstable-traits",
+ "embassy-time/nightly",
+ "embassy-time/unstable-traits",
+ "static_cell/nightly",
+ "embassy-usb",
+ "embedded-io/async",
+ "embassy-net",
+ "embassy-lora",
+ "lora-phy",
+ "lorawan-device",
+ "lorawan",
+]
[dependencies]
embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
@@ -22,7 +38,7 @@ embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["ti
lora-phy = { version = "1", optional = true }
lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true }
lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true }
-embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
+embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true }
defmt = "0.3"
defmt-rtt = "0.4"
@@ -36,4 +52,4 @@ rand = { version = "0.8.4", default-features = false }
embedded-storage = "0.3.0"
usbd-hid = "0.6.0"
serde = { version = "1.0.136", default-features = false }
-embedded-hal-async = "0.2.0-alpha.1"
+embedded-hal-async = { version = "0.2.0-alpha.1", optional = true }
From 6e65282f185d94a8c449374e6d4ed4eefa5793a4 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 22 Jun 2023 21:10:58 +0200
Subject: [PATCH 20/74] esp-hosted: smaller delay after transfer, makes
slightly better perf.
---
embassy-net-esp-hosted/src/lib.rs | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs
index 2a4601ce4..44dfbe89c 100644
--- a/embassy-net-esp-hosted/src/lib.rs
+++ b/embassy-net-esp-hosted/src/lib.rs
@@ -227,7 +227,12 @@ where
}
self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap();
- let delay_until = Instant::now() + Duration::from_millis(1);
+
+ // The esp-hosted firmware deasserts the HANSHAKE pin a few us AFTER ending the SPI transfer
+ // If we check it again too fast, we'll see it's high from the previous transfer, and if we send it
+ // data it will get lost.
+ // Make sure we check it after 100us at minimum.
+ let delay_until = Instant::now() + Duration::from_micros(100);
self.handle_rx(&mut rx_buf);
Timer::at(delay_until).await;
}
From 8bbfa6827cd68f67a50a89b13947542e632d5411 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 22 Jun 2023 21:11:53 +0200
Subject: [PATCH 21/74] esp-hosted: add perf hil test.
---
ci.sh | 2 +-
examples/nrf52840/src/bin/wifi_esp_hosted.rs | 8 +-
tests/nrf/Cargo.toml | 4 +
tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 270 +++++++++++++++++++
tests/rp/src/bin/cyw43-perf.rs | 9 +-
5 files changed, 280 insertions(+), 13 deletions(-)
create mode 100644 tests/nrf/src/bin/wifi_esp_hosted_perf.rs
diff --git a/ci.sh b/ci.sh
index 3fe1b1ce8..a03efb856 100755
--- a/ci.sh
+++ b/ci.sh
@@ -3,7 +3,7 @@
set -euo pipefail
export RUSTFLAGS=-Dwarnings
-export DEFMT_LOG=trace,cyw43=info,cyw43_pio=info,smoltcp=info
+export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info
# needed by wifi examples
export WIFI_NETWORK=x
diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
index cea45c5c8..4eb31b105 100644
--- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs
+++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs
@@ -26,7 +26,7 @@ async fn wifi_task(
'static,
ExclusiveDevice, Output<'static, peripherals::P0_31>>,
Input<'static, AnyPin>,
- Output<'static, peripherals::P1_03>,
+ Output<'static, peripherals::P1_05>,
>,
) -> ! {
runner.run().await
@@ -48,11 +48,11 @@ async fn main(spawner: Spawner) {
let mosi = p.P0_30;
let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
- let ready = Input::new(p.P1_02.degrade(), Pull::None);
- let reset = Output::new(p.P1_03, Level::Low, OutputDrive::Standard);
+ let ready = Input::new(p.P1_04.degrade(), Pull::None);
+ let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
let mut config = spim::Config::default();
- config.frequency = spim::Frequency::M1;
+ config.frequency = spim::Frequency::M32;
config.mode = spim::MODE_2; // !!!
let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
let spi = ExclusiveDevice::new(spi, cs);
diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml
index 9735c87d9..4f9ecc47a 100644
--- a/tests/nrf/Cargo.toml
+++ b/tests/nrf/Cargo.toml
@@ -13,6 +13,10 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature
embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] }
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
embedded-io = { version = "0.4.0", features = ["async"] }
+embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] }
+embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] }
+embedded-hal-async = { version = "0.2.0-alpha.1" }
+static_cell = { version = "1.1", features = [ "nightly" ] }
defmt = "0.3"
defmt-rtt = "0.4"
diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
new file mode 100644
index 000000000..277b985c5
--- /dev/null
+++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs
@@ -0,0 +1,270 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+#[path = "../common.rs"]
+mod common;
+
+use defmt::{error, info, unwrap};
+use embassy_executor::Spawner;
+use embassy_futures::join::join;
+use embassy_net::tcp::TcpSocket;
+use embassy_net::{Config, Ipv4Address, Stack, StackResources};
+use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull};
+use embassy_nrf::rng::Rng;
+use embassy_nrf::spim::{self, Spim};
+use embassy_nrf::{bind_interrupts, peripherals};
+use embassy_time::{with_timeout, Duration, Timer};
+use embedded_hal_async::spi::ExclusiveDevice;
+use static_cell::make_static;
+use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _};
+
+teleprobe_meta::timeout!(120);
+
+bind_interrupts!(struct Irqs {
+ SPIM3 => spim::InterruptHandler;
+ RNG => embassy_nrf::rng::InterruptHandler;
+});
+
+#[embassy_executor::task]
+async fn wifi_task(
+ runner: hosted::Runner<
+ 'static,
+ ExclusiveDevice, Output<'static, peripherals::P0_31>>,
+ Input<'static, AnyPin>,
+ Output<'static, peripherals::P1_05>,
+ >,
+) -> ! {
+ runner.run().await
+}
+
+type MyDriver = hosted::NetDriver<'static>;
+
+#[embassy_executor::task]
+async fn net_task(stack: &'static Stack) -> ! {
+ stack.run().await
+}
+
+#[embassy_executor::main]
+async fn main(spawner: Spawner) {
+ info!("Hello World!");
+
+ let p = embassy_nrf::init(Default::default());
+
+ let miso = p.P0_28;
+ let sck = p.P0_29;
+ let mosi = p.P0_30;
+ let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive);
+ let handshake = Input::new(p.P1_01.degrade(), Pull::Up);
+ let ready = Input::new(p.P1_04.degrade(), Pull::None);
+ let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard);
+
+ let mut config = spim::Config::default();
+ config.frequency = spim::Frequency::M32;
+ config.mode = spim::MODE_2; // !!!
+ let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config);
+ let spi = ExclusiveDevice::new(spi, cs);
+
+ let (device, mut control, runner) = embassy_net_esp_hosted::new(
+ make_static!(embassy_net_esp_hosted::State::new()),
+ spi,
+ handshake,
+ ready,
+ reset,
+ )
+ .await;
+
+ unwrap!(spawner.spawn(wifi_task(runner)));
+
+ control.init().await;
+ control.join(WIFI_NETWORK, WIFI_PASSWORD).await;
+
+ // Generate random seed
+ let mut rng = Rng::new(p.RNG, Irqs);
+ let mut seed = [0; 8];
+ rng.blocking_fill_bytes(&mut seed);
+ let seed = u64::from_le_bytes(seed);
+
+ // Init network stack
+ let stack = &*make_static!(Stack::new(
+ device,
+ Config::dhcpv4(Default::default()),
+ make_static!(StackResources::<2>::new()),
+ seed
+ ));
+
+ unwrap!(spawner.spawn(net_task(stack)));
+
+ info!("Waiting for DHCP up...");
+ while stack.config_v4().is_none() {
+ Timer::after(Duration::from_millis(100)).await;
+ }
+ info!("IP addressing up!");
+
+ let down = test_download(stack).await;
+ let up = test_upload(stack).await;
+ let updown = test_upload_download(stack).await;
+
+ assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS);
+ assert!(up > TEST_EXPECTED_UPLOAD_KBPS);
+ assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS);
+
+ info!("Test OK");
+ cortex_m::asm::bkpt();
+}
+
+// Test-only wifi network, no internet access!
+const WIFI_NETWORK: &str = "EmbassyTest";
+const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud";
+
+const TEST_DURATION: usize = 10;
+const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 150;
+const TEST_EXPECTED_UPLOAD_KBPS: usize = 150;
+const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150;
+const RX_BUFFER_SIZE: usize = 4096;
+const TX_BUFFER_SIZE: usize = 4096;
+const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2);
+const DOWNLOAD_PORT: u16 = 4321;
+const UPLOAD_PORT: u16 = 4322;
+const UPLOAD_DOWNLOAD_PORT: u16 = 4323;
+
+async fn test_download(stack: &'static Stack) -> usize {
+ info!("Testing download...");
+
+ let mut rx_buffer = [0; RX_BUFFER_SIZE];
+ let mut tx_buffer = [0; TX_BUFFER_SIZE];
+ let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
+ socket.set_timeout(Some(Duration::from_secs(10)));
+
+ info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT);
+ if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await {
+ error!("connect error: {:?}", e);
+ return 0;
+ }
+ info!("connected, testing...");
+
+ let mut rx_buf = [0; 4096];
+ let mut total: usize = 0;
+ with_timeout(Duration::from_secs(TEST_DURATION as _), async {
+ loop {
+ match socket.read(&mut rx_buf).await {
+ Ok(0) => {
+ error!("read EOF");
+ return 0;
+ }
+ Ok(n) => total += n,
+ Err(e) => {
+ error!("read error: {:?}", e);
+ return 0;
+ }
+ }
+ }
+ })
+ .await
+ .ok();
+
+ let kbps = (total + 512) / 1024 / TEST_DURATION;
+ info!("download: {} kB/s", kbps);
+ kbps
+}
+
+async fn test_upload(stack: &'static Stack) -> usize {
+ info!("Testing upload...");
+
+ let mut rx_buffer = [0; RX_BUFFER_SIZE];
+ let mut tx_buffer = [0; TX_BUFFER_SIZE];
+ let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
+ socket.set_timeout(Some(Duration::from_secs(10)));
+
+ info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT);
+ if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await {
+ error!("connect error: {:?}", e);
+ return 0;
+ }
+ info!("connected, testing...");
+
+ let buf = [0; 4096];
+ let mut total: usize = 0;
+ with_timeout(Duration::from_secs(TEST_DURATION as _), async {
+ loop {
+ match socket.write(&buf).await {
+ Ok(0) => {
+ error!("write zero?!??!?!");
+ return 0;
+ }
+ Ok(n) => total += n,
+ Err(e) => {
+ error!("write error: {:?}", e);
+ return 0;
+ }
+ }
+ }
+ })
+ .await
+ .ok();
+
+ let kbps = (total + 512) / 1024 / TEST_DURATION;
+ info!("upload: {} kB/s", kbps);
+ kbps
+}
+
+async fn test_upload_download(stack: &'static Stack) -> usize {
+ info!("Testing upload+download...");
+
+ let mut rx_buffer = [0; RX_BUFFER_SIZE];
+ let mut tx_buffer = [0; TX_BUFFER_SIZE];
+ let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
+ socket.set_timeout(Some(Duration::from_secs(10)));
+
+ info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT);
+ if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await {
+ error!("connect error: {:?}", e);
+ return 0;
+ }
+ info!("connected, testing...");
+
+ let (mut reader, mut writer) = socket.split();
+
+ let tx_buf = [0; 4096];
+ let mut rx_buf = [0; 4096];
+ let mut total: usize = 0;
+ let tx_fut = async {
+ loop {
+ match writer.write(&tx_buf).await {
+ Ok(0) => {
+ error!("write zero?!??!?!");
+ return 0;
+ }
+ Ok(_) => {}
+ Err(e) => {
+ error!("write error: {:?}", e);
+ return 0;
+ }
+ }
+ }
+ };
+
+ let rx_fut = async {
+ loop {
+ match reader.read(&mut rx_buf).await {
+ Ok(0) => {
+ error!("read EOF");
+ return 0;
+ }
+ Ok(n) => total += n,
+ Err(e) => {
+ error!("read error: {:?}", e);
+ return 0;
+ }
+ }
+ }
+ };
+
+ with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut))
+ .await
+ .ok();
+
+ let kbps = (total + 512) / 1024 / TEST_DURATION;
+ info!("upload+download: {} kB/s", kbps);
+ kbps
+}
diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs
index 7a94ea191..9fc537a4b 100644
--- a/tests/rp/src/bin/cyw43-perf.rs
+++ b/tests/rp/src/bin/cyw43-perf.rs
@@ -63,20 +63,13 @@ async fn main(spawner: Spawner) {
.set_power_management(cyw43::PowerManagementMode::PowerSave)
.await;
- let config = Config::dhcpv4(Default::default());
- //let config = embassy_net::Config::Static(embassy_net::Config {
- // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24),
- // dns_servers: Vec::new(),
- // gateway: Some(Ipv4Address::new(192, 168, 69, 1)),
- //});
-
// Generate random seed
let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random.
// Init network stack
let stack = &*make_static!(Stack::new(
net_device,
- config,
+ Config::dhcpv4(Default::default()),
make_static!(StackResources::<2>::new()),
seed
));
From 23c51a18741c4c500c46955b5cd028ec0eb7d53a Mon Sep 17 00:00:00 2001
From: Dietrich Beck
Date: Thu, 22 Jun 2023 23:02:16 +0200
Subject: [PATCH 22/74] disable pull-up and down resistors for rp adc
blocking_read
---
embassy-rp/src/adc.rs | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs
index b96d5a4a8..699a0d61d 100644
--- a/embassy-rp/src/adc.rs
+++ b/embassy-rp/src/adc.rs
@@ -112,8 +112,14 @@ impl<'d> Adc<'d> {
r.result().read().result().into()
}
- pub fn blocking_read, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 {
+ pub fn blocking_read, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 {
let r = Self::regs();
+ pin.pad_ctrl().modify(|w| {
+ w.set_ie(true);
+ let (pu, pd) = (false, false);
+ w.set_pue(pu);
+ w.set_pde(pd);
+ });
r.cs().modify(|w| {
w.set_ainsel(PIN::channel());
w.set_start_once(true)
@@ -166,7 +172,7 @@ impl_pin!(PIN_29, 3);
impl OneShot, WORD, PIN> for Adc<'static>
where
WORD: From,
- PIN: Channel, ID = u8>,
+ PIN: Channel, ID = u8> + Pin,
{
type Error = ();
fn read(&mut self, pin: &mut PIN) -> nb::Result {
From 558247d8f60dbdebf5f3df3a632d9e32fe0f0277 Mon Sep 17 00:00:00 2001
From: GhaithOueslati
Date: Thu, 22 Jun 2023 22:51:38 +0100
Subject: [PATCH 23/74] update hci crate name
---
embassy-stm32-wpan/Cargo.toml | 4 ++--
embassy-stm32-wpan/src/ble.rs | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 3659d7135..2977084ff 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -24,12 +24,12 @@ heapless = "0.7.16"
bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
-bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true }
+stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true }
[features]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
-ble = ["dep:bluetooth-hci-async"]
+ble = ["dep:stm32wb-hci"]
mac = []
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs
index 04acf0aff..619cd66a0 100644
--- a/embassy-stm32-wpan/src/ble.rs
+++ b/embassy-stm32-wpan/src/ble.rs
@@ -63,7 +63,7 @@ impl Ble {
}
}
-pub extern crate bluetooth_hci_async as hci;
+pub extern crate stm32wb_hci as hci;
impl hci::Controller for Ble {
async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) {
From 64ff1a6b75aa13797cf64bb97e597f333a2ae9b6 Mon Sep 17 00:00:00 2001
From: GhaithOueslati
Date: Thu, 22 Jun 2023 22:53:07 +0100
Subject: [PATCH 24/74] update hci crate git path
---
embassy-stm32-wpan/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 2977084ff..ee60a22e5 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -24,7 +24,7 @@ heapless = "0.7.16"
bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
-stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true }
+stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/stm32wb-hci", features = ["version-5-0"], optional = true }
[features]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
From caf63b9e7336ed3ddb0dc997d431f15a26ae7693 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Thu, 22 Jun 2023 21:05:51 -0500
Subject: [PATCH 25/74] stm32/tests: update ble test
---
embassy-stm32-wpan/Cargo.toml | 2 +-
examples/stm32wb/Cargo.toml | 5 +-
examples/stm32wb/src/bin/tl_mbox_mac.rs | 2 +-
tests/stm32/Cargo.toml | 3 +
tests/stm32/src/bin/tl_mbox.rs | 217 +++++++++++++++++++++---
5 files changed, 205 insertions(+), 24 deletions(-)
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index ee60a22e5..6d78ca577 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -24,7 +24,7 @@ heapless = "0.7.16"
bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
-stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/stm32wb-hci", features = ["version-5-0"], optional = true }
+stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true }
[features]
defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"]
diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml
index 726cd10d4..fbb2d918b 100644
--- a/examples/stm32wb/Cargo.toml
+++ b/examples/stm32wb/Cargo.toml
@@ -37,4 +37,7 @@ required-features = ["mac"]
[[bin]]
name = "eddystone_beacon"
-required-features = ["ble"]
\ No newline at end of file
+required-features = ["ble"]
+
+[patch.crates-io]
+stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"}
\ No newline at end of file
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index 6c8653cf4..afd319a41 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) {
let config = Config::default();
let mbox = TlMbox::init(p.IPCC, Irqs, config);
- let sys_event = mbox.sys_subsystem.tl_read().await;
+ let sys_event = mbox.sys_subsystem.read().await;
info!("sys event: {}", sys_event.payload());
mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml
index fe646927a..c2422f7bc 100644
--- a/tests/stm32/Cargo.toml
+++ b/tests/stm32/Cargo.toml
@@ -46,6 +46,9 @@ rand_chacha = { version = "0.3", default-features = false }
chrono = { version = "^0.4", default-features = false, optional = true}
+[patch.crates-io]
+stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"}
+
# BEGIN TESTS
# Generated by gen_test.py. DO NOT EDIT.
[[bin]]
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index f55c0292a..76c736a5b 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -6,43 +6,49 @@
#[path = "../common.rs"]
mod common;
-use core::mem;
+use core::time::Duration;
use common::*;
use embassy_executor::Spawner;
-use embassy_futures::poll_once;
use embassy_stm32::bind_interrupts;
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
+use embassy_stm32_wpan::ble::hci::host::uart::UartHci;
+use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
+use embassy_stm32_wpan::ble::hci::types::AdvertisingType;
+use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{
+ AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
+};
+use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands;
+use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
+use embassy_stm32_wpan::ble::hci::BdAddr;
+use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
use embassy_stm32_wpan::{mm, TlMbox};
-use embassy_time::{Duration, Timer};
+use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs{
IPCC_C1_RX => ReceiveInterruptHandler;
IPCC_C1_TX => TransmitInterruptHandler;
});
+const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7;
+
#[embassy_executor::task]
async fn run_mm_queue(memory_manager: mm::MemoryManager) {
memory_manager.run_queue().await;
}
#[embassy_executor::main]
-async fn main(spawner: Spawner) {
+async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config());
info!("Hello World!");
let config = Config::default();
- let mbox = TlMbox::init(p.IPCC, Irqs, config);
+ let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
- spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
+ // spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
- let ready_event = mbox.sys_subsystem.read().await;
- let _ = poll_once(mbox.sys_subsystem.read()); // clear rx not
-
- info!("sys event {:x} : {:x}", ready_event.stub().kind, ready_event.payload());
-
- // test memory manager
- mem::drop(ready_event);
+ let sys_event = mbox.sys_subsystem.read().await;
+ info!("sys event: {}", sys_event.payload());
let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap();
let version_major = fw_info.version_major();
@@ -57,19 +63,188 @@ async fn main(spawner: Spawner) {
version_major, version_minor, subversion, sram2a_size, sram2b_size
);
- Timer::after(Duration::from_millis(50)).await;
+ mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
- let result = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
- info!("subsystem initialization: {}", result);
+ info!("resetting BLE...");
+ mbox.ble_subsystem.reset().await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
- info!("starting ble...");
- mbox.ble_subsystem.tl_write(0x0c, &[]).await;
+ info!("config public address...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::public_address(get_bd_addr()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
- info!("waiting for ble...");
- let ble_event = mbox.ble_subsystem.tl_read().await;
+ info!("config random address...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::random_address(get_random_addr()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
- info!("ble event {:x} : {:x}", ble_event.stub().kind, ble_event.payload());
+ info!("config identity root...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::identity_root(&get_irk()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("config encryption root...");
+ mbox.ble_subsystem
+ .write_config_data(&ConfigData::encryption_root(&get_erk()).build())
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("config tx power level...");
+ mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("GATT init...");
+ mbox.ble_subsystem.init_gatt().await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("GAP init...");
+ mbox.ble_subsystem
+ .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH)
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ // info!("set scan response...");
+ // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap();
+ // let response = mbox.ble_subsystem.read().await.unwrap();
+ // info!("{}", response);
+
+ info!("set discoverable...");
+ mbox.ble_subsystem
+ .set_discoverable(&DiscoverableParameters {
+ advertising_type: AdvertisingType::NonConnectableUndirected,
+ advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))),
+ address_type: OwnAddressType::Public,
+ filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan,
+ local_name: None,
+ advertising_data: &[],
+ conn_interval: (None, None),
+ })
+ .await
+ .unwrap();
+
+ let response = mbox.ble_subsystem.read().await;
+ info!("{}", response);
+
+ // remove some advertisement to decrease the packet size
+ info!("delete tx power ad type...");
+ mbox.ble_subsystem
+ .delete_ad_type(AdvertisingDataType::TxPowerLevel)
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("delete conn interval ad type...");
+ mbox.ble_subsystem
+ .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval)
+ .await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("update advertising data...");
+ mbox.ble_subsystem
+ .update_advertising_data(&eddystone_advertising_data())
+ .await
+ .unwrap();
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("update advertising data type...");
+ mbox.ble_subsystem
+ .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe])
+ .await
+ .unwrap();
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
+
+ info!("update advertising data flags...");
+ mbox.ble_subsystem
+ .update_advertising_data(&[
+ 2,
+ AdvertisingDataType::Flags as u8,
+ (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support
+ ])
+ .await
+ .unwrap();
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ info!("{}", response);
info!("Test OK");
cortex_m::asm::bkpt();
}
+
+fn get_bd_addr() -> BdAddr {
+ let mut bytes = [0u8; 6];
+
+ let lhci_info = LhciC1DeviceInformationCcrp::new();
+ bytes[0] = (lhci_info.uid64 & 0xff) as u8;
+ bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
+ bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
+ bytes[3] = lhci_info.device_type_id;
+ bytes[4] = (lhci_info.st_company_id & 0xff) as u8;
+ bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8;
+
+ BdAddr(bytes)
+}
+
+fn get_random_addr() -> BdAddr {
+ let mut bytes = [0u8; 6];
+
+ let lhci_info = LhciC1DeviceInformationCcrp::new();
+ bytes[0] = (lhci_info.uid64 & 0xff) as u8;
+ bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8;
+ bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8;
+ bytes[3] = 0;
+ bytes[4] = 0x6E;
+ bytes[5] = 0xED;
+
+ BdAddr(bytes)
+}
+
+const BLE_CFG_IRK: [u8; 16] = [
+ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0,
+];
+const BLE_CFG_ERK: [u8; 16] = [
+ 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21,
+];
+
+fn get_irk() -> EncryptionKey {
+ EncryptionKey(BLE_CFG_IRK)
+}
+
+fn get_erk() -> EncryptionKey {
+ EncryptionKey(BLE_CFG_ERK)
+}
+
+fn eddystone_advertising_data() -> [u8; 24] {
+ const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com";
+
+ let mut service_data = [0u8; 24];
+ let url_len = EDDYSTONE_URL.len();
+
+ service_data[0] = 6 + url_len as u8;
+ service_data[1] = AdvertisingDataType::ServiceData as u8;
+
+ // 16-bit eddystone uuid
+ service_data[2] = 0xaa;
+ service_data[3] = 0xFE;
+
+ service_data[4] = 0x10; // URL frame type
+ service_data[5] = 22_i8 as u8; // calibrated TX power at 0m
+ service_data[6] = 0x03; // eddystone url prefix = https
+
+ service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL);
+
+ service_data
+}
From ea04a0277bb19719188e904a86e28c34f9801c96 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Fri, 23 Jun 2023 12:14:26 +0200
Subject: [PATCH 26/74] change dma complete transfer IR default to true
---
embassy-stm32/src/dma/bdma.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs
index 32b75bb68..5a87888b7 100644
--- a/embassy-stm32/src/dma/bdma.rs
+++ b/embassy-stm32/src/dma/bdma.rs
@@ -35,7 +35,7 @@ impl Default for TransferOptions {
Self {
circular: false,
half_transfer_ir: false,
- complete_transfer_ir: false,
+ complete_transfer_ir: true,
}
}
}
From 915f79c974ace037e914397b42eb9d2448bd5ca3 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Fri, 23 Jun 2023 12:14:40 +0200
Subject: [PATCH 27/74] allow independent use of ch1 and ch2 on dac
---
embassy-stm32/src/dac/mod.rs | 152 +++++++++++++++++++++++------------
1 file changed, 101 insertions(+), 51 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 42646d20d..5b39758bf 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -22,7 +22,7 @@ pub enum Channel {
}
impl Channel {
- fn index(&self) -> usize {
+ const fn index(&self) -> usize {
match self {
Channel::Ch1 => 0,
Channel::Ch2 => 1,
@@ -109,72 +109,100 @@ pub enum ValueArray<'a> {
}
pub struct Dac<'d, T: Instance, Tx> {
- channels: u8,
+ ch1: bool,
+ ch2: bool,
txdma: PeripheralRef<'d, Tx>,
_peri: PeripheralRef<'d, T>,
}
impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
- /// Create a new instance with one channel
- pub fn new_1ch(
+ pub fn new_ch1(
peri: impl Peripheral + 'd,
txdma: impl Peripheral
+ 'd,
_ch1: impl Peripheral
> + 'd,
) -> Self {
into_ref!(peri);
- Self::new_inner(peri, 1, txdma)
+ Self::new_inner(peri, true, false, txdma)
}
- /// Create a new instance with two channels
- pub fn new_2ch(
+ pub fn new_ch2(
+ peri: impl Peripheral
+ 'd,
+ txdma: impl Peripheral
+ 'd,
+ _ch2: impl Peripheral
> + 'd,
+ ) -> Self {
+ into_ref!(peri);
+ Self::new_inner(peri, false, true, txdma)
+ }
+
+ pub fn new_ch1_and_ch2(
peri: impl Peripheral
+ 'd,
txdma: impl Peripheral
+ 'd,
_ch1: impl Peripheral
> + 'd,
_ch2: impl Peripheral
> + 'd,
) -> Self {
into_ref!(peri);
- Self::new_inner(peri, 2, txdma)
+ Self::new_inner(peri, true, true, txdma)
}
/// Perform initialisation steps for the DAC
- fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral
+ 'd) -> Self {
+ fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral
+ 'd) -> Self {
into_ref!(txdma);
T::enable();
T::reset();
- T::regs().mcr().modify(|reg| {
- for ch in 0..channels {
- reg.set_mode(ch as usize, 0);
- reg.set_mode(ch as usize, 0);
- }
- });
-
- T::regs().cr().modify(|reg| {
- for ch in 0..channels {
- reg.set_en(ch as usize, true);
- reg.set_ten(ch as usize, true);
- }
- });
-
- Self {
- channels,
+ let mut dac = Self {
+ ch1,
+ ch2,
txdma,
_peri: peri,
+ };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ if ch1 {
+ dac.set_channel_mode(Channel::Ch1, 0).unwrap();
+ dac.enable_channel(Channel::Ch1).unwrap();
+ dac.set_trigger_enable(Channel::Ch1, true).unwrap();
}
+ if ch2 {
+ dac.set_channel_mode(Channel::Ch2, 0).unwrap();
+ dac.enable_channel(Channel::Ch2).unwrap();
+ dac.set_trigger_enable(Channel::Ch2, true).unwrap();
+ }
+
+ dac
}
/// Check the channel is configured
- fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
- if ch == Channel::Ch2 && self.channels < 2 {
+ fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> {
+ if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) {
Err(Error::UnconfiguredChannel)
} else {
Ok(())
}
}
- /// Set the enable register of the given channel
+ /// Enable trigger of the given channel
+ fn set_trigger_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
+ self.check_channel_configured(ch)?;
+ T::regs().cr().modify(|reg| {
+ reg.set_ten(ch.index(), on);
+ });
+ Ok(())
+ }
+
+ /// Set mode register of the given channel
+ fn set_channel_mode(&mut self, ch: Channel, val: u8) -> Result<(), Error> {
+ self.check_channel_configured(ch)?;
+ T::regs().mcr().modify(|reg| {
+ reg.set_mode(ch.index(), val);
+ });
+ Ok(())
+ }
+
+ /// Set enable register of the given channel
fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
- self.check_channel_exists(ch)?;
+ self.check_channel_configured(ch)?;
T::regs().cr().modify(|reg| {
reg.set_en(ch.index(), on);
});
@@ -193,7 +221,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
/// Select a new trigger for CH1 (disables the channel)
pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
- self.check_channel_exists(Channel::Ch1)?;
+ self.check_channel_configured(Channel::Ch1)?;
unwrap!(self.disable_channel(Channel::Ch1));
T::regs().cr().modify(|reg| {
reg.set_tsel1(trigger.tsel());
@@ -203,7 +231,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
/// Select a new trigger for CH2 (disables the channel)
pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
- self.check_channel_exists(Channel::Ch2)?;
+ self.check_channel_configured(Channel::Ch2)?;
unwrap!(self.disable_channel(Channel::Ch2));
T::regs().cr().modify(|reg| {
reg.set_tsel2(trigger.tsel());
@@ -213,7 +241,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
/// Perform a software trigger on `ch`
pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
- self.check_channel_exists(ch)?;
+ self.check_channel_configured(ch)?;
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(ch.index(), true);
});
@@ -232,7 +260,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
///
/// The `value` is written to the corresponding "data holding register"
pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
- self.check_channel_exists(ch)?;
+ self.check_channel_configured(ch)?;
match value {
Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
@@ -241,39 +269,61 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
Ok(())
}
- /// Write `data` to the DAC via DMA.
+ /// Write `data` to the DAC CH1 via DMA.
///
/// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
/// This will configure a circular DMA transfer that periodically outputs the `data`.
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
- /// ## Current limitations
- /// - Only CH1 Supported
- ///
- pub async fn write(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ /// **Important:** Channel 1 has to be configured for the DAC instance!
+ pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
- // TODO: Make this a parameter or get it from the struct or so...
- const CHANNEL: usize = 0;
+ self.check_channel_configured(Channel::Ch1)?;
+ self.write_inner(data, circular, Channel::Ch1).await
+ }
+
+ /// Write `data` to the DAC CH2 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 2 has to be configured for the DAC instance!
+ pub async fn write_ch2(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ self.check_channel_configured(Channel::Ch2)?;
+ self.write_inner(data, circular, Channel::Ch2).await
+ }
+
+ /// Performs the dma write for the given channel.
+ /// TODO: Should self be &mut?
+ async fn write_inner(&self, data_ch1: ValueArray<'_>, circular: bool, channel: Channel) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ let channel = channel.index();
// Enable DAC and DMA
T::regs().cr().modify(|w| {
- w.set_en(CHANNEL, true);
- w.set_dmaen(CHANNEL, true);
+ w.set_en(channel, true);
+ w.set_dmaen(channel, true);
});
let tx_request = self.txdma.request();
- let channel = &self.txdma;
+ let dma_channel = &self.txdma;
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data_ch1 {
ValueArray::Bit8(buf) => unsafe {
Transfer::new_write(
- channel,
+ dma_channel,
tx_request,
buf,
- T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8,
+ T::regs().dhr8r(channel).as_ptr() as *mut u8,
TransferOptions {
circular,
half_transfer_ir: false,
@@ -283,10 +333,10 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
},
ValueArray::Bit12Left(buf) => unsafe {
Transfer::new_write(
- channel,
+ dma_channel,
tx_request,
buf,
- T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16,
+ T::regs().dhr12l(channel).as_ptr() as *mut u16,
TransferOptions {
circular,
half_transfer_ir: false,
@@ -296,10 +346,10 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
},
ValueArray::Bit12Right(buf) => unsafe {
Transfer::new_write(
- channel,
+ dma_channel,
tx_request,
buf,
- T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16,
+ T::regs().dhr12r(channel).as_ptr() as *mut u16,
TransferOptions {
circular,
half_transfer_ir: false,
@@ -315,9 +365,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
// TODO: Do we need to check any status registers here?
T::regs().cr().modify(|w| {
// Disable the DAC peripheral
- w.set_en(CHANNEL, false);
+ w.set_en(channel, false);
// Disable the DMA. TODO: Is this necessary?
- w.set_dmaen(CHANNEL, false);
+ w.set_dmaen(channel, false);
});
Ok(())
From 29f32ce00ec0f50ef5e3b29c7e50f7f5479b4967 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 17:54:06 -0500
Subject: [PATCH 28/74] stm32/wpan: reorg subsystems
---
embassy-stm32-wpan/src/evt.rs | 4 +--
embassy-stm32-wpan/src/lhci.rs | 8 +++---
embassy-stm32-wpan/src/lib.rs | 26 +++++++++-----------
embassy-stm32-wpan/src/{ => sub}/ble.rs | 0
embassy-stm32-wpan/src/{ => sub}/mac.rs | 0
embassy-stm32-wpan/src/{ => sub}/mm.rs | 0
embassy-stm32-wpan/src/sub/mod.rs | 6 +++++
embassy-stm32-wpan/src/{ => sub}/sys.rs | 0
examples/stm32wb/src/bin/eddystone_beacon.rs | 14 +++++------
tests/stm32/src/bin/tl_mbox.rs | 17 +++++++------
10 files changed, 41 insertions(+), 34 deletions(-)
rename embassy-stm32-wpan/src/{ => sub}/ble.rs (100%)
rename embassy-stm32-wpan/src/{ => sub}/mac.rs (100%)
rename embassy-stm32-wpan/src/{ => sub}/mm.rs (100%)
create mode 100644 embassy-stm32-wpan/src/sub/mod.rs
rename embassy-stm32-wpan/src/{ => sub}/sys.rs (100%)
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs
index 25249a13a..22f089037 100644
--- a/embassy-stm32-wpan/src/evt.rs
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -145,14 +145,14 @@ impl Drop for EvtBox {
fn drop(&mut self) {
#[cfg(feature = "ble")]
unsafe {
- use crate::mm;
+ use crate::sub::mm;
mm::MemoryManager::drop_event_packet(self.ptr)
};
#[cfg(feature = "mac")]
unsafe {
- use crate::mac;
+ use crate::sub::mac;
mac::Mac::drop_event_packet(self.ptr)
}
diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs
index 62116a695..284103705 100644
--- a/embassy-stm32-wpan/src/lhci.rs
+++ b/embassy-stm32-wpan/src/lhci.rs
@@ -1,7 +1,9 @@
+use core::ptr;
+
use crate::cmd::CmdPacket;
use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE};
use crate::evt::{CcEvt, EvtPacket, EvtSerial};
-use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable};
+use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE};
use crate::TL_REF_TABLE;
const TL_BLEEVT_CC_OPCODE: u8 = 0x0e;
@@ -38,7 +40,7 @@ impl Default for LhciC1DeviceInformationCcrp {
safe_boot_info_table,
rss_info_table,
wireless_fw_info_table,
- } = unsafe { &*(*TL_REF_TABLE.as_ptr()).device_info_table }.clone();
+ } = unsafe { ptr::read_volatile(TL_DEVICE_INFO_TABLE.as_ptr()) };
let device_id = stm32_device_signature::device_id();
let uid96_0 = (device_id[3] as u32) << 24
@@ -105,7 +107,7 @@ impl LhciC1DeviceInformationCcrp {
let self_ptr: *const LhciC1DeviceInformationCcrp = self;
let self_buf = self_ptr.cast();
- core::ptr::copy(self_buf, evt_cc_payload_buf, self_size);
+ ptr::copy(self_buf, evt_cc_payload_buf, self_size);
}
}
}
diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs
index bf0f0466e..99c610583 100644
--- a/embassy-stm32-wpan/src/lib.rs
+++ b/embassy-stm32-wpan/src/lib.rs
@@ -11,26 +11,24 @@ use embassy_hal_common::{into_ref, Peripheral, PeripheralRef};
use embassy_stm32::interrupt;
use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler};
use embassy_stm32::peripherals::IPCC;
-use mm::MemoryManager;
-use sys::Sys;
+use sub::mm::MemoryManager;
+use sub::sys::Sys;
use tables::*;
use unsafe_linked_list::LinkedListNode;
-#[cfg(feature = "ble")]
-pub mod ble;
pub mod channels;
pub mod cmd;
pub mod consts;
pub mod evt;
pub mod lhci;
-#[cfg(feature = "mac")]
-pub mod mac;
-pub mod mm;
pub mod shci;
-pub mod sys;
+pub mod sub;
pub mod tables;
pub mod unsafe_linked_list;
+#[cfg(feature = "ble")]
+pub use crate::sub::ble::hci;
+
type PacketHeader = LinkedListNode;
pub struct TlMbox<'d> {
@@ -39,9 +37,9 @@ pub struct TlMbox<'d> {
pub sys_subsystem: Sys,
pub mm_subsystem: MemoryManager,
#[cfg(feature = "ble")]
- pub ble_subsystem: ble::Ble,
+ pub ble_subsystem: sub::ble::Ble,
#[cfg(feature = "mac")]
- pub mac_subsystem: mac::Mac,
+ pub mac_subsystem: sub::mac::Mac,
}
impl<'d> TlMbox<'d> {
@@ -128,12 +126,12 @@ impl<'d> TlMbox<'d> {
Self {
_ipcc: ipcc,
- sys_subsystem: sys::Sys::new(),
+ sys_subsystem: sub::sys::Sys::new(),
#[cfg(feature = "ble")]
- ble_subsystem: ble::Ble::new(),
+ ble_subsystem: sub::ble::Ble::new(),
#[cfg(feature = "mac")]
- mac_subsystem: mac::Mac::new(),
- mm_subsystem: mm::MemoryManager::new(),
+ mac_subsystem: sub::mac::Mac::new(),
+ mm_subsystem: sub::mm::MemoryManager::new(),
}
}
}
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs
similarity index 100%
rename from embassy-stm32-wpan/src/ble.rs
rename to embassy-stm32-wpan/src/sub/ble.rs
diff --git a/embassy-stm32-wpan/src/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
similarity index 100%
rename from embassy-stm32-wpan/src/mac.rs
rename to embassy-stm32-wpan/src/sub/mac.rs
diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs
similarity index 100%
rename from embassy-stm32-wpan/src/mm.rs
rename to embassy-stm32-wpan/src/sub/mm.rs
diff --git a/embassy-stm32-wpan/src/sub/mod.rs b/embassy-stm32-wpan/src/sub/mod.rs
new file mode 100644
index 000000000..bee3dbdf1
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mod.rs
@@ -0,0 +1,6 @@
+#[cfg(feature = "ble")]
+pub mod ble;
+#[cfg(feature = "mac")]
+pub mod mac;
+pub mod mm;
+pub mod sys;
diff --git a/embassy-stm32-wpan/src/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
similarity index 100%
rename from embassy-stm32-wpan/src/sys.rs
rename to embassy-stm32-wpan/src/sub/sys.rs
diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs
index fdd5be4a2..b99f8cb2e 100644
--- a/examples/stm32wb/src/bin/eddystone_beacon.rs
+++ b/examples/stm32wb/src/bin/eddystone_beacon.rs
@@ -8,15 +8,15 @@ use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::bind_interrupts;
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
-use embassy_stm32_wpan::ble::hci::host::uart::UartHci;
-use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
-use embassy_stm32_wpan::ble::hci::types::AdvertisingType;
-use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{
+use embassy_stm32_wpan::hci::host::uart::UartHci;
+use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
+use embassy_stm32_wpan::hci::types::AdvertisingType;
+use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
};
-use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands;
-use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
-use embassy_stm32_wpan::ble::hci::BdAddr;
+use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands;
+use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
+use embassy_stm32_wpan::hci::BdAddr;
use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
use embassy_stm32_wpan::TlMbox;
use {defmt_rtt as _, panic_probe as _};
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index 76c736a5b..8880554de 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -12,17 +12,18 @@ use common::*;
use embassy_executor::Spawner;
use embassy_stm32::bind_interrupts;
use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler};
-use embassy_stm32_wpan::ble::hci::host::uart::UartHci;
-use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
-use embassy_stm32_wpan::ble::hci::types::AdvertisingType;
-use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{
+use embassy_stm32_wpan::hci::host::uart::UartHci;
+use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType};
+use embassy_stm32_wpan::hci::types::AdvertisingType;
+use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{
AdvertisingDataType, DiscoverableParameters, GapCommands, Role,
};
-use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands;
-use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
-use embassy_stm32_wpan::ble::hci::BdAddr;
+use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands;
+use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel};
+use embassy_stm32_wpan::hci::BdAddr;
use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp;
-use embassy_stm32_wpan::{mm, TlMbox};
+use embassy_stm32_wpan::sub::mm;
+use embassy_stm32_wpan::TlMbox;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs{
From f23b34951a20f569997bbe028048f3943d7e4c56 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 17:55:47 -0500
Subject: [PATCH 29/74] rustfmt
---
embassy-stm32-wpan/src/lhci.rs | 1 -
1 file changed, 1 deletion(-)
diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs
index 284103705..89f204f99 100644
--- a/embassy-stm32-wpan/src/lhci.rs
+++ b/embassy-stm32-wpan/src/lhci.rs
@@ -4,7 +4,6 @@ use crate::cmd::CmdPacket;
use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE};
use crate::evt::{CcEvt, EvtPacket, EvtSerial};
use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE};
-use crate::TL_REF_TABLE;
const TL_BLEEVT_CC_OPCODE: u8 = 0x0e;
const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62;
From 91fdd76053c747c569b0eefe0715522465fe0194 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 18:08:42 -0500
Subject: [PATCH 30/74] stm32/wpan: use align to align data
---
embassy-stm32-wpan/Cargo.toml | 1 +
embassy-stm32-wpan/src/tables.rs | 34 ++++++++++++--------------------
2 files changed, 14 insertions(+), 21 deletions(-)
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 6d78ca577..4b830cab3 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -21,6 +21,7 @@ embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" }
defmt = { version = "0.3", optional = true }
cortex-m = "0.7.6"
heapless = "0.7.16"
+aligned = "0.4.1"
bit_field = "0.10.2"
stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] }
diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs
index 3f26282c6..1b5dcdf2e 100644
--- a/embassy-stm32-wpan/src/tables.rs
+++ b/embassy-stm32-wpan/src/tables.rs
@@ -1,5 +1,6 @@
use core::mem::MaybeUninit;
+use aligned::{Aligned, A4};
use bit_field::BitField;
use crate::cmd::{AclDataPacket, CmdPacket};
@@ -164,9 +165,6 @@ pub struct Mac802_15_4Table {
pub evt_queue: *const u8,
}
-#[repr(C, align(4))]
-pub struct AlignedData([u8; L]);
-
/// Reference table. Contains pointers to all other tables.
#[derive(Debug, Copy, Clone)]
#[repr(C)]
@@ -222,10 +220,9 @@ pub static mut FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit
#[link_section = "MB_MEM1"]
pub static mut TRACES_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit();
-const CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
-
#[link_section = "MB_MEM2"]
-pub static mut CS_BUFFER: MaybeUninit> = MaybeUninit::uninit();
+pub static mut CS_BUFFER: MaybeUninit> =
+ MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
pub static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit();
@@ -238,35 +235,30 @@ pub static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::unin
#[link_section = "MB_MEM2"]
pub static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit();
-#[cfg(feature = "mac")]
-const MAC_802_15_4_NOTIF_RSP_EVT_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255;
-
#[cfg(feature = "mac")]
#[link_section = "MB_MEM2"]
-pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit> =
- MaybeUninit::uninit();
+pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit<
+ Aligned,
+> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
-pub static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit();
+pub static mut EVT_POOL: MaybeUninit> = MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
pub static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit();
-const SYS_SPARE_EVT_BUF_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255;
-
#[link_section = "MB_MEM2"]
-pub static mut SYS_SPARE_EVT_BUF: MaybeUninit> = MaybeUninit::uninit();
+pub static mut SYS_SPARE_EVT_BUF: MaybeUninit> =
+ MaybeUninit::uninit();
#[link_section = "MB_MEM1"]
pub static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit();
-const BLE_SPARE_EVT_BUF_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255;
-
#[link_section = "MB_MEM2"]
-pub static mut BLE_SPARE_EVT_BUF: MaybeUninit> = MaybeUninit::uninit();
-
-const HCI_ACL_DATA_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + 5 + 251;
+pub static mut BLE_SPARE_EVT_BUF: MaybeUninit> =
+ MaybeUninit::uninit();
#[link_section = "MB_MEM2"]
// fuck these "magic" numbers from ST ---v---v
-pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; HCI_ACL_DATA_BUFFER_SIZE]> = MaybeUninit::uninit();
+pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit> =
+ MaybeUninit::uninit();
From d43417e97c4de487b4ebf018830825e034c5394e Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 19:59:48 -0500
Subject: [PATCH 31/74] stm32/wpan: implement mm pattern
---
embassy-stm32-wpan/src/consts.rs | 4 +++
embassy-stm32-wpan/src/evt.rs | 33 ++++++++-------------
embassy-stm32-wpan/src/sub/ble.rs | 25 +++++++++++++---
embassy-stm32-wpan/src/sub/mac.rs | 48 ++++++++++++++++---------------
embassy-stm32-wpan/src/sub/mm.rs | 23 ++++++++-------
embassy-stm32-wpan/src/sub/sys.rs | 3 +-
tests/stm32/src/bin/tl_mbox.rs | 4 +--
7 files changed, 78 insertions(+), 62 deletions(-)
diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs
index 9a107306c..f234151d7 100644
--- a/embassy-stm32-wpan/src/consts.rs
+++ b/embassy-stm32-wpan/src/consts.rs
@@ -87,3 +87,7 @@ pub const fn divc(x: usize, y: usize) -> usize {
pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE;
#[allow(dead_code)]
pub const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE;
+
+pub const TL_BLEEVT_CC_OPCODE: u8 = 0x0E;
+pub const TL_BLEEVT_CS_OPCODE: u8 = 0x0F;
+pub const TL_BLEEVT_VS_OPCODE: u8 = 0xFF;
diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs
index 22f089037..c6528413d 100644
--- a/embassy-stm32-wpan/src/evt.rs
+++ b/embassy-stm32-wpan/src/evt.rs
@@ -1,3 +1,4 @@
+use core::marker::PhantomData;
use core::{ptr, slice};
use super::PacketHeader;
@@ -93,17 +94,22 @@ impl EvtPacket {
}
}
+pub trait MemoryManager {
+ unsafe fn drop_event_packet(evt: *mut EvtPacket);
+}
+
/// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically
/// on [`Drop`]
#[derive(Debug)]
-pub struct EvtBox {
+pub struct EvtBox {
ptr: *mut EvtPacket,
+ mm: PhantomData,
}
-unsafe impl Send for EvtBox {}
-impl EvtBox {
+unsafe impl Send for EvtBox {}
+impl EvtBox {
pub(super) fn new(ptr: *mut EvtPacket) -> Self {
- Self { ptr }
+ Self { ptr, mm: PhantomData }
}
/// Returns information about the event
@@ -126,9 +132,6 @@ impl EvtBox {
}
}
- /// writes an underlying [`EvtPacket`] into the provided buffer.
- /// Returns the number of bytes that were written.
- /// Returns an error if event kind is unknown or if provided buffer size is not enough.
pub fn serial<'a>(&'a self) -> &'a [u8] {
unsafe {
let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial;
@@ -141,20 +144,8 @@ impl EvtBox {
}
}
-impl Drop for EvtBox {
+impl Drop for EvtBox {
fn drop(&mut self) {
- #[cfg(feature = "ble")]
- unsafe {
- use crate::sub::mm;
-
- mm::MemoryManager::drop_event_packet(self.ptr)
- };
-
- #[cfg(feature = "mac")]
- unsafe {
- use crate::sub::mac;
-
- mac::Mac::drop_event_packet(self.ptr)
- }
+ unsafe { T::drop_event_packet(self.ptr) };
}
}
diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs
index 619cd66a0..cd32692e1 100644
--- a/embassy-stm32-wpan/src/sub/ble.rs
+++ b/embassy-stm32-wpan/src/sub/ble.rs
@@ -1,14 +1,16 @@
use core::marker::PhantomData;
+use core::ptr;
use embassy_stm32::ipcc::Ipcc;
use hci::Opcode;
-use crate::channels;
use crate::cmd::CmdPacket;
-use crate::consts::TlPacketType;
-use crate::evt::EvtBox;
+use crate::consts::{TlPacketType, TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE};
+use crate::evt::{EvtBox, EvtPacket, EvtStub};
+use crate::sub::mm;
use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
use crate::unsafe_linked_list::LinkedListNode;
+use crate::{channels, evt};
pub struct Ble {
phantom: PhantomData,
@@ -30,7 +32,7 @@ impl Ble {
Self { phantom: PhantomData }
}
/// `HW_IPCC_BLE_EvtNot`
- pub async fn tl_read(&self) -> EvtBox {
+ pub async fn tl_read(&self) -> EvtBox {
Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe {
if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) {
Some(EvtBox::new(node_ptr.cast()))
@@ -63,6 +65,21 @@ impl Ble {
}
}
+impl evt::MemoryManager for Ble {
+ /// SAFETY: passing a pointer to something other than a managed event packet is UB
+ unsafe fn drop_event_packet(evt: *mut EvtPacket) {
+ let stub = unsafe {
+ let p_evt_stub = &(*evt).evt_serial as *const _ as *const EvtStub;
+
+ ptr::read_volatile(p_evt_stub)
+ };
+
+ if !(stub.evt_code == TL_BLEEVT_CS_OPCODE || stub.evt_code == TL_BLEEVT_CC_OPCODE) {
+ mm::MemoryManager::drop_event_packet(evt);
+ }
+ }
+}
+
pub extern crate stm32wb_hci as hci;
impl hci::Controller for Ble {
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
index d2be1b85c..fd8af8609 100644
--- a/embassy-stm32-wpan/src/sub/mac.rs
+++ b/embassy-stm32-wpan/src/sub/mac.rs
@@ -8,13 +8,13 @@ use embassy_futures::poll_once;
use embassy_stm32::ipcc::Ipcc;
use embassy_sync::waitqueue::AtomicWaker;
-use crate::channels;
use crate::cmd::CmdPacket;
use crate::consts::TlPacketType;
use crate::evt::{EvtBox, EvtPacket};
use crate::tables::{
Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE,
};
+use crate::{channels, evt};
static MAC_WAKER: AtomicWaker = AtomicWaker::new();
static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
@@ -36,31 +36,10 @@ impl Mac {
Self { phantom: PhantomData }
}
- /// SAFETY: passing a pointer to something other than a managed event packet is UB
- pub(crate) unsafe fn drop_event_packet(_: *mut EvtPacket) {
- // Write the ack
- CmdPacket::write_into(
- MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _,
- TlPacketType::OtAck,
- 0,
- &[],
- );
-
- // Clear the rx flag
- let _ = poll_once(Ipcc::receive::(
- channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL,
- || None,
- ));
-
- // Allow a new read call
- MAC_EVT_OUT.store(false, Ordering::SeqCst);
- MAC_WAKER.wake();
- }
-
/// `HW_IPCC_MAC_802_15_4_EvtNot`
///
/// This function will stall if the previous `EvtBox` has not been dropped
- pub async fn read(&self) -> EvtBox {
+ pub async fn read(&self) -> EvtBox {
// Wait for the last event box to be dropped
poll_fn(|cx| {
MAC_WAKER.register(cx.waker());
@@ -109,3 +88,26 @@ impl Mac {
.await;
}
}
+
+impl evt::MemoryManager for Mac {
+ /// SAFETY: passing a pointer to something other than a managed event packet is UB
+ unsafe fn drop_event_packet(_: *mut EvtPacket) {
+ // Write the ack
+ CmdPacket::write_into(
+ MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _,
+ TlPacketType::OtAck,
+ 0,
+ &[],
+ );
+
+ // Clear the rx flag
+ let _ = poll_once(Ipcc::receive::(
+ channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL,
+ || None,
+ ));
+
+ // Allow a new read call
+ MAC_EVT_OUT.store(false, Ordering::SeqCst);
+ MAC_WAKER.wake();
+ }
+}
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs
index 047fddcd4..1f2ecac2e 100644
--- a/embassy-stm32-wpan/src/sub/mm.rs
+++ b/embassy-stm32-wpan/src/sub/mm.rs
@@ -8,13 +8,13 @@ use cortex_m::interrupt;
use embassy_stm32::ipcc::Ipcc;
use embassy_sync::waitqueue::AtomicWaker;
-use crate::channels;
use crate::consts::POOL_SIZE;
use crate::evt::EvtPacket;
use crate::tables::{
MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE,
};
use crate::unsafe_linked_list::LinkedListNode;
+use crate::{channels, evt};
static MM_WAKER: AtomicWaker = AtomicWaker::new();
static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit();
@@ -43,16 +43,6 @@ impl MemoryManager {
Self { phantom: PhantomData }
}
- #[allow(dead_code)]
- /// SAFETY: passing a pointer to something other than a managed event packet is UB
- pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) {
- interrupt::free(|_| unsafe {
- LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
- });
-
- MM_WAKER.wake();
- }
-
pub async fn run_queue(&self) {
loop {
poll_fn(|cx| unsafe {
@@ -77,3 +67,14 @@ impl MemoryManager {
}
}
}
+
+impl evt::MemoryManager for MemoryManager {
+ /// SAFETY: passing a pointer to something other than a managed event packet is UB
+ unsafe fn drop_event_packet(evt: *mut EvtPacket) {
+ interrupt::free(|_| unsafe {
+ LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _);
+ });
+
+ MM_WAKER.wake();
+ }
+}
diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
index 2b699b725..af652860d 100644
--- a/embassy-stm32-wpan/src/sub/sys.rs
+++ b/embassy-stm32-wpan/src/sub/sys.rs
@@ -6,6 +6,7 @@ use crate::consts::TlPacketType;
use crate::evt::{CcEvt, EvtBox, EvtPacket};
#[allow(unused_imports)]
use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode};
+use crate::sub::mm;
use crate::tables::{SysTable, WirelessFwInfoTable};
use crate::unsafe_linked_list::LinkedListNode;
use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE};
@@ -73,7 +74,7 @@ impl Sys {
}
/// `HW_IPCC_SYS_EvtNot`
- pub async fn read(&self) -> EvtBox {
+ pub async fn read(&self) -> EvtBox {
Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe {
if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) {
Some(EvtBox::new(node_ptr.cast()))
diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs
index 8880554de..af3832709 100644
--- a/tests/stm32/src/bin/tl_mbox.rs
+++ b/tests/stm32/src/bin/tl_mbox.rs
@@ -39,14 +39,14 @@ async fn run_mm_queue(memory_manager: mm::MemoryManager) {
}
#[embassy_executor::main]
-async fn main(_spawner: Spawner) {
+async fn main(spawner: Spawner) {
let p = embassy_stm32::init(config());
info!("Hello World!");
let config = Config::default();
let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
- // spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
+ spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
let sys_event = mbox.sys_subsystem.read().await;
info!("sys event: {}", sys_event.payload());
From 49333ce6adf28ff6c3eb1a632c0d4860379ef3ef Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 20:09:13 -0500
Subject: [PATCH 32/74] stm32/wpan: move linker file into pkg
---
embassy-stm32-wpan/build.rs | 13 ++++++++++++-
{embassy-stm32 => embassy-stm32-wpan}/tl_mbox.x.in | 0
embassy-stm32/build.rs | 10 ----------
3 files changed, 12 insertions(+), 11 deletions(-)
rename {embassy-stm32 => embassy-stm32-wpan}/tl_mbox.x.in (100%)
diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs
index 4edf73d59..94aac070d 100644
--- a/embassy-stm32-wpan/build.rs
+++ b/embassy-stm32-wpan/build.rs
@@ -1,4 +1,5 @@
-use std::env;
+use std::path::PathBuf;
+use std::{env, fs};
fn main() {
match env::vars()
@@ -10,6 +11,16 @@ fn main() {
Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"),
Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"),
}
+
+ let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
+
+ // ========
+ // stm32wb tl_mbox link sections
+
+ let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
+ fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap();
+ println!("cargo:rustc-link-search={}", out_dir.display());
+ println!("cargo:rerun-if-changed=tl_mbox.x.in");
}
enum GetOneError {
diff --git a/embassy-stm32/tl_mbox.x.in b/embassy-stm32-wpan/tl_mbox.x.in
similarity index 100%
rename from embassy-stm32/tl_mbox.x.in
rename to embassy-stm32-wpan/tl_mbox.x.in
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index f71074bcf..40103d322 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -911,16 +911,6 @@ fn main() {
println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]);
}
- // ========
- // stm32wb tl_mbox link sections
-
- if chip_name.starts_with("stm32wb") {
- let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
- fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap();
- println!("cargo:rustc-link-search={}", out_dir.display());
- println!("cargo:rerun-if-changed=tl_mbox.x.in");
- }
-
// =======
// Features for targeting groups of chips
From 388d3e273d3d003e6a058b4bad9e2517dd33d626 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Sat, 24 Jun 2023 13:10:59 +0200
Subject: [PATCH 33/74] first attempt at fixing the 2nd channel problem
---
embassy-stm32/src/dac/mod.rs | 386 +++++++++++++++++++++--------------
1 file changed, 234 insertions(+), 152 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 5b39758bf..e87292b86 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -1,5 +1,7 @@
#![macro_use]
+use core::marker::PhantomData;
+
use embassy_hal_common::{into_ref, PeripheralRef};
use crate::dma::{Transfer, TransferOptions};
@@ -108,166 +110,108 @@ pub enum ValueArray<'a> {
Bit12Right(&'a [u16]),
}
-pub struct Dac<'d, T: Instance, Tx> {
- ch1: bool,
- ch2: bool,
- txdma: PeripheralRef<'d, Tx>,
- _peri: PeripheralRef<'d, T>,
-}
-
-impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
- pub fn new_ch1(
- peri: impl Peripheral + 'd,
- txdma: impl Peripheral
+ 'd,
- _ch1: impl Peripheral
> + 'd,
- ) -> Self {
- into_ref!(peri);
- Self::new_inner(peri, true, false, txdma)
- }
-
- pub fn new_ch2(
- peri: impl Peripheral
+ 'd,
- txdma: impl Peripheral
+ 'd,
- _ch2: impl Peripheral
> + 'd,
- ) -> Self {
- into_ref!(peri);
- Self::new_inner(peri, false, true, txdma)
- }
-
- pub fn new_ch1_and_ch2(
- peri: impl Peripheral
+ 'd,
- txdma: impl Peripheral
+ 'd,
- _ch1: impl Peripheral
> + 'd,
- _ch2: impl Peripheral
> + 'd,
- ) -> Self {
- into_ref!(peri);
- Self::new_inner(peri, true, true, txdma)
- }
-
- /// Perform initialisation steps for the DAC
- fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral
+ 'd) -> Self {
- into_ref!(txdma);
- T::enable();
- T::reset();
-
- let mut dac = Self {
- ch1,
- ch2,
- txdma,
- _peri: peri,
- };
-
- // Configure each activated channel. All results can be `unwrap`ed since they
- // will only error if the channel is not configured (i.e. ch1, ch2 are false)
- if ch1 {
- dac.set_channel_mode(Channel::Ch1, 0).unwrap();
- dac.enable_channel(Channel::Ch1).unwrap();
- dac.set_trigger_enable(Channel::Ch1, true).unwrap();
- }
- if ch2 {
- dac.set_channel_mode(Channel::Ch2, 0).unwrap();
- dac.enable_channel(Channel::Ch2).unwrap();
- dac.set_trigger_enable(Channel::Ch2, true).unwrap();
- }
-
- dac
- }
-
- /// Check the channel is configured
- fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> {
- if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) {
- Err(Error::UnconfiguredChannel)
- } else {
- Ok(())
- }
- }
+pub trait DacChannel {
+ const CHANNEL: Channel;
/// Enable trigger of the given channel
- fn set_trigger_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
- self.check_channel_configured(ch)?;
+ fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> {
T::regs().cr().modify(|reg| {
- reg.set_ten(ch.index(), on);
+ reg.set_ten(Self::CHANNEL.index(), on);
});
Ok(())
}
/// Set mode register of the given channel
- fn set_channel_mode(&mut self, ch: Channel, val: u8) -> Result<(), Error> {
- self.check_channel_configured(ch)?;
+ fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
T::regs().mcr().modify(|reg| {
- reg.set_mode(ch.index(), val);
+ reg.set_mode(Self::CHANNEL.index(), val);
});
Ok(())
}
/// Set enable register of the given channel
- fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> {
- self.check_channel_configured(ch)?;
+ fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> {
T::regs().cr().modify(|reg| {
- reg.set_en(ch.index(), on);
+ reg.set_en(Self::CHANNEL.index(), on);
});
Ok(())
}
/// Enable the DAC channel `ch`
- pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
- self.set_channel_enable(ch, true)
+ fn enable_channel(&mut self) -> Result<(), Error> {
+ self.set_channel_enable(true)
}
/// Disable the DAC channel `ch`
- pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
- self.set_channel_enable(ch, false)
- }
-
- /// Select a new trigger for CH1 (disables the channel)
- pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
- self.check_channel_configured(Channel::Ch1)?;
- unwrap!(self.disable_channel(Channel::Ch1));
- T::regs().cr().modify(|reg| {
- reg.set_tsel1(trigger.tsel());
- });
- Ok(())
- }
-
- /// Select a new trigger for CH2 (disables the channel)
- pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
- self.check_channel_configured(Channel::Ch2)?;
- unwrap!(self.disable_channel(Channel::Ch2));
- T::regs().cr().modify(|reg| {
- reg.set_tsel2(trigger.tsel());
- });
- Ok(())
+ fn disable_channel(&mut self) -> Result<(), Error> {
+ self.set_channel_enable(false)
}
/// Perform a software trigger on `ch`
- pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> {
- self.check_channel_configured(ch)?;
+ fn trigger(&mut self) -> Result<(), Error> {
T::regs().swtrigr().write(|reg| {
- reg.set_swtrig(ch.index(), true);
+ reg.set_swtrig(Self::CHANNEL.index(), true);
});
Ok(())
}
- /// Perform a software trigger on all channels
- pub fn trigger_all(&mut self) {
- T::regs().swtrigr().write(|reg| {
- reg.set_swtrig(Channel::Ch1.index(), true);
- reg.set_swtrig(Channel::Ch2.index(), true);
- });
- }
-
/// Set a value to be output by the DAC on trigger.
///
/// The `value` is written to the corresponding "data holding register"
- pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> {
- self.check_channel_configured(ch)?;
+ fn set(&mut self, value: Value) -> Result<(), Error> {
match value {
- Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)),
- Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)),
- Value::Bit12Right(v) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
+ Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
}
Ok(())
}
+}
+
+pub struct Dac<'d, T: Instance, Tx> {
+ ch1: DacCh1<'d, T, Tx>,
+ ch2: DacCh2<'d, T, Tx>,
+}
+
+pub struct DacCh1<'d, T: Instance, Tx> {
+ _peri: PeripheralRef<'d, T>,
+ dma: PeripheralRef<'d, Tx>,
+}
+
+pub struct DacCh2<'d, T: Instance, Tx> {
+ phantom: PhantomData<&'d mut T>,
+ dma: PeripheralRef<'d, Tx>,
+}
+
+impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
+ /// Perform initialisation steps for the DAC
+ pub fn new(
+ peri: impl Peripheral + 'd,
+ dma: impl Peripheral
+ 'd,
+ _pin: impl Peripheral
> + 'd,
+ ) -> Self {
+ into_ref!(peri, dma);
+ T::enable();
+ T::reset();
+
+ let mut dac = Self { _peri: peri, dma };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ dac.set_channel_mode(0).unwrap();
+ dac.enable_channel().unwrap();
+ dac.set_trigger_enable(true).unwrap();
+
+ dac
+ }
+ /// Select a new trigger for CH1 (disables the channel)
+ pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
+ unwrap!(self.disable_channel());
+ T::regs().cr().modify(|reg| {
+ reg.set_tsel1(trigger.tsel());
+ });
+ Ok(())
+ }
/// Write `data` to the DAC CH1 via DMA.
///
@@ -276,36 +220,12 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 1 has to be configured for the DAC instance!
- pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
- self.check_channel_configured(Channel::Ch1)?;
- self.write_inner(data, circular, Channel::Ch1).await
- }
-
- /// Write `data` to the DAC CH2 via DMA.
- ///
- /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
- /// This will configure a circular DMA transfer that periodically outputs the `data`.
- /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
- ///
- /// **Important:** Channel 2 has to be configured for the DAC instance!
- pub async fn write_ch2(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- self.check_channel_configured(Channel::Ch2)?;
- self.write_inner(data, circular, Channel::Ch2).await
- }
-
- /// Performs the dma write for the given channel.
- /// TODO: Should self be &mut?
- async fn write_inner(&self, data_ch1: ValueArray<'_>, circular: bool, channel: Channel) -> Result<(), Error>
- where
- Tx: Dma,
- {
- let channel = channel.index();
+ let channel = Channel::Ch1.index();
+ debug!("Writing to channel {}", channel);
// Enable DAC and DMA
T::regs().cr().modify(|w| {
@@ -313,11 +233,11 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
w.set_dmaen(channel, true);
});
- let tx_request = self.txdma.request();
- let dma_channel = &self.txdma;
+ let tx_request = self.dma.request();
+ let dma_channel = &self.dma;
// Initiate the correct type of DMA transfer depending on what data is passed
- let tx_f = match data_ch1 {
+ let tx_f = match data {
ValueArray::Bit8(buf) => unsafe {
Transfer::new_write(
dma_channel,
@@ -374,6 +294,168 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
}
}
+impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
+ /// Perform initialisation steps for the DAC
+ pub fn new_ch2(
+ peri: impl Peripheral + 'd,
+ dma: impl Peripheral
+ 'd,
+ _pin: impl Peripheral
> + 'd,
+ ) -> Self {
+ into_ref!(peri, dma);
+ T::enable();
+ T::reset();
+
+ let mut dac = Self {
+ phantom: PhantomData,
+ dma,
+ };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ dac.set_channel_mode(0).unwrap();
+ dac.enable_channel().unwrap();
+ dac.set_trigger_enable(true).unwrap();
+
+ dac
+ }
+
+ /// Select a new trigger for CH1 (disables the channel)
+ pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
+ unwrap!(self.disable_channel());
+ T::regs().cr().modify(|reg| {
+ reg.set_tsel2(trigger.tsel());
+ });
+ Ok(())
+ }
+
+ /// Write `data` to the DAC CH1 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 1 has to be configured for the DAC instance!
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ let channel = Channel::Ch2.index();
+ debug!("Writing to channel {}", channel);
+
+ // Enable DAC and DMA
+ T::regs().cr().modify(|w| {
+ w.set_en(channel, true);
+ w.set_dmaen(channel, true);
+ });
+
+ let tx_request = self.dma.request();
+ let dma_channel = &self.dma;
+
+ // Initiate the correct type of DMA transfer depending on what data is passed
+ let tx_f = match data {
+ ValueArray::Bit8(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr8r(channel).as_ptr() as *mut u8,
+ TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ },
+ )
+ },
+ ValueArray::Bit12Left(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12l(channel).as_ptr() as *mut u16,
+ TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ },
+ )
+ },
+ ValueArray::Bit12Right(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12r(channel).as_ptr() as *mut u16,
+ TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ },
+ )
+ },
+ };
+
+ tx_f.await;
+
+ // finish dma
+ // TODO: Do we need to check any status registers here?
+ T::regs().cr().modify(|w| {
+ // Disable the DAC peripheral
+ w.set_en(channel, false);
+ // Disable the DMA. TODO: Is this necessary?
+ w.set_dmaen(channel, false);
+ });
+
+ Ok(())
+ }
+}
+
+impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
+ pub fn new(
+ peri: impl Peripheral + 'd,
+ dma_ch1: impl Peripheral
+ 'd,
+ dma_ch2: impl Peripheral
+ 'd,
+ _pin_ch1: impl Peripheral
> + 'd,
+ _pin_ch2: impl Peripheral
> + 'd,
+ ) -> Self {
+ into_ref!(peri, dma_ch1, dma_ch2);
+ T::enable();
+ T::reset();
+
+ let mut dac_ch1 = DacCh1 {
+ _peri: peri,
+ dma: dma_ch1,
+ };
+
+ let mut dac_ch2 = DacCh2 {
+ phantom: PhantomData,
+ dma: dma_ch2,
+ };
+
+ // Configure each activated channel. All results can be `unwrap`ed since they
+ // will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ dac_ch1.set_channel_mode(0).unwrap();
+ dac_ch1.enable_channel().unwrap();
+ dac_ch1.set_trigger_enable(true).unwrap();
+
+ dac_ch1.set_channel_mode(0).unwrap();
+ dac_ch1.enable_channel().unwrap();
+ dac_ch1.set_trigger_enable(true).unwrap();
+
+ Self {
+ ch1: dac_ch1,
+ ch2: dac_ch2,
+ }
+ }
+}
+
+impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> {
+ const CHANNEL: Channel = Channel::Ch1;
+}
+
+impl<'d, T: Instance, Tx> DacChannel for DacCh2<'d, T, Tx> {
+ const CHANNEL: Channel = Channel::Ch2;
+}
+
pub(crate) mod sealed {
pub trait Instance {
fn regs() -> &'static crate::pac::dac::Dac;
From df944edeef738590f481d35ee9e2a1afb09601fa Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Sun, 25 Jun 2023 10:53:35 +0200
Subject: [PATCH 34/74] fix minor issues with splitting channels etc
---
embassy-stm32/src/dac/mod.rs | 46 ++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 13 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index e87292b86..3dcd6b771 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -168,9 +168,9 @@ pub trait DacChannel {
}
}
-pub struct Dac<'d, T: Instance, Tx> {
- ch1: DacCh1<'d, T, Tx>,
- ch2: DacCh2<'d, T, Tx>,
+pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
+ ch1: DacCh1<'d, T, TxCh1>,
+ ch2: DacCh2<'d, T, TxCh2>,
}
pub struct DacCh1<'d, T: Instance, Tx> {
@@ -220,7 +220,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 1 has to be configured for the DAC instance!
- async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
@@ -297,11 +297,11 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
/// Perform initialisation steps for the DAC
pub fn new_ch2(
- peri: impl Peripheral + 'd,
+ _peri: impl Peripheral
+ 'd,
dma: impl Peripheral
+ 'd,
_pin: impl Peripheral
> + 'd,
) -> Self {
- into_ref!(peri, dma);
+ into_ref!(_peri, dma);
T::enable();
T::reset();
@@ -335,7 +335,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 1 has to be configured for the DAC instance!
- async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: Dma,
{
@@ -409,11 +409,11 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
}
}
-impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
+impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
pub fn new(
peri: impl Peripheral + 'd,
- dma_ch1: impl Peripheral
+ 'd,
- dma_ch2: impl Peripheral
+ 'd,
+ dma_ch1: impl Peripheral
+ 'd,
+ dma_ch2: impl Peripheral
+ 'd,
_pin_ch1: impl Peripheral
> + 'd,
_pin_ch2: impl Peripheral
> + 'd,
) -> Self {
@@ -437,15 +437,35 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
dac_ch1.enable_channel().unwrap();
dac_ch1.set_trigger_enable(true).unwrap();
- dac_ch1.set_channel_mode(0).unwrap();
- dac_ch1.enable_channel().unwrap();
- dac_ch1.set_trigger_enable(true).unwrap();
+ dac_ch2.set_channel_mode(0).unwrap();
+ dac_ch2.enable_channel().unwrap();
+ dac_ch2.set_trigger_enable(true).unwrap();
Self {
ch1: dac_ch1,
ch2: dac_ch2,
}
}
+
+ pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) {
+ (self.ch1, self.ch2)
+ }
+
+ pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> {
+ &mut self.ch1
+ }
+
+ pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> {
+ &mut self.ch2
+ }
+
+ pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> {
+ &self.ch1
+ }
+
+ pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> {
+ &self.ch2
+ }
}
impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> {
From 8cafaa1f3c9b75e8dba30a7f37f60d9fee6e65e2 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Sun, 25 Jun 2023 11:54:25 +0200
Subject: [PATCH 35/74] add docs, cleanup
---
embassy-stm32/src/dac/mod.rs | 322 +++++++++++++++++------------------
1 file changed, 155 insertions(+), 167 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 3dcd6b771..d95674ff0 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -1,5 +1,6 @@
#![macro_use]
+//! Provide access to the STM32 digital-to-analog converter (DAC).
use core::marker::PhantomData;
use embassy_hal_common::{into_ref, PeripheralRef};
@@ -11,6 +12,7 @@ use crate::{peripherals, Peripheral};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+/// Curstom Errors
pub enum Error {
UnconfiguredChannel,
InvalidValue,
@@ -18,6 +20,7 @@ pub enum Error {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+/// DAC Channels
pub enum Channel {
Ch1,
Ch2,
@@ -34,6 +37,7 @@ impl Channel {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+/// Trigger sources for CH1
pub enum Ch1Trigger {
Tim6,
Tim3,
@@ -60,6 +64,7 @@ impl Ch1Trigger {
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+/// Trigger sources for CH2
pub enum Ch2Trigger {
Tim6,
Tim8,
@@ -109,7 +114,7 @@ pub enum ValueArray<'a> {
// 12 bit values stored in a u16, right-aligned
Bit12Right(&'a [u16]),
}
-
+/// Provide common functions for DAC channels
pub trait DacChannel {
const CHANNEL: Channel;
@@ -157,7 +162,7 @@ pub trait DacChannel {
/// Set a value to be output by the DAC on trigger.
///
- /// The `value` is written to the corresponding "data holding register"
+ /// The `value` is written to the corresponding "data holding register".
fn set(&mut self, value: Value) -> Result<(), Error> {
match value {
Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)),
@@ -166,25 +171,51 @@ pub trait DacChannel {
}
Ok(())
}
+
+ /// Write `data` to the DAC channel via DMA.
+ ///
+ /// `circular` sets the DMA to circular mode.
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma;
}
+/// Hold two DAC channels
+///
+/// Note: This consumes the DAC `Instance` only once, allowing to get both channels simultaneously.
+///
+/// # Example for obtaining both DAC channels
+///
+/// ```no_run
+/// // DMA channels and pins may need to be changed for your controller
+/// let (dac_ch1, dac_ch2) =
+/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
+/// ```
pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
ch1: DacCh1<'d, T, TxCh1>,
ch2: DacCh2<'d, T, TxCh2>,
}
+/// DAC CH1
+///
+/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
pub struct DacCh1<'d, T: Instance, Tx> {
+ /// To consume T
_peri: PeripheralRef<'d, T>,
dma: PeripheralRef<'d, Tx>,
}
+/// DAC CH2
+///
+/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously.
pub struct DacCh2<'d, T: Instance, Tx> {
+ /// Instead of PeripheralRef to consume T
phantom: PhantomData<&'d mut T>,
dma: PeripheralRef<'d, Tx>,
}
impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
- /// Perform initialisation steps for the DAC
+ /// Obtain DAC CH1
pub fn new(
peri: impl Peripheral + 'd,
dma: impl Peripheral
+ 'd,
@@ -204,7 +235,8 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
dac
}
- /// Select a new trigger for CH1 (disables the channel)
+
+ /// Select a new trigger for this channel
pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
unwrap!(self.disable_channel());
T::regs().cr().modify(|reg| {
@@ -212,91 +244,11 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
});
Ok(())
}
-
- /// Write `data` to the DAC CH1 via DMA.
- ///
- /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
- /// This will configure a circular DMA transfer that periodically outputs the `data`.
- /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
- ///
- /// **Important:** Channel 1 has to be configured for the DAC instance!
- pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- let channel = Channel::Ch1.index();
- debug!("Writing to channel {}", channel);
-
- // Enable DAC and DMA
- T::regs().cr().modify(|w| {
- w.set_en(channel, true);
- w.set_dmaen(channel, true);
- });
-
- let tx_request = self.dma.request();
- let dma_channel = &self.dma;
-
- // Initiate the correct type of DMA transfer depending on what data is passed
- let tx_f = match data {
- ValueArray::Bit8(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr8r(channel).as_ptr() as *mut u8,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- ValueArray::Bit12Left(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr12l(channel).as_ptr() as *mut u16,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- ValueArray::Bit12Right(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr12r(channel).as_ptr() as *mut u16,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- };
-
- tx_f.await;
-
- // finish dma
- // TODO: Do we need to check any status registers here?
- T::regs().cr().modify(|w| {
- // Disable the DAC peripheral
- w.set_en(channel, false);
- // Disable the DMA. TODO: Is this necessary?
- w.set_dmaen(channel, false);
- });
-
- Ok(())
- }
}
impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
- /// Perform initialisation steps for the DAC
- pub fn new_ch2(
+ /// Obtain DAC CH2
+ pub fn new(
_peri: impl Peripheral + 'd,
dma: impl Peripheral
+ 'd,
_pin: impl Peripheral
> + 'd,
@@ -319,7 +271,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
dac
}
- /// Select a new trigger for CH1 (disables the channel)
+ /// Select a new trigger for this channel
pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> {
unwrap!(self.disable_channel());
T::regs().cr().modify(|reg| {
@@ -327,89 +279,12 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
});
Ok(())
}
-
- /// Write `data` to the DAC CH1 via DMA.
- ///
- /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
- /// This will configure a circular DMA transfer that periodically outputs the `data`.
- /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
- ///
- /// **Important:** Channel 1 has to be configured for the DAC instance!
- pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- let channel = Channel::Ch2.index();
- debug!("Writing to channel {}", channel);
-
- // Enable DAC and DMA
- T::regs().cr().modify(|w| {
- w.set_en(channel, true);
- w.set_dmaen(channel, true);
- });
-
- let tx_request = self.dma.request();
- let dma_channel = &self.dma;
-
- // Initiate the correct type of DMA transfer depending on what data is passed
- let tx_f = match data {
- ValueArray::Bit8(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr8r(channel).as_ptr() as *mut u8,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- ValueArray::Bit12Left(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr12l(channel).as_ptr() as *mut u16,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- ValueArray::Bit12Right(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr12r(channel).as_ptr() as *mut u16,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- };
-
- tx_f.await;
-
- // finish dma
- // TODO: Do we need to check any status registers here?
- T::regs().cr().modify(|w| {
- // Disable the DAC peripheral
- w.set_en(channel, false);
- // Disable the DMA. TODO: Is this necessary?
- w.set_dmaen(channel, false);
- });
-
- Ok(())
- }
}
impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
+ /// Create a new DAC instance with both channels.
+ ///
+ /// This is used to obtain two independent channels via `split()` for use e.g. with DMA.
pub fn new(
peri: impl Peripheral + 'd,
dma_ch1: impl Peripheral
+ 'd,
@@ -447,22 +322,27 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
}
}
+ /// Split the DAC into CH1 and CH2 for independent use.
pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) {
(self.ch1, self.ch2)
}
+ /// Get mutable reference to CH1
pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> {
&mut self.ch1
}
+ /// Get mutable reference to CH2
pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> {
&mut self.ch2
}
+ /// Get reference to CH1
pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> {
&self.ch1
}
+ /// Get reference to CH2
pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> {
&self.ch2
}
@@ -470,10 +350,117 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> {
const CHANNEL: Channel = Channel::Ch1;
+
+ /// Write `data` to the DAC CH1 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 1 has to be configured for the DAC instance!
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ write_inner(Self::CHANNEL, &self.dma, data, circular).await
+ }
}
impl<'d, T: Instance, Tx> DacChannel for DacCh2<'d, T, Tx> {
const CHANNEL: Channel = Channel::Ch2;
+
+ /// Write `data` to the DAC CH2 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 2 has to be configured for the DAC instance!
+ async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: Dma,
+ {
+ write_inner(Self::CHANNEL, &self.dma, data, circular).await
+ }
+}
+
+/// Shared utility function to perform the actual DMA config and write.
+async fn write_inner(
+ ch: Channel,
+ dma: &PeripheralRef<'_, Tx>,
+ data: ValueArray<'_>,
+ circular: bool,
+) -> Result<(), Error>
+where
+ Tx: Dma,
+{
+ let channel = ch.index();
+ debug!("Writing to channel {}", channel);
+
+ // Enable DAC and DMA
+ T::regs().cr().modify(|w| {
+ w.set_en(channel, true);
+ w.set_dmaen(channel, true);
+ });
+
+ let tx_request = dma.request();
+ let dma_channel = dma;
+
+ // Initiate the correct type of DMA transfer depending on what data is passed
+ let tx_f = match data {
+ ValueArray::Bit8(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr8r(channel).as_ptr() as *mut u8,
+ TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ },
+ )
+ },
+ ValueArray::Bit12Left(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12l(channel).as_ptr() as *mut u16,
+ TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ },
+ )
+ },
+ ValueArray::Bit12Right(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12r(channel).as_ptr() as *mut u16,
+ TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ },
+ )
+ },
+ };
+
+ tx_f.await;
+
+ // finish dma
+ // TODO: Do we need to check any status registers here?
+ T::regs().cr().modify(|w| {
+ // Disable the DAC peripheral
+ w.set_en(channel, false);
+ // Disable the DMA. TODO: Is this necessary?
+ w.set_dmaen(channel, false);
+ });
+
+ Ok(())
}
pub(crate) mod sealed {
@@ -485,6 +472,7 @@ pub(crate) mod sealed {
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
dma_trait!(Dma, Instance);
+/// Marks a pin that can be used with the DAC
pub trait DacPin: crate::gpio::Pin + 'static {}
foreach_peripheral!(
From 018622f607a17037903ef7c5592dda762002f89b Mon Sep 17 00:00:00 2001
From: xoviat
Date: Sun, 25 Jun 2023 11:38:48 -0500
Subject: [PATCH 36/74] stm32/wpan: update example
---
examples/stm32wb/src/bin/tl_mbox_mac.rs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs
index afd319a41..f67be4682 100644
--- a/examples/stm32wb/src/bin/tl_mbox_mac.rs
+++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs
@@ -49,7 +49,9 @@ async fn main(_spawner: Spawner) {
let sys_event = mbox.sys_subsystem.read().await;
info!("sys event: {}", sys_event.payload());
- mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
+ let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await;
+ info!("initialized mac: {}", result);
+
//
// info!("starting ble...");
// mbox.ble_subsystem.t_write(0x0c, &[]).await;
From aa0ab06645446bcb4b99a9407dc9c6c58030d8de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1niel=20Buga?=
Date: Sun, 25 Jun 2023 22:24:48 +0200
Subject: [PATCH 37/74] Update darling
---
embassy-macros/Cargo.toml | 4 ++--
embassy-macros/src/lib.rs | 37 ++++++++++++++++++++++---------
embassy-macros/src/macros/main.rs | 9 ++++----
embassy-macros/src/macros/task.rs | 5 +++--
4 files changed, 37 insertions(+), 18 deletions(-)
diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml
index 781026b99..3b8fe8b44 100644
--- a/embassy-macros/Cargo.toml
+++ b/embassy-macros/Cargo.toml
@@ -12,9 +12,9 @@ categories = [
]
[dependencies]
-syn = { version = "1.0.76", features = ["full", "extra-traits"] }
+syn = { version = "2.0.15", features = ["full", "extra-traits"] }
quote = "1.0.9"
-darling = "0.13.0"
+darling = "0.20.1"
proc-macro2 = "1.0.29"
[lib]
diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs
index ba4f13b77..c9d58746a 100644
--- a/embassy-macros/src/lib.rs
+++ b/embassy-macros/src/lib.rs
@@ -1,11 +1,28 @@
#![doc = include_str!("../README.md")]
extern crate proc_macro;
+use darling::ast::NestedMeta;
use proc_macro::TokenStream;
mod macros;
mod util;
use macros::*;
+use syn::parse::{Parse, ParseBuffer};
+use syn::punctuated::Punctuated;
+use syn::Token;
+
+struct Args {
+ meta: Vec,
+}
+
+impl Parse for Args {
+ fn parse(input: &ParseBuffer) -> syn::Result {
+ let meta = Punctuated::::parse_terminated(input)?;
+ Ok(Args {
+ meta: meta.into_iter().collect(),
+ })
+ }
+}
/// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how
/// many concurrent tasks can be spawned (default is 1) for the function.
@@ -39,10 +56,10 @@ use macros::*;
/// ```
#[proc_macro_attribute]
pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ let args = syn::parse_macro_input!(args as Args);
let f = syn::parse_macro_input!(item as syn::ItemFn);
- task::run(args, f).unwrap_or_else(|x| x).into()
+ task::run(&args.meta, f).unwrap_or_else(|x| x).into()
}
/// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task.
@@ -65,9 +82,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream {
/// ```
#[proc_macro_attribute]
pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ let args = syn::parse_macro_input!(args as Args);
let f = syn::parse_macro_input!(item as syn::ItemFn);
- main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into()
+ main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into()
}
/// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task.
@@ -100,9 +117,9 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream {
/// ```
#[proc_macro_attribute]
pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ let args = syn::parse_macro_input!(args as Args);
let f = syn::parse_macro_input!(item as syn::ItemFn);
- main::run(args.clone(), f, main::riscv(args))
+ main::run(&args.meta, f, main::riscv(&args.meta))
.unwrap_or_else(|x| x)
.into()
}
@@ -127,9 +144,9 @@ pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream {
/// ```
#[proc_macro_attribute]
pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ let args = syn::parse_macro_input!(args as Args);
let f = syn::parse_macro_input!(item as syn::ItemFn);
- main::run(args, f, main::std()).unwrap_or_else(|x| x).into()
+ main::run(&args.meta, f, main::std()).unwrap_or_else(|x| x).into()
}
/// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task.
@@ -152,7 +169,7 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream {
/// ```
#[proc_macro_attribute]
pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream {
- let args = syn::parse_macro_input!(args as syn::AttributeArgs);
+ let args = syn::parse_macro_input!(args as Args);
let f = syn::parse_macro_input!(item as syn::ItemFn);
- main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into()
+ main::run(&args.meta, f, main::wasm()).unwrap_or_else(|x| x).into()
}
diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs
index 5c099f68a..7c4d55163 100644
--- a/embassy-macros/src/macros/main.rs
+++ b/embassy-macros/src/macros/main.rs
@@ -1,3 +1,4 @@
+use darling::export::NestedMeta;
use darling::FromMeta;
use proc_macro2::TokenStream;
use quote::quote;
@@ -11,8 +12,8 @@ struct Args {
entry: Option,
}
-pub fn riscv(args: syn::AttributeArgs) -> TokenStream {
- let maybe_entry = match Args::from_list(&args) {
+pub fn riscv(args: &[NestedMeta]) -> TokenStream {
+ let maybe_entry = match Args::from_list(args) {
Ok(args) => args.entry,
Err(e) => return e.write_errors(),
};
@@ -77,9 +78,9 @@ pub fn std() -> TokenStream {
}
}
-pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result {
+pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result {
#[allow(unused_variables)]
- let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
+ let args = Args::from_list(args).map_err(|e| e.write_errors())?;
let fargs = f.sig.inputs.clone();
diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs
index 9f30cf43e..8c4bf7265 100644
--- a/embassy-macros/src/macros/task.rs
+++ b/embassy-macros/src/macros/task.rs
@@ -1,3 +1,4 @@
+use darling::export::NestedMeta;
use darling::FromMeta;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
@@ -11,8 +12,8 @@ struct Args {
pool_size: Option,
}
-pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result {
- let args = Args::from_list(&args).map_err(|e| e.write_errors())?;
+pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result {
+ let args = Args::from_list(args).map_err(|e| e.write_errors())?;
let pool_size: usize = args.pool_size.unwrap_or(1);
From 2809e926cf8a3a1556c674a7b17c8db4b926f243 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1niel=20Buga?=
Date: Sun, 25 Jun 2023 22:32:24 +0200
Subject: [PATCH 38/74] Allow arbitrary expressions as pool_size
---
embassy-macros/src/macros/task.rs | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs
index 8c4bf7265..1d30434e9 100644
--- a/embassy-macros/src/macros/task.rs
+++ b/embassy-macros/src/macros/task.rs
@@ -1,21 +1,24 @@
use darling::export::NestedMeta;
use darling::FromMeta;
-use proc_macro2::TokenStream;
+use proc_macro2::{Span, TokenStream};
use quote::{format_ident, quote};
-use syn::{parse_quote, ItemFn, ReturnType, Type};
+use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type};
use crate::util::ctxt::Ctxt;
#[derive(Debug, FromMeta)]
struct Args {
#[darling(default)]
- pool_size: Option,
+ pool_size: Option,
}
pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result {
let args = Args::from_list(args).map_err(|e| e.write_errors())?;
- let pool_size: usize = args.pool_size.unwrap_or(1);
+ let pool_size = args.pool_size.unwrap_or(Expr::Lit(ExprLit {
+ attrs: vec![],
+ lit: Lit::Int(LitInt::new("1", Span::call_site())),
+ }));
let ctxt = Ctxt::new();
@@ -46,10 +49,6 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result Result ::embassy_executor::SpawnToken {
type Fut = impl ::core::future::Future + 'static;
- static POOL: ::embassy_executor::raw::TaskPool = ::embassy_executor::raw::TaskPool::new();
+ const POOL_SIZE: usize = #pool_size;
+ static POOL: ::embassy_executor::raw::TaskPool = ::embassy_executor::raw::TaskPool::new();
unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) }
}
};
From 12872ce49b3945c1a28ae362f78bcfb334a9eeb8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1niel=20Buga?=
Date: Sun, 25 Jun 2023 23:03:14 +0200
Subject: [PATCH 39/74] Modify an example
---
examples/nrf52840/src/bin/self_spawn.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs
index 196255a52..31ea6c81e 100644
--- a/examples/nrf52840/src/bin/self_spawn.rs
+++ b/examples/nrf52840/src/bin/self_spawn.rs
@@ -7,7 +7,11 @@ use embassy_executor::Spawner;
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};
-#[embassy_executor::task(pool_size = 2)]
+mod config {
+ pub const MY_TASK_POOL_SIZE: usize = 2;
+}
+
+#[embassy_executor::task(pool_size = config::MY_TASK_POOL_SIZE)]
async fn my_task(spawner: Spawner, n: u32) {
Timer::after(Duration::from_secs(1)).await;
info!("Spawning self! {}", n);
From e7bc84dda8cc28835d1b7d3574a94b6142e29864 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Mon, 26 Jun 2023 09:42:25 +0200
Subject: [PATCH 40/74] fix issues when DAC2 present, add additional options to
DMA (NOT YET WORKING with STM32H7A3ZI)
---
embassy-stm32/build.rs | 4 +-
embassy-stm32/src/dac/mod.rs | 267 ++++++++++++++++++++---------------
embassy-stm32/src/dma/dma.rs | 26 +++-
3 files changed, 178 insertions(+), 119 deletions(-)
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index f7a25743c..7fa4fae45 100644
--- a/embassy-stm32/build.rs
+++ b/embassy-stm32/build.rs
@@ -699,8 +699,8 @@ fn main() {
// SDMMCv1 uses the same channel for both directions, so just implement for RX
(("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)),
(("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)),
- (("dac", "CH1"), quote!(crate::dac::Dma)),
- (("dac", "CH2"), quote!(crate::dac::Dma)),
+ (("dac", "CH1"), quote!(crate::dac::DmaCh1)),
+ (("dac", "CH2"), quote!(crate::dac::DmaCh2)),
]
.into();
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index d95674ff0..6ead00e15 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -171,13 +171,6 @@ pub trait DacChannel {
}
Ok(())
}
-
- /// Write `data` to the DAC channel via DMA.
- ///
- /// `circular` sets the DMA to circular mode.
- async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
- where
- Tx: Dma;
}
/// Hold two DAC channels
@@ -244,6 +237,81 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
});
Ok(())
}
+
+ /// Write `data` to the DAC CH1 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 1 has to be configured for the DAC instance!
+ pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: DmaCh1,
+ {
+ let channel = Channel::Ch1.index();
+ debug!("Writing to channel {}", channel);
+
+ // Enable DAC and DMA
+ T::regs().cr().modify(|w| {
+ w.set_en(channel, true);
+ w.set_dmaen(channel, true);
+ });
+
+ let tx_request = self.dma.request();
+ let dma_channel = &self.dma;
+
+ let tx_options = TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ ..Default::default()
+ };
+
+ // Initiate the correct type of DMA transfer depending on what data is passed
+ let tx_f = match data {
+ ValueArray::Bit8(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr8r(channel).as_ptr() as *mut u8,
+ tx_options,
+ )
+ },
+ ValueArray::Bit12Left(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12l(channel).as_ptr() as *mut u16,
+ tx_options,
+ )
+ },
+ ValueArray::Bit12Right(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12r(channel).as_ptr() as *mut u16,
+ tx_options,
+ )
+ },
+ };
+
+ tx_f.await;
+
+ // finish dma
+ // TODO: Do we need to check any status registers here?
+ T::regs().cr().modify(|w| {
+ // Disable the DAC peripheral
+ w.set_en(channel, false);
+ // Disable the DMA. TODO: Is this necessary?
+ w.set_dmaen(channel, false);
+ });
+
+ Ok(())
+ }
}
impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
@@ -279,6 +347,81 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
});
Ok(())
}
+
+ /// Write `data` to the DAC CH2 via DMA.
+ ///
+ /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
+ /// This will configure a circular DMA transfer that periodically outputs the `data`.
+ /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
+ ///
+ /// **Important:** Channel 2 has to be configured for the DAC instance!
+ pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ where
+ Tx: DmaCh2,
+ {
+ let channel = Channel::Ch2.index();
+ debug!("Writing to channel {}", channel);
+
+ // Enable DAC and DMA
+ T::regs().cr().modify(|w| {
+ w.set_en(channel, true);
+ w.set_dmaen(channel, true);
+ });
+
+ let tx_request = self.dma.request();
+ let dma_channel = &self.dma;
+
+ let tx_options = TransferOptions {
+ circular,
+ half_transfer_ir: false,
+ complete_transfer_ir: !circular,
+ ..Default::default()
+ };
+
+ // Initiate the correct type of DMA transfer depending on what data is passed
+ let tx_f = match data {
+ ValueArray::Bit8(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr8r(channel).as_ptr() as *mut u8,
+ tx_options,
+ )
+ },
+ ValueArray::Bit12Left(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12l(channel).as_ptr() as *mut u16,
+ tx_options,
+ )
+ },
+ ValueArray::Bit12Right(buf) => unsafe {
+ Transfer::new_write(
+ dma_channel,
+ tx_request,
+ buf,
+ T::regs().dhr12r(channel).as_ptr() as *mut u16,
+ tx_options,
+ )
+ },
+ };
+
+ tx_f.await;
+
+ // finish dma
+ // TODO: Do we need to check any status registers here?
+ T::regs().cr().modify(|w| {
+ // Disable the DAC peripheral
+ w.set_en(channel, false);
+ // Disable the DMA. TODO: Is this necessary?
+ w.set_dmaen(channel, false);
+ });
+
+ Ok(())
+ }
}
impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
@@ -350,117 +493,10 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> {
const CHANNEL: Channel = Channel::Ch1;
-
- /// Write `data` to the DAC CH1 via DMA.
- ///
- /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
- /// This will configure a circular DMA transfer that periodically outputs the `data`.
- /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
- ///
- /// **Important:** Channel 1 has to be configured for the DAC instance!
- async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- write_inner(Self::CHANNEL, &self.dma, data, circular).await
- }
}
impl<'d, T: Instance, Tx> DacChannel for DacCh2<'d, T, Tx> {
const CHANNEL: Channel = Channel::Ch2;
-
- /// Write `data` to the DAC CH2 via DMA.
- ///
- /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set.
- /// This will configure a circular DMA transfer that periodically outputs the `data`.
- /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
- ///
- /// **Important:** Channel 2 has to be configured for the DAC instance!
- async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
- where
- Tx: Dma,
- {
- write_inner(Self::CHANNEL, &self.dma, data, circular).await
- }
-}
-
-/// Shared utility function to perform the actual DMA config and write.
-async fn write_inner(
- ch: Channel,
- dma: &PeripheralRef<'_, Tx>,
- data: ValueArray<'_>,
- circular: bool,
-) -> Result<(), Error>
-where
- Tx: Dma,
-{
- let channel = ch.index();
- debug!("Writing to channel {}", channel);
-
- // Enable DAC and DMA
- T::regs().cr().modify(|w| {
- w.set_en(channel, true);
- w.set_dmaen(channel, true);
- });
-
- let tx_request = dma.request();
- let dma_channel = dma;
-
- // Initiate the correct type of DMA transfer depending on what data is passed
- let tx_f = match data {
- ValueArray::Bit8(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr8r(channel).as_ptr() as *mut u8,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- ValueArray::Bit12Left(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr12l(channel).as_ptr() as *mut u16,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- ValueArray::Bit12Right(buf) => unsafe {
- Transfer::new_write(
- dma_channel,
- tx_request,
- buf,
- T::regs().dhr12r(channel).as_ptr() as *mut u16,
- TransferOptions {
- circular,
- half_transfer_ir: false,
- complete_transfer_ir: !circular,
- },
- )
- },
- };
-
- tx_f.await;
-
- // finish dma
- // TODO: Do we need to check any status registers here?
- T::regs().cr().modify(|w| {
- // Disable the DAC peripheral
- w.set_en(channel, false);
- // Disable the DMA. TODO: Is this necessary?
- w.set_dmaen(channel, false);
- });
-
- Ok(())
}
pub(crate) mod sealed {
@@ -470,7 +506,8 @@ pub(crate) mod sealed {
}
pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
-dma_trait!(Dma, Instance);
+dma_trait!(DmaCh1, Instance);
+dma_trait!(DmaCh2, Instance);
/// Marks a pin that can be used with the DAC
pub trait DacPin: crate::gpio::Pin + 'static {}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 8abe541d3..a5f828948 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -29,6 +29,12 @@ pub struct TransferOptions {
pub flow_ctrl: FlowControl,
/// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
pub fifo_threshold: Option,
+ /// Enable circular DMA
+ pub circular: bool,
+ /// Enable half transfer interrupt
+ pub half_transfer_ir: bool,
+ /// Enable transfer complete interrupt
+ pub complete_transfer_ir: bool,
}
impl Default for TransferOptions {
@@ -38,6 +44,9 @@ impl Default for TransferOptions {
mburst: Burst::Single,
flow_ctrl: FlowControl::Dma,
fifo_threshold: None,
+ circular: false,
+ half_transfer_ir: false,
+ complete_transfer_ir: true,
}
}
}
@@ -366,13 +375,20 @@ impl<'a, C: Channel> Transfer<'a, C> {
});
w.set_pinc(vals::Inc::FIXED);
w.set_teie(true);
- w.set_tcie(true);
+ w.set_tcie(options.complete_transfer_ir);
+ w.set_htie(options.half_transfer_ir);
#[cfg(dma_v1)]
w.set_trbuff(true);
#[cfg(dma_v2)]
w.set_chsel(_request);
+ if options.circular {
+ w.set_circ(vals::Circ::ENABLED);
+ debug!("Setting circular mode");
+ } else {
+ w.set_circ(vals::Circ::DISABLED);
+ }
w.set_pburst(options.pburst.into());
w.set_mburst(options.mburst.into());
w.set_pfctrl(options.flow_ctrl.into());
@@ -404,8 +420,14 @@ impl<'a, C: Channel> Transfer<'a, C> {
}
pub fn is_running(&mut self) -> bool {
+ //let ch = self.channel.regs().st(self.channel.num());
+ //ch.cr().read().en()
+
let ch = self.channel.regs().st(self.channel.num());
- ch.cr().read().en()
+ let en = ch.cr().read().en();
+ let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
+ let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
+ en && (circular || !tcif)
}
/// Gets the total remaining transfers for the channel
From 64cba950e55dd5cdd7d6ef13c2dbb03825bc6d01 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Mon, 26 Jun 2023 01:59:25 +0200
Subject: [PATCH 41/74] Update smoltcp.
---
embassy-net/Cargo.toml | 4 ++--
embassy-net/src/device.rs | 3 ++-
embassy-net/src/lib.rs | 18 +++++++++++++-----
embassy-net/src/udp.rs | 2 +-
4 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 4ac572577..63947c261 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -38,10 +38,10 @@ igmp = ["smoltcp/proto-igmp"]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
-smoltcp = { version = "0.9.0", default-features = false, features = [
+smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "803840b5ccac01cc0f108993958f637835f0adbe", default-features = false, features = [
"socket",
"async",
-]}
+] }
embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" }
embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" }
diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs
index 583cdc87f..4513c86d3 100644
--- a/embassy-net/src/device.rs
+++ b/embassy-net/src/device.rs
@@ -51,8 +51,9 @@ where
Medium::Ethernet => phy::Medium::Ethernet,
#[cfg(feature = "medium-ip")]
Medium::Ip => phy::Medium::Ip,
+ #[allow(unreachable_patterns)]
_ => panic!(
- "Unsupported medium {:?}. MAke sure to enable it in embassy-net's Cargo features.",
+ "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
caps.medium
),
};
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 7e8f765f9..3e83da7aa 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -235,12 +235,19 @@ impl Stack {
#[cfg(feature = "medium-ethernet")]
let medium = device.capabilities().medium;
- let mut iface_cfg = smoltcp::iface::Config::new();
+ let hardware_addr = match medium {
+ #[cfg(feature = "medium-ethernet")]
+ Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())),
+ #[cfg(feature = "medium-ip")]
+ Medium::Ip => HardwareAddress::Ip,
+ #[allow(unreachable_patterns)]
+ _ => panic!(
+ "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.",
+ medium
+ ),
+ };
+ let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr);
iface_cfg.random_seed = random_seed;
- #[cfg(feature = "medium-ethernet")]
- if medium == Medium::Ethernet {
- iface_cfg.hardware_addr = Some(HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())));
- }
let iface = Interface::new(
iface_cfg,
@@ -248,6 +255,7 @@ impl Stack {
inner: &mut device,
cx: None,
},
+ instant_to_smoltcp(Instant::now()),
);
let sockets = SocketSet::new(&mut resources.sockets[..]);
diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs
index c9843cfe8..36f8d06f2 100644
--- a/embassy-net/src/udp.rs
+++ b/embassy-net/src/udp.rs
@@ -104,7 +104,7 @@ impl<'a> UdpSocket<'a> {
pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> {
poll_fn(move |cx| {
self.with_mut(|s, _| match s.recv_slice(buf) {
- Ok(x) => Poll::Ready(Ok(x)),
+ Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))),
// No data ready
Err(udp::RecvError::Exhausted) => {
s.register_recv_waker(cx.waker());
From 715bf20c4159f2b11f4edf0cd3b1b999ef19b56b Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Mon, 26 Jun 2023 20:13:55 +0200
Subject: [PATCH 42/74] Update smoltcp to 0.10
---
embassy-net/Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml
index 63947c261..cef8247eb 100644
--- a/embassy-net/Cargo.toml
+++ b/embassy-net/Cargo.toml
@@ -38,7 +38,7 @@ igmp = ["smoltcp/proto-igmp"]
defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true }
-smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "803840b5ccac01cc0f108993958f637835f0adbe", default-features = false, features = [
+smoltcp = { version = "0.10.0", default-features = false, features = [
"socket",
"async",
] }
From 28fb492c402c74add5c650b9d65687816585c923 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 00:42:24 +0200
Subject: [PATCH 43/74] stm32/otg: flush fifos on reconfigure and on ep
disable.
---
embassy-stm32/src/usb_otg/usb.rs | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 8af5c7bd5..532157e6c 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -540,6 +540,19 @@ impl<'d, T: Instance> Bus<'d, T> {
fifo_top <= T::FIFO_DEPTH_WORDS,
"FIFO allocations exceeded maximum capacity"
);
+
+ // Flush fifos
+ r.grstctl().write(|w| {
+ w.set_rxfflsh(true);
+ w.set_txfflsh(true);
+ w.set_txfnum(0x10);
+ });
+ loop {
+ let x = r.grstctl().read();
+ if !x.rxfflsh() && !x.txfflsh() {
+ break;
+ }
+ }
}
fn configure_endpoints(&mut self) {
@@ -744,7 +757,19 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
r.doepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
- })
+ });
+
+ // Flush tx fifo
+ r.grstctl().write(|w| {
+ w.set_txfflsh(true);
+ w.set_txfnum(ep_addr.index() as _);
+ });
+ loop {
+ let x = r.grstctl().read();
+ if !x.txfflsh() {
+ break;
+ }
+ }
});
// Wake `Endpoint::wait_enabled()`
From a575e40a3503f4bf500b7ee3cadcce44727c7c6f Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 02:12:06 +0200
Subject: [PATCH 44/74] stm32/otg: clear NAK bit on endpoint enable.
---
embassy-stm32/src/usb_otg/usb.rs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 532157e6c..1a0d44fd2 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -780,13 +780,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
// cancel transfer if active
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
r.diepctl(ep_addr.index()).modify(|w| {
- w.set_snak(true);
+ w.set_snak(true); // set NAK
w.set_epdis(true);
})
}
r.diepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
+ w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
})
});
From 80407aa930279a7d23bd1295c7703d0d9064aa58 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 02:12:33 +0200
Subject: [PATCH 45/74] stm32/otg: set tx fifo num in IN endpoints on
configure.
---
embassy-stm32/src/usb_otg/usb.rs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 1a0d44fd2..b2f7eb852 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -124,7 +124,7 @@ impl interrupt::typelevel::Handler for InterruptHandl
}
state.ep_in_wakers[ep_num].wake();
- trace!("in ep={} irq val={:b}", ep_num, ep_ints.0);
+ trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
}
ep_mask >>= 1;
@@ -144,7 +144,7 @@ impl interrupt::typelevel::Handler for InterruptHandl
// // clear all
// r.doepint(ep_num).write_value(ep_ints);
// state.ep_out_wakers[ep_num].wake();
- // trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0);
+ // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
// }
// ep_mask >>= 1;
@@ -571,6 +571,8 @@ impl<'d, T: Instance> Bus<'d, T> {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
+ w.set_txfnum(index as _);
+ w.set_snak(true);
}
});
});
From 5e6e18b310ef3c19fd4cdc42fa74dd8ed455e444 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 03:56:09 +0200
Subject: [PATCH 46/74] stm32/usb: add TODO: implement VBUS detection.
---
embassy-stm32/src/usb/usb.rs | 95 ++++++++++++++++++------------------
1 file changed, 48 insertions(+), 47 deletions(-)
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 2367127e8..01b158b17 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -480,56 +480,57 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
poll_fn(move |cx| {
BUS_WAKER.register(cx.waker());
- if self.inited {
- let regs = T::regs();
-
- if IRQ_RESUME.load(Ordering::Acquire) {
- IRQ_RESUME.store(false, Ordering::Relaxed);
- return Poll::Ready(Event::Resume);
- }
-
- if IRQ_RESET.load(Ordering::Acquire) {
- IRQ_RESET.store(false, Ordering::Relaxed);
-
- trace!("RESET");
- regs.daddr().write(|w| {
- w.set_ef(true);
- w.set_add(0);
- });
-
- regs.epr(0).write(|w| {
- w.set_ep_type(EpType::CONTROL);
- w.set_stat_rx(Stat::NAK);
- w.set_stat_tx(Stat::NAK);
- });
-
- for i in 1..EP_COUNT {
- regs.epr(i).write(|w| {
- w.set_ea(i as _);
- w.set_ep_type(self.ep_types[i - 1]);
- })
- }
-
- for w in &EP_IN_WAKERS {
- w.wake()
- }
- for w in &EP_OUT_WAKERS {
- w.wake()
- }
-
- return Poll::Ready(Event::Reset);
- }
-
- if IRQ_SUSPEND.load(Ordering::Acquire) {
- IRQ_SUSPEND.store(false, Ordering::Relaxed);
- return Poll::Ready(Event::Suspend);
- }
-
- Poll::Pending
- } else {
+ // TODO: implement VBUS detection.
+ if !self.inited {
self.inited = true;
return Poll::Ready(Event::PowerDetected);
}
+
+ let regs = T::regs();
+
+ if IRQ_RESUME.load(Ordering::Acquire) {
+ IRQ_RESUME.store(false, Ordering::Relaxed);
+ return Poll::Ready(Event::Resume);
+ }
+
+ if IRQ_RESET.load(Ordering::Acquire) {
+ IRQ_RESET.store(false, Ordering::Relaxed);
+
+ trace!("RESET");
+ regs.daddr().write(|w| {
+ w.set_ef(true);
+ w.set_add(0);
+ });
+
+ regs.epr(0).write(|w| {
+ w.set_ep_type(EpType::CONTROL);
+ w.set_stat_rx(Stat::NAK);
+ w.set_stat_tx(Stat::NAK);
+ });
+
+ for i in 1..EP_COUNT {
+ regs.epr(i).write(|w| {
+ w.set_ea(i as _);
+ w.set_ep_type(self.ep_types[i - 1]);
+ })
+ }
+
+ for w in &EP_IN_WAKERS {
+ w.wake()
+ }
+ for w in &EP_OUT_WAKERS {
+ w.wake()
+ }
+
+ return Poll::Ready(Event::Reset);
+ }
+
+ if IRQ_SUSPEND.load(Ordering::Acquire) {
+ IRQ_SUSPEND.store(false, Ordering::Relaxed);
+ return Poll::Ready(Event::Suspend);
+ }
+
+ Poll::Pending
})
.await
}
From a2d1e7f02ca8d94c755ced56f1db11646ac2aa72 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 03:56:25 +0200
Subject: [PATCH 47/74] rp/usb: add TODO: implement VBUS detection.
---
embassy-rp/src/usb.rs | 1 +
1 file changed, 1 insertion(+)
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 1900ab416..b3f3bd927 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -353,6 +353,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
poll_fn(move |cx| {
BUS_WAKER.register(cx.waker());
+ // TODO: implement VBUS detection.
if !self.inited {
self.inited = true;
return Poll::Ready(Event::PowerDetected);
From 219ef5b37a1dff5f6e770da252ec010d55c43257 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 08:42:51 +0200
Subject: [PATCH 48/74] stm32/otg: add VBUS detection.
Fixes #1442.
---
embassy-stm32/src/usb_otg/usb.rs | 479 +++++++++++++----------
examples/stm32f4/src/bin/usb_ethernet.rs | 4 +-
examples/stm32f4/src/bin/usb_serial.rs | 4 +-
examples/stm32f7/src/bin/usb_serial.rs | 4 +-
examples/stm32h7/src/bin/usb_serial.rs | 4 +-
examples/stm32l4/src/bin/usb_serial.rs | 4 +-
examples/stm32u5/src/bin/usb_serial.rs | 4 +-
7 files changed, 297 insertions(+), 206 deletions(-)
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index b2f7eb852..6c00c93d6 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
use embassy_hal_common::{into_ref, Peripheral};
use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver::{
- self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut,
- EndpointType, Event, Unsupported,
+ self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
+ EndpointOut, EndpointType, Event, Unsupported,
};
use futures::future::poll_fn;
@@ -31,7 +31,7 @@ impl interrupt::typelevel::Handler for InterruptHandl
let state = T::state();
let ints = r.gintsts().read();
- if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() {
+ if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
// Mask interrupts and notify `Bus` to process them
r.gintmsk().write(|_| {});
T::state().bus_waker.wake();
@@ -256,7 +256,34 @@ struct EndpointData {
fifo_size_words: u16,
}
+#[non_exhaustive]
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub struct Config {
+ /// Enable VBUS detection.
+ ///
+ /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
+ /// This is done by checkihg whether there is 5V on the VBUS pin or not.
+ ///
+ /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
+ /// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
+ /// there's power in VBUS, i.e. the USB cable is always plugged in.)
+ ///
+ /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
+ /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
+ ///
+ /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
+ /// voltage divider. See ST application note AN4879 and the reference manual for more details.
+ pub vbus_detection: bool,
+}
+
+impl Default for Config {
+ fn default() -> Self {
+ Self { vbus_detection: true }
+ }
+}
+
pub struct Driver<'d, T: Instance> {
+ config: Config,
phantom: PhantomData<&'d mut T>,
ep_in: [Option; MAX_EP_COUNT],
ep_out: [Option; MAX_EP_COUNT],
@@ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> {
dp: impl Peripheral> + 'd,
dm: impl Peripheral
> + 'd,
ep_out_buffer: &'d mut [u8],
+ config: Config,
) -> Self {
into_ref!(dp, dm);
@@ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> {
dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
Self {
+ config,
phantom: PhantomData,
ep_in: [None; MAX_EP_COUNT],
ep_out: [None; MAX_EP_COUNT],
@@ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> {
ulpi_d6: impl Peripheral
> + 'd,
ulpi_d7: impl Peripheral
> + 'd,
ep_out_buffer: &'d mut [u8],
+ config: Config,
) -> Self {
assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
@@ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
);
Self {
+ config,
phantom: PhantomData,
ep_in: [None; MAX_EP_COUNT],
ep_out: [None; MAX_EP_COUNT],
@@ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
(
Bus {
+ config: self.config,
phantom: PhantomData,
ep_in: self.ep_in,
ep_out: self.ep_out,
phy_type: self.phy_type,
- enabled: false,
+ inited: false,
},
ControlPipe {
_phantom: PhantomData,
@@ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
}
pub struct Bus<'d, T: Instance> {
+ config: Config,
phantom: PhantomData<&'d mut T>,
ep_in: [Option; MAX_EP_COUNT],
ep_out: [Option; MAX_EP_COUNT],
phy_type: PhyType,
- enabled: bool,
+ inited: bool,
}
impl<'d, T: Instance> Bus<'d, T> {
@@ -498,11 +531,202 @@ impl<'d, T: Instance> Bus<'d, T> {
w.set_iepint(true);
w.set_oepint(true);
w.set_rxflvlm(true);
+ w.set_srqim(true);
+ w.set_otgint(true);
});
}
}
impl<'d, T: Instance> Bus<'d, T> {
+ fn init(&mut self) {
+ #[cfg(stm32l4)]
+ {
+ crate::peripherals::PWR::enable();
+ critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
+ }
+
+ #[cfg(stm32f7)]
+ {
+ // Enable ULPI clock if external PHY is used
+ let ulpien = !self.phy_type.internal();
+ critical_section::with(|_| {
+ crate::pac::RCC.ahb1enr().modify(|w| {
+ if T::HIGH_SPEED {
+ w.set_usb_otg_hsulpien(ulpien);
+ } else {
+ w.set_usb_otg_hsen(ulpien);
+ }
+ });
+
+ // Low power mode
+ crate::pac::RCC.ahb1lpenr().modify(|w| {
+ if T::HIGH_SPEED {
+ w.set_usb_otg_hsulpilpen(ulpien);
+ } else {
+ w.set_usb_otg_hslpen(ulpien);
+ }
+ });
+ });
+ }
+
+ #[cfg(stm32h7)]
+ {
+ // If true, VDD33USB is generated by internal regulator from VDD50USB
+ // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
+ // TODO: unhardcode
+ let internal_regulator = false;
+
+ // Enable USB power
+ critical_section::with(|_| {
+ crate::pac::PWR.cr3().modify(|w| {
+ w.set_usb33den(true);
+ w.set_usbregen(internal_regulator);
+ })
+ });
+
+ // Wait for USB power to stabilize
+ while !crate::pac::PWR.cr3().read().usb33rdy() {}
+
+ // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
+ critical_section::with(|_| {
+ crate::pac::RCC
+ .d2ccip2r()
+ .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
+ });
+
+ // Enable ULPI clock if external PHY is used
+ let ulpien = !self.phy_type.internal();
+ critical_section::with(|_| {
+ crate::pac::RCC.ahb1enr().modify(|w| {
+ if T::HIGH_SPEED {
+ w.set_usb_otg_hs_ulpien(ulpien);
+ } else {
+ w.set_usb_otg_fs_ulpien(ulpien);
+ }
+ });
+ crate::pac::RCC.ahb1lpenr().modify(|w| {
+ if T::HIGH_SPEED {
+ w.set_usb_otg_hs_ulpilpen(ulpien);
+ } else {
+ w.set_usb_otg_fs_ulpilpen(ulpien);
+ }
+ });
+ });
+ }
+
+ #[cfg(stm32u5)]
+ {
+ // Enable USB power
+ critical_section::with(|_| {
+ crate::pac::RCC.ahb3enr().modify(|w| {
+ w.set_pwren(true);
+ });
+ cortex_m::asm::delay(2);
+
+ crate::pac::PWR.svmcr().modify(|w| {
+ w.set_usv(true);
+ w.set_uvmen(true);
+ });
+ });
+
+ // Wait for USB power to stabilize
+ while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
+
+ // Select HSI48 as USB clock source.
+ critical_section::with(|_| {
+ crate::pac::RCC.ccipr1().modify(|w| {
+ w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
+ })
+ });
+ }
+
+ ::enable();
+ ::reset();
+
+ T::Interrupt::unpend();
+ unsafe { T::Interrupt::enable() };
+
+ let r = T::regs();
+ let core_id = r.cid().read().0;
+ info!("Core id {:08x}", core_id);
+
+ // Wait for AHB ready.
+ while !r.grstctl().read().ahbidl() {}
+
+ // Configure as device.
+ r.gusbcfg().write(|w| {
+ // Force device mode
+ w.set_fdmod(true);
+ // Enable internal full-speed PHY
+ w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
+ });
+
+ // Configuring Vbus sense and SOF output
+ match core_id {
+ 0x0000_1200 | 0x0000_1100 => {
+ assert!(self.phy_type != PhyType::InternalHighSpeed);
+
+ r.gccfg_v1().modify(|w| {
+ // Enable internal full-speed PHY, logic is inverted
+ w.set_pwrdwn(self.phy_type.internal());
+ });
+
+ // F429-like chips have the GCCFG.NOVBUSSENS bit
+ r.gccfg_v1().modify(|w| {
+ w.set_novbussens(!self.config.vbus_detection);
+ w.set_vbusasen(false);
+ w.set_vbusbsen(self.config.vbus_detection);
+ w.set_sofouten(false);
+ });
+ }
+ 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
+ // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
+ r.gccfg_v2().modify(|w| {
+ // Enable internal full-speed PHY, logic is inverted
+ w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
+ w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
+ });
+
+ r.gccfg_v2().modify(|w| {
+ w.set_vbden(self.config.vbus_detection);
+ });
+
+ // Force B-peripheral session
+ r.gotgctl().modify(|w| {
+ w.set_bvaloen(!self.config.vbus_detection);
+ w.set_bvaloval(true);
+ });
+ }
+ _ => unimplemented!("Unknown USB core id {:X}", core_id),
+ }
+
+ // Soft disconnect.
+ r.dctl().write(|w| w.set_sdis(true));
+
+ // Set speed.
+ r.dcfg().write(|w| {
+ w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
+ w.set_dspd(self.phy_type.to_dspd());
+ });
+
+ // Unmask transfer complete EP interrupt
+ r.diepmsk().write(|w| {
+ w.set_xfrcm(true);
+ });
+
+ // Unmask and clear core interrupts
+ Bus::::restore_irqs();
+ r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
+
+ // Unmask global interrupt
+ r.gahbcfg().write(|w| {
+ w.set_gint(true); // unmask global interrupt
+ });
+
+ // Connect
+ r.dctl().write(|w| w.set_sdis(false));
+ }
+
fn init_fifo(&mut self) {
trace!("init_fifo");
@@ -613,6 +837,13 @@ impl<'d, T: Instance> Bus<'d, T> {
});
}
+ fn disable_all_endpoints(&mut self) {
+ for i in 0..T::ENDPOINT_COUNT {
+ self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
+ self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
+ }
+ }
+
fn disable(&mut self) {
T::Interrupt::disable();
@@ -627,9 +858,14 @@ impl<'d, T: Instance> Bus<'d, T> {
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| {
- // TODO: implement VBUS detection
- if !self.enabled {
- return Poll::Ready(Event::PowerDetected);
+ if !self.inited {
+ self.init();
+ self.inited = true;
+
+ // If no vbus detection, just return a single PowerDetected event at startup.
+ if !self.config.vbus_detection {
+ return Poll::Ready(Event::PowerDetected);
+ }
}
let r = T::regs();
@@ -637,6 +873,32 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
T::state().bus_waker.register(cx.waker());
let ints = r.gintsts().read();
+
+ if ints.srqint() {
+ trace!("vbus detected");
+
+ r.gintsts().write(|w| w.set_srqint(true)); // clear
+ Self::restore_irqs();
+
+ if self.config.vbus_detection {
+ return Poll::Ready(Event::PowerDetected);
+ }
+ }
+
+ if ints.otgint() {
+ let otgints = r.gotgint().read();
+ r.gotgint().write_value(otgints); // clear all
+ Self::restore_irqs();
+
+ if otgints.sedet() {
+ trace!("vbus removed");
+ if self.config.vbus_detection {
+ self.disable_all_endpoints();
+ return Poll::Ready(Event::PowerRemoved);
+ }
+ }
+ }
+
if ints.usbrst() {
trace!("reset");
@@ -801,203 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn enable(&mut self) {
trace!("enable");
-
- #[cfg(stm32l4)]
- {
- crate::peripherals::PWR::enable();
- critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
- }
-
- #[cfg(stm32f7)]
- {
- // Enable ULPI clock if external PHY is used
- let ulpien = !self.phy_type.internal();
- critical_section::with(|_| {
- crate::pac::RCC.ahb1enr().modify(|w| {
- if T::HIGH_SPEED {
- w.set_usb_otg_hsulpien(ulpien);
- } else {
- w.set_usb_otg_hsen(ulpien);
- }
- });
-
- // Low power mode
- crate::pac::RCC.ahb1lpenr().modify(|w| {
- if T::HIGH_SPEED {
- w.set_usb_otg_hsulpilpen(ulpien);
- } else {
- w.set_usb_otg_hslpen(ulpien);
- }
- });
- });
- }
-
- #[cfg(stm32h7)]
- {
- // If true, VDD33USB is generated by internal regulator from VDD50USB
- // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
- // TODO: unhardcode
- let internal_regulator = false;
-
- // Enable USB power
- critical_section::with(|_| {
- crate::pac::PWR.cr3().modify(|w| {
- w.set_usb33den(true);
- w.set_usbregen(internal_regulator);
- })
- });
-
- // Wait for USB power to stabilize
- while !crate::pac::PWR.cr3().read().usb33rdy() {}
-
- // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
- critical_section::with(|_| {
- crate::pac::RCC
- .d2ccip2r()
- .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
- });
-
- // Enable ULPI clock if external PHY is used
- let ulpien = !self.phy_type.internal();
- critical_section::with(|_| {
- crate::pac::RCC.ahb1enr().modify(|w| {
- if T::HIGH_SPEED {
- w.set_usb_otg_hs_ulpien(ulpien);
- } else {
- w.set_usb_otg_fs_ulpien(ulpien);
- }
- });
- crate::pac::RCC.ahb1lpenr().modify(|w| {
- if T::HIGH_SPEED {
- w.set_usb_otg_hs_ulpilpen(ulpien);
- } else {
- w.set_usb_otg_fs_ulpilpen(ulpien);
- }
- });
- });
- }
-
- #[cfg(stm32u5)]
- {
- // Enable USB power
- critical_section::with(|_| {
- crate::pac::RCC.ahb3enr().modify(|w| {
- w.set_pwren(true);
- });
- cortex_m::asm::delay(2);
-
- crate::pac::PWR.svmcr().modify(|w| {
- w.set_usv(true);
- w.set_uvmen(true);
- });
- });
-
- // Wait for USB power to stabilize
- while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
-
- // Select HSI48 as USB clock source.
- critical_section::with(|_| {
- crate::pac::RCC.ccipr1().modify(|w| {
- w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
- })
- });
- }
-
- ::enable();
- ::reset();
-
- T::Interrupt::unpend();
- unsafe { T::Interrupt::enable() };
-
- let r = T::regs();
- let core_id = r.cid().read().0;
- info!("Core id {:08x}", core_id);
-
- // Wait for AHB ready.
- while !r.grstctl().read().ahbidl() {}
-
- // Configure as device.
- r.gusbcfg().write(|w| {
- // Force device mode
- w.set_fdmod(true);
- // Enable internal full-speed PHY
- w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
- });
-
- // Configuring Vbus sense and SOF output
- match core_id {
- 0x0000_1200 | 0x0000_1100 => {
- assert!(self.phy_type != PhyType::InternalHighSpeed);
-
- r.gccfg_v1().modify(|w| {
- // Enable internal full-speed PHY, logic is inverted
- w.set_pwrdwn(self.phy_type.internal());
- });
-
- // F429-like chips have the GCCFG.NOVBUSSENS bit
- r.gccfg_v1().modify(|w| {
- w.set_novbussens(true);
- w.set_vbusasen(false);
- w.set_vbusbsen(false);
- w.set_sofouten(false);
- });
- }
- 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
- // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
- r.gccfg_v2().modify(|w| {
- // Enable internal full-speed PHY, logic is inverted
- w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
- w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
- });
-
- r.gccfg_v2().modify(|w| {
- w.set_vbden(false);
- });
-
- // Force B-peripheral session
- r.gotgctl().modify(|w| {
- w.set_bvaloen(true);
- w.set_bvaloval(true);
- });
- }
- _ => unimplemented!("Unknown USB core id {:X}", core_id),
- }
-
- // Soft disconnect.
- r.dctl().write(|w| w.set_sdis(true));
-
- // Set speed.
- r.dcfg().write(|w| {
- w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
- w.set_dspd(self.phy_type.to_dspd());
- });
-
- // Unmask transfer complete EP interrupt
- r.diepmsk().write(|w| {
- w.set_xfrcm(true);
- });
-
- // Unmask and clear core interrupts
- Bus::::restore_irqs();
- r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
-
- // Unmask global interrupt
- r.gahbcfg().write(|w| {
- w.set_gint(true); // unmask global interrupt
- });
-
- // Connect
- r.dctl().write(|w| w.set_sdis(false));
-
- self.enabled = true;
+ // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
}
async fn disable(&mut self) {
trace!("disable");
- Bus::disable(self);
-
- self.enabled = false;
+ // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
+ //Bus::disable(self);
}
async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
@@ -1140,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
state.ep_in_wakers[index].register(cx.waker());
let diepctl = r.diepctl(index).read();
+ let dtxfsts = r.dtxfsts(index).read();
+ info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
if !diepctl.usbaep() {
+ trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
Poll::Ready(Err(EndpointError::Disabled))
} else if !diepctl.epena() {
+ trace!("write ep={:?} wait for prev: ready", self.info.addr);
Poll::Ready(Ok(()))
} else {
+ trace!("write ep={:?} wait for prev: pending", self.info.addr);
Poll::Pending
}
})
@@ -1169,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
Poll::Pending
} else {
+ trace!("write ep={:?} wait for fifo: ready", self.info.addr);
Poll::Ready(())
}
})
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 953d99a45..b1f01417c 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -52,7 +52,9 @@ async fn main(spawner: Spawner) {
// Create the driver, from the HAL.
let ep_out_buffer = &mut make_static!([0; 256])[..];
- let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer);
+ let mut config = embassy_stm32::usb_otg::Config::default();
+ config.vbus_detection = true;
+ let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index f8f5940a7..4ff6452ef 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
- let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer);
+ let mut config = embassy_stm32::usb_otg::Config::default();
+ config.vbus_detection = true;
+ let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 763309ce2..a2c76178b 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
- let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer);
+ let mut config = embassy_stm32::usb_otg::Config::default();
+ config.vbus_detection = true;
+ let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index c622f19f7..97291f60c 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
- let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer);
+ let mut config = embassy_stm32::usb_otg::Config::default();
+ config.vbus_detection = true;
+ let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 80811a43e..410d6891b 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
- let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer);
+ let mut config = embassy_stm32::usb_otg::Config::default();
+ config.vbus_detection = true;
+ let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index f36daf91b..9e47fb18a 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -31,7 +31,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
- let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer);
+ let mut config = embassy_stm32::usb_otg::Config::default();
+ config.vbus_detection = true;
+ let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
From afec1b439bb40b769c8ccd1c1b19d58edd034c3d Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Tue, 27 Jun 2023 18:17:51 +0200
Subject: [PATCH 49/74] feature-gate dma write, make trigger not return a
result
---
embassy-stm32/src/dac/mod.rs | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 6ead00e15..3e48d558a 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -153,11 +153,10 @@ pub trait DacChannel {
}
/// Perform a software trigger on `ch`
- fn trigger(&mut self) -> Result<(), Error> {
+ fn trigger(&mut self) {
T::regs().swtrigr().write(|reg| {
reg.set_swtrig(Self::CHANNEL.index(), true);
});
- Ok(())
}
/// Set a value to be output by the DAC on trigger.
@@ -230,6 +229,8 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
}
/// Select a new trigger for this channel
+ ///
+ /// **Important**: This disables the channel!
pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> {
unwrap!(self.disable_channel());
T::regs().cr().modify(|reg| {
@@ -245,6 +246,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 1 has to be configured for the DAC instance!
+ #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: DmaCh1,
@@ -355,6 +357,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
/// Note that for performance reasons in circular mode the transfer complete interrupt is disabled.
///
/// **Important:** Channel 2 has to be configured for the DAC instance!
+ #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though)
pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error>
where
Tx: DmaCh2,
From 56dd22f0ac49be2b824e88026d38b69843b56972 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Tue, 27 Jun 2023 21:23:47 +0200
Subject: [PATCH 50/74] feature-gate set_channel_mode, undo dma.rs changes
---
embassy-stm32/src/dac/mod.rs | 17 ++++++++++-------
embassy-stm32/src/dma/dma.rs | 18 +-----------------
2 files changed, 11 insertions(+), 24 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 3e48d558a..b53083524 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -127,6 +127,7 @@ pub trait DacChannel {
}
/// Set mode register of the given channel
+ #[cfg(dac_v2)]
fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> {
T::regs().mcr().modify(|reg| {
reg.set_mode(Self::CHANNEL.index(), val);
@@ -221,6 +222,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
// Configure each activated channel. All results can be `unwrap`ed since they
// will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ #[cfg(dac_v2)]
dac.set_channel_mode(0).unwrap();
dac.enable_channel().unwrap();
dac.set_trigger_enable(true).unwrap();
@@ -334,6 +336,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
// Configure each activated channel. All results can be `unwrap`ed since they
// will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ #[cfg(dac_v2)]
dac.set_channel_mode(0).unwrap();
dac.enable_channel().unwrap();
dac.set_trigger_enable(true).unwrap();
@@ -454,10 +457,12 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> {
// Configure each activated channel. All results can be `unwrap`ed since they
// will only error if the channel is not configured (i.e. ch1, ch2 are false)
+ #[cfg(dac_v2)]
dac_ch1.set_channel_mode(0).unwrap();
dac_ch1.enable_channel().unwrap();
dac_ch1.set_trigger_enable(true).unwrap();
+ #[cfg(dac_v2)]
dac_ch2.set_channel_mode(0).unwrap();
dac_ch2.enable_channel().unwrap();
dac_ch2.set_trigger_enable(true).unwrap();
@@ -521,27 +526,25 @@ foreach_peripheral!(
#[cfg(rcc_h7)]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
- critical_section::with(|_| unsafe {
- crate::rcc::get_freqs().apb1
- })
+ critical_section::with(|_| crate::rcc::get_freqs().apb1)
}
fn reset() {
- critical_section::with(|_| unsafe {
+ critical_section::with(|_| {
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
})
}
fn enable() {
- critical_section::with(|_| unsafe {
+ critical_section::with(|_| {
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
})
}
fn disable() {
- critical_section::with(|_| unsafe {
- crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false));
+ critical_section::with(|_| {
+ crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
})
}
}
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index a5f828948..0b7b60789 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -29,12 +29,6 @@ pub struct TransferOptions {
pub flow_ctrl: FlowControl,
/// FIFO threshold for DMA FIFO mode. If none, direct mode is used.
pub fifo_threshold: Option,
- /// Enable circular DMA
- pub circular: bool,
- /// Enable half transfer interrupt
- pub half_transfer_ir: bool,
- /// Enable transfer complete interrupt
- pub complete_transfer_ir: bool,
}
impl Default for TransferOptions {
@@ -44,9 +38,6 @@ impl Default for TransferOptions {
mburst: Burst::Single,
flow_ctrl: FlowControl::Dma,
fifo_threshold: None,
- circular: false,
- half_transfer_ir: false,
- complete_transfer_ir: true,
}
}
}
@@ -375,20 +366,13 @@ impl<'a, C: Channel> Transfer<'a, C> {
});
w.set_pinc(vals::Inc::FIXED);
w.set_teie(true);
- w.set_tcie(options.complete_transfer_ir);
- w.set_htie(options.half_transfer_ir);
+ w.set_tcie(true);
#[cfg(dma_v1)]
w.set_trbuff(true);
#[cfg(dma_v2)]
w.set_chsel(_request);
- if options.circular {
- w.set_circ(vals::Circ::ENABLED);
- debug!("Setting circular mode");
- } else {
- w.set_circ(vals::Circ::DISABLED);
- }
w.set_pburst(options.pburst.into());
w.set_mburst(options.mburst.into());
w.set_pfctrl(options.flow_ctrl.into());
From 60c54107ce5cc50f9d9365297d31973d96f00021 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Tue, 27 Jun 2023 21:58:56 +0200
Subject: [PATCH 51/74] fix sdmmc bdma transferconfig fields
---
embassy-stm32/src/sdmmc/mod.rs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs
index 80a336a48..698292bff 100644
--- a/embassy-stm32/src/sdmmc/mod.rs
+++ b/embassy-stm32/src/sdmmc/mod.rs
@@ -227,7 +227,11 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp
fifo_threshold: Some(crate::dma::FifoThreshold::Full),
};
#[cfg(all(sdmmc_v1, not(dma)))]
-const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {};
+const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {
+ circular: false,
+ half_transfer_ir: false,
+ complete_transfer_ir: true,
+};
/// SDMMC configuration
///
From 9c81d6315500b236adc7634d2d2d6ef776f984eb Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Tue, 27 Jun 2023 22:33:17 +0200
Subject: [PATCH 52/74] fix warnings
---
embassy-stm32/src/dac/mod.rs | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index b53083524..6686a387a 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -5,7 +5,6 @@ use core::marker::PhantomData;
use embassy_hal_common::{into_ref, PeripheralRef};
-use crate::dma::{Transfer, TransferOptions};
use crate::pac::dac;
use crate::rcc::RccPeripheral;
use crate::{peripherals, Peripheral};
@@ -195,6 +194,7 @@ pub struct Dac<'d, T: Instance, TxCh1, TxCh2> {
pub struct DacCh1<'d, T: Instance, Tx> {
/// To consume T
_peri: PeripheralRef<'d, T>,
+ #[allow(unused)] // For chips whose DMA is not (yet) supported
dma: PeripheralRef<'d, Tx>,
}
@@ -204,6 +204,7 @@ pub struct DacCh1<'d, T: Instance, Tx> {
pub struct DacCh2<'d, T: Instance, Tx> {
/// Instead of PeripheralRef to consume T
phantom: PhantomData<&'d mut T>,
+ #[allow(unused)] // For chips whose DMA is not (yet) supported
dma: PeripheralRef<'d, Tx>,
}
@@ -265,7 +266,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
let tx_request = self.dma.request();
let dma_channel = &self.dma;
- let tx_options = TransferOptions {
+ let tx_options = crate::dma::TransferOptions {
circular,
half_transfer_ir: false,
complete_transfer_ir: !circular,
@@ -275,7 +276,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data {
ValueArray::Bit8(buf) => unsafe {
- Transfer::new_write(
+ crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
@@ -284,7 +285,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
)
},
ValueArray::Bit12Left(buf) => unsafe {
- Transfer::new_write(
+ crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
@@ -293,7 +294,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> {
)
},
ValueArray::Bit12Right(buf) => unsafe {
- Transfer::new_write(
+ crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
@@ -377,7 +378,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
let tx_request = self.dma.request();
let dma_channel = &self.dma;
- let tx_options = TransferOptions {
+ let tx_options = crate::dma::TransferOptions {
circular,
half_transfer_ir: false,
complete_transfer_ir: !circular,
@@ -387,7 +388,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
// Initiate the correct type of DMA transfer depending on what data is passed
let tx_f = match data {
ValueArray::Bit8(buf) => unsafe {
- Transfer::new_write(
+ crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
@@ -396,7 +397,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
)
},
ValueArray::Bit12Left(buf) => unsafe {
- Transfer::new_write(
+ crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
@@ -405,7 +406,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> {
)
},
ValueArray::Bit12Right(buf) => unsafe {
- Transfer::new_write(
+ crate::dma::Transfer::new_write(
dma_channel,
tx_request,
buf,
@@ -526,7 +527,7 @@ foreach_peripheral!(
#[cfg(rcc_h7)]
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
- critical_section::with(|_| crate::rcc::get_freqs().apb1)
+ critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 })
}
fn reset() {
From f5ca687e9bbeb81ce24f56db6cd7defbcb5c2db2 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 23:49:12 +0200
Subject: [PATCH 53/74] sync/pipe: fix doc typos.
---
embassy-sync/src/pipe.rs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index db6ebb08b..13bf4ef01 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -282,7 +282,7 @@ where
/// returns the amount of bytes written.
///
/// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full,
- /// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that
+ /// this method will wait until it isn't. See [`try_write`](Self::try_write) for a variant that
/// returns an error instead of waiting.
///
/// It is not guaranteed that all bytes in the buffer are written, even if there's enough
@@ -319,7 +319,7 @@ where
/// returns the amount of bytes read.
///
/// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty,
- /// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that
+ /// this method will wait until it isn't. See [`try_read`](Self::try_read) for a variant that
/// returns an error instead of waiting.
///
/// It is not guaranteed that all bytes in the buffer are read, even if there's enough
From ed493be869fa653dc14d31060375e17e2469ce11 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 23:49:30 +0200
Subject: [PATCH 54/74] stm32: update metapac, includes fix for OTG with 9
endpoints (H7)
---
embassy-stm32/Cargo.toml | 4 ++--
embassy-stm32/src/rcc/l0.rs | 4 ++--
examples/stm32g4/src/bin/usb_serial.rs | 4 +++-
3 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 3d9ee8261..f15c6d0b7 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -57,7 +57,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
atomic-polyfill = "1.0.1"
-stm32-metapac = "10"
+stm32-metapac = "11"
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
-stm32-metapac = { version = "10", default-features = false, features = ["metadata"]}
+stm32-metapac = { version = "11", default-features = false, features = ["metadata"]}
[features]
default = ["rt"]
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index 42a481a74..d53b61069 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,7 +1,7 @@
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::pac::RCC;
#[cfg(crs)]
-use crate::pac::{CRS, SYSCFG};
+use crate::pac::{crs, CRS, SYSCFG};
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) {
CRS.cfgr().write(|w|
// Select LSE as synchronization source
- w.set_syncsrc(0b01));
+ w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index c111a9787..289d0ed86 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -38,7 +38,9 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config);
info!("Hello World!");
- pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10));
+ pac::RCC.ccipr().write(|w| {
+ w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK);
+ });
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
From 91c31d5e437b510af3c535f5e597881042563496 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 11:58:25 +0200
Subject: [PATCH 55/74] Update DAC examples, add DAC + DMA example
---
embassy-stm32/src/dac/mod.rs | 2 +-
examples/stm32f4/src/bin/dac.rs | 9 +-
examples/stm32h7/src/bin/dac.rs | 9 +-
examples/stm32l4/Cargo.toml | 2 +
examples/stm32l4/src/bin/dac.rs | 16 ++-
examples/stm32l4/src/bin/dac_dma.rs | 148 ++++++++++++++++++++++++++++
6 files changed, 167 insertions(+), 19 deletions(-)
create mode 100644 examples/stm32l4/src/bin/dac_dma.rs
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
index 6686a387a..1dc13949d 100644
--- a/embassy-stm32/src/dac/mod.rs
+++ b/embassy-stm32/src/dac/mod.rs
@@ -178,7 +178,7 @@ pub trait DacChannel {
///
/// # Example for obtaining both DAC channels
///
-/// ```no_run
+/// ```ignore
/// // DMA channels and pins may need to be changed for your controller
/// let (dac_ch1, dac_ch2) =
/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs
index d97ae7082..3a6216712 100644
--- a/examples/stm32f4/src/bin/dac.rs
+++ b/examples/stm32f4/src/bin/dac.rs
@@ -4,7 +4,8 @@
use defmt::*;
use embassy_executor::Spawner;
-use embassy_stm32::dac::{Channel, Dac, Value};
+use embassy_stm32::dac::{DacCh1, DacChannel, Value};
+use embassy_stm32::dma::NoDma;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
@@ -12,12 +13,12 @@ async fn main(_spawner: Spawner) -> ! {
let p = embassy_stm32::init(Default::default());
info!("Hello World, dude!");
- let mut dac = Dac::new_1ch(p.DAC, p.PA4);
+ let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4);
loop {
for v in 0..=255 {
- unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v))));
- unwrap!(dac.trigger(Channel::Ch1));
+ unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
+ dac.trigger();
}
}
}
diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs
index f12716370..586b4154b 100644
--- a/examples/stm32h7/src/bin/dac.rs
+++ b/examples/stm32h7/src/bin/dac.rs
@@ -4,7 +4,8 @@
use cortex_m_rt::entry;
use defmt::*;
-use embassy_stm32::dac::{Channel, Dac, Value};
+use embassy_stm32::dac::{DacCh1, DacChannel, Value};
+use embassy_stm32::dma::NoDma;
use embassy_stm32::time::mhz;
use embassy_stm32::Config;
use {defmt_rtt as _, panic_probe as _};
@@ -19,12 +20,12 @@ fn main() -> ! {
config.rcc.pll1.q_ck = Some(mhz(100));
let p = embassy_stm32::init(config);
- let mut dac = Dac::new_1ch(p.DAC1, p.PA4);
+ let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
loop {
for v in 0..=255 {
- unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v))));
- unwrap!(dac.trigger(Channel::Ch1));
+ unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
+ dac.trigger();
}
}
}
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index 3bb473ef5..d2d228282 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -25,3 +25,5 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
heapless = { version = "0.7.5", default-features = false }
micromath = "2.0.0"
+
+static_cell = "1.0.0"
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index a36ed5d90..8aad27646 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -3,26 +3,22 @@
#![feature(type_alias_impl_trait)]
use defmt::*;
-use embassy_stm32::dac::{Channel, Dac, Value};
+use embassy_stm32::dac::{DacCh1, DacChannel, Value};
+use embassy_stm32::dma::NoDma;
use embassy_stm32::pac;
use {defmt_rtt as _, panic_probe as _};
#[cortex_m_rt::entry]
fn main() -> ! {
+ let p = embassy_stm32::init(Default::default());
info!("Hello World!");
- pac::RCC.apb1enr1().modify(|w| {
- w.set_dac1en(true);
- });
-
- let p = embassy_stm32::init(Default::default());
-
- let mut dac = Dac::new_1ch(p.DAC1, p.PA4);
+ let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4);
loop {
for v in 0..=255 {
- unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v))));
- unwrap!(dac.trigger(Channel::Ch1));
+ unwrap!(dac.set(Value::Bit8(to_sine_wave(v))));
+ dac.trigger();
}
}
}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
new file mode 100644
index 000000000..81e6a58e4
--- /dev/null
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -0,0 +1,148 @@
+#![no_std]
+#![no_main]
+#![feature(type_alias_impl_trait)]
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_stm32::dac::{DacChannel, ValueArray};
+use embassy_stm32::pac::timer::vals::{Mms, Opm};
+use embassy_stm32::peripherals::{TIM6, TIM7};
+use embassy_stm32::rcc::low_level::RccPeripheral;
+use embassy_stm32::time::Hertz;
+use embassy_stm32::timer::low_level::Basic16bitInstance;
+use micromath::F32Ext;
+use static_cell::StaticCell;
+use {defmt_rtt as _, panic_probe as _};
+
+pub type Dac1Type<'d> =
+ embassy_stm32::dac::DacCh1<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
+
+pub type Dac2Type<'d> =
+ embassy_stm32::dac::DacCh2<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
+
+#[embassy_executor::main]
+async fn main(spawner: Spawner) {
+ let config = embassy_stm32::Config::default();
+
+ // Initialize the board and obtain a Peripherals instance
+ let p: embassy_stm32::Peripherals = embassy_stm32::init(config);
+
+ // Obtain two independent channels (p.DAC1 can only be consumed once, though!)
+ let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
+
+ let dac1 = {
+ type T = impl Sized;
+ static STATIC_CELL: StaticCell = StaticCell::new();
+ STATIC_CELL.init(dac_ch1)
+ };
+
+ let dac2 = {
+ type T = impl Sized;
+ static STATIC_CELL: StaticCell = StaticCell::new();
+ STATIC_CELL.init(dac_ch2)
+ };
+
+ spawner.spawn(dac_task1(dac1)).ok();
+ spawner.spawn(dac_task2(dac2)).ok();
+}
+
+#[embassy_executor::task]
+async fn dac_task1(dac: &'static mut Dac1Type<'static>) {
+ let data: &[u8; 256] = &calculate_array::<256>();
+
+ info!("TIM6 frequency is {}", TIM6::frequency());
+ const FREQUENCY: Hertz = Hertz::hz(200);
+ let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32;
+
+ // Depends on your clock and on the specific chip used, you may need higher or lower values here
+ if reload < 10 {
+ error!("Reload value {} below threshold!", reload);
+ }
+
+ dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap();
+ dac.enable_channel().unwrap();
+
+ TIM6::enable();
+ TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
+ TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
+ TIM6::regs().cr1().modify(|w| {
+ w.set_opm(Opm::DISABLED);
+ w.set_cen(true);
+ });
+
+ debug!(
+ "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
+ TIM6::frequency(),
+ FREQUENCY,
+ reload,
+ reload as u16,
+ data.len()
+ );
+
+ // Loop technically not necessary if DMA circular mode is enabled
+ loop {
+ info!("Loop DAC1");
+ if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
+ error!("Could not write to dac: {}", e);
+ }
+ }
+}
+
+#[embassy_executor::task]
+async fn dac_task2(dac: &'static mut Dac2Type<'static>) {
+ let data: &[u8; 256] = &calculate_array::<256>();
+
+ info!("TIM7 frequency is {}", TIM7::frequency());
+
+ const FREQUENCY: Hertz = Hertz::hz(600);
+ let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32;
+
+ if reload < 10 {
+ error!("Reload value {} below threshold!", reload);
+ }
+
+ TIM7::enable();
+ TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1));
+ TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE));
+ TIM7::regs().cr1().modify(|w| {
+ w.set_opm(Opm::DISABLED);
+ w.set_cen(true);
+ });
+
+ dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap();
+
+ debug!(
+ "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}",
+ TIM7::frequency(),
+ FREQUENCY,
+ reload,
+ reload as u16,
+ data.len()
+ );
+
+ if let Err(e) = dac.write(ValueArray::Bit8(data), true).await {
+ error!("Could not write to dac: {}", e);
+ }
+}
+
+fn to_sine_wave(v: u8) -> u8 {
+ if v >= 128 {
+ // top half
+ let r = 3.14 * ((v - 128) as f32 / 128.0);
+ (r.sin() * 128.0 + 127.0) as u8
+ } else {
+ // bottom half
+ let r = 3.14 + 3.14 * (v as f32 / 128.0);
+ (r.sin() * 128.0 + 127.0) as u8
+ }
+}
+
+fn calculate_array() -> [u8; N] {
+ let mut res = [0; N];
+ let mut i = 0;
+ while i < N {
+ res[i] = to_sine_wave(i as u8);
+ i += 1;
+ }
+ res
+}
From 59f829c6cce3427f95b7c5b137f62f8af0c3c40f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?D=C3=A1niel=20Buga?=
Date: Wed, 28 Jun 2023 15:03:57 +0200
Subject: [PATCH 56/74] Make StackResources::new() const
---
embassy-net/src/lib.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs
index 3e83da7aa..17a7a22a2 100644
--- a/embassy-net/src/lib.rs
+++ b/embassy-net/src/lib.rs
@@ -57,7 +57,7 @@ pub struct StackResources {
impl StackResources {
/// Create a new set of stack resources.
- pub fn new() -> Self {
+ pub const fn new() -> Self {
#[cfg(feature = "dns")]
const INIT: Option = None;
Self {
From 27a89019adaebfd1916d3b71dde1db3a6a768883 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:21:24 +0200
Subject: [PATCH 57/74] add doc
---
examples/stm32l4/src/bin/dac_dma.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index 81e6a58e4..aefc8412f 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -52,6 +52,8 @@ async fn dac_task1(dac: &'static mut Dac1Type<'static>) {
info!("TIM6 frequency is {}", TIM6::frequency());
const FREQUENCY: Hertz = Hertz::hz(200);
+
+ // Compute the reload value such that we obtain the FREQUENCY for the sine
let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32;
// Depends on your clock and on the specific chip used, you may need higher or lower values here
From f2e7a23148f0c1f663744bfe47fbbb37d9552080 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:25:57 +0200
Subject: [PATCH 58/74] attempt at fixing ci
---
examples/stm32l4/.cargo/config.toml | 3 ++-
examples/stm32l4/memory.x | 8 ++++----
examples/stm32l4/src/bin/dac_dma.rs | 2 +-
3 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index abf55eb2e..4ccdf121e 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,7 +2,8 @@
# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list`
#runner = "probe-rs-cli run --chip STM32L475VGT6"
#runner = "probe-rs-cli run --chip STM32L475VG"
-runner = "probe-rs-cli run --chip STM32L4S5VI"
+#runner = "probe-rs-cli run --chip STM32L4S5VI"
+runner = "probe-run --chip STM32L432KCUx"
[build]
target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/memory.x b/examples/stm32l4/memory.x
index eb87d1b54..0cef526ae 100644
--- a/examples/stm32l4/memory.x
+++ b/examples/stm32l4/memory.x
@@ -1,7 +1,7 @@
MEMORY
{
- /* NOTE 1 K = 1 KiBi = 1024 bytes */
- /* These values correspond to the STM32L4S5 */
- FLASH : ORIGIN = 0x08000000, LENGTH = 1024K
- RAM : ORIGIN = 0x20000000, LENGTH = 128K
+ /* NOTE K = KiBi = 1024 bytes */
+ /* TODO Adjust these memory regions to match your device memory layout */
+ FLASH : ORIGIN = 0x8000000, LENGTH = 256K
+ RAM : ORIGIN = 0x20000000, LENGTH = 64K
}
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index aefc8412f..7c0df835b 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -93,7 +93,7 @@ async fn dac_task1(dac: &'static mut Dac1Type<'static>) {
#[embassy_executor::task]
async fn dac_task2(dac: &'static mut Dac2Type<'static>) {
let data: &[u8; 256] = &calculate_array::<256>();
-
+
info!("TIM7 frequency is {}", TIM7::frequency());
const FREQUENCY: Hertz = Hertz::hz(600);
From 02f367f733591c9423731a86ea7726772a88dac0 Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:28:10 +0200
Subject: [PATCH 59/74] attempt at fixing ci
---
examples/stm32l4/src/bin/dac.rs | 1 -
1 file changed, 1 deletion(-)
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index 8aad27646..ade43eb35 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -5,7 +5,6 @@
use defmt::*;
use embassy_stm32::dac::{DacCh1, DacChannel, Value};
use embassy_stm32::dma::NoDma;
-use embassy_stm32::pac;
use {defmt_rtt as _, panic_probe as _};
#[cortex_m_rt::entry]
From bf7e24e9d7abc5d31b75ef97418577920bd4600c Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:37:29 +0200
Subject: [PATCH 60/74] revert to STM32L4S5VI
---
examples/stm32l4/.cargo/config.toml | 3 +--
examples/stm32l4/memory.x | 8 ++++----
2 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml
index 4ccdf121e..abf55eb2e 100644
--- a/examples/stm32l4/.cargo/config.toml
+++ b/examples/stm32l4/.cargo/config.toml
@@ -2,8 +2,7 @@
# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list`
#runner = "probe-rs-cli run --chip STM32L475VGT6"
#runner = "probe-rs-cli run --chip STM32L475VG"
-#runner = "probe-rs-cli run --chip STM32L4S5VI"
-runner = "probe-run --chip STM32L432KCUx"
+runner = "probe-rs-cli run --chip STM32L4S5VI"
[build]
target = "thumbv7em-none-eabi"
diff --git a/examples/stm32l4/memory.x b/examples/stm32l4/memory.x
index 0cef526ae..eb87d1b54 100644
--- a/examples/stm32l4/memory.x
+++ b/examples/stm32l4/memory.x
@@ -1,7 +1,7 @@
MEMORY
{
- /* NOTE K = KiBi = 1024 bytes */
- /* TODO Adjust these memory regions to match your device memory layout */
- FLASH : ORIGIN = 0x8000000, LENGTH = 256K
- RAM : ORIGIN = 0x20000000, LENGTH = 64K
+ /* NOTE 1 K = 1 KiBi = 1024 bytes */
+ /* These values correspond to the STM32L4S5 */
+ FLASH : ORIGIN = 0x08000000, LENGTH = 1024K
+ RAM : ORIGIN = 0x20000000, LENGTH = 128K
}
From daedfbbd8756e921cc6343ad531401d309966eaa Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 15:39:36 +0200
Subject: [PATCH 61/74] add dma is_running change doc
---
embassy-stm32/src/dma/dma.rs | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs
index 0b7b60789..9c03599eb 100644
--- a/embassy-stm32/src/dma/dma.rs
+++ b/embassy-stm32/src/dma/dma.rs
@@ -404,11 +404,9 @@ impl<'a, C: Channel> Transfer<'a, C> {
}
pub fn is_running(&mut self) -> bool {
- //let ch = self.channel.regs().st(self.channel.num());
- //ch.cr().read().en()
-
let ch = self.channel.regs().st(self.channel.num());
let en = ch.cr().read().en();
+ // Check if circular mode is enabled, if so it will still be running even if tcif == 1
let circular = ch.cr().read().circ() == vals::Circ::ENABLED;
let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0;
en && (circular || !tcif)
From d5898c11ebef63fa0ec6dba8381484f4cfabd65c Mon Sep 17 00:00:00 2001
From: JuliDi <20155974+JuliDi@users.noreply.github.com>
Date: Wed, 28 Jun 2023 16:40:50 +0200
Subject: [PATCH 62/74] remove need for StaticCell in dac_dma example for
stm32l4
---
examples/stm32l4/Cargo.toml | 2 --
examples/stm32l4/src/bin/dac_dma.rs | 29 ++++++++---------------------
2 files changed, 8 insertions(+), 23 deletions(-)
diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml
index d2d228282..3bb473ef5 100644
--- a/examples/stm32l4/Cargo.toml
+++ b/examples/stm32l4/Cargo.toml
@@ -25,5 +25,3 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa
heapless = { version = "0.7.5", default-features = false }
micromath = "2.0.0"
-
-static_cell = "1.0.0"
diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs
index 7c0df835b..c27cc03e1 100644
--- a/examples/stm32l4/src/bin/dac_dma.rs
+++ b/examples/stm32l4/src/bin/dac_dma.rs
@@ -11,14 +11,13 @@ use embassy_stm32::rcc::low_level::RccPeripheral;
use embassy_stm32::time::Hertz;
use embassy_stm32::timer::low_level::Basic16bitInstance;
use micromath::F32Ext;
-use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
-pub type Dac1Type<'d> =
- embassy_stm32::dac::DacCh1<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
+pub type Dac1Type =
+ embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>;
-pub type Dac2Type<'d> =
- embassy_stm32::dac::DacCh2<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
+pub type Dac2Type =
+ embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>;
#[embassy_executor::main]
async fn main(spawner: Spawner) {
@@ -30,24 +29,12 @@ async fn main(spawner: Spawner) {
// Obtain two independent channels (p.DAC1 can only be consumed once, though!)
let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split();
- let dac1 = {
- type T = impl Sized;
- static STATIC_CELL: StaticCell = StaticCell::new();
- STATIC_CELL.init(dac_ch1)
- };
-
- let dac2 = {
- type T = impl Sized;
- static STATIC_CELL: StaticCell = StaticCell::new();
- STATIC_CELL.init(dac_ch2)
- };
-
- spawner.spawn(dac_task1(dac1)).ok();
- spawner.spawn(dac_task2(dac2)).ok();
+ spawner.spawn(dac_task1(dac_ch1)).ok();
+ spawner.spawn(dac_task2(dac_ch2)).ok();
}
#[embassy_executor::task]
-async fn dac_task1(dac: &'static mut Dac1Type<'static>) {
+async fn dac_task1(mut dac: Dac1Type) {
let data: &[u8; 256] = &calculate_array::<256>();
info!("TIM6 frequency is {}", TIM6::frequency());
@@ -91,7 +78,7 @@ async fn dac_task1(dac: &'static mut Dac1Type<'static>) {
}
#[embassy_executor::task]
-async fn dac_task2(dac: &'static mut Dac2Type<'static>) {
+async fn dac_task2(mut dac: Dac2Type) {
let data: &[u8; 256] = &calculate_array::<256>();
info!("TIM7 frequency is {}", TIM7::frequency());
From 5666c569033d59fc894230ed4161e6c686733b2d Mon Sep 17 00:00:00 2001
From: Kevin Lannen
Date: Wed, 28 Jun 2023 13:05:39 -0600
Subject: [PATCH 63/74] STM32G4: Add CRS support to RCC
Create working CRS USB Example
---
embassy-stm32/src/rcc/g4.rs | 77 +++++++++++++++++++++++++-
examples/stm32g4/src/bin/usb_serial.rs | 30 ++++++----
2 files changed, 96 insertions(+), 11 deletions(-)
diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs
index 9401af4c3..ff8f97541 100644
--- a/embassy-stm32/src/rcc/g4.rs
+++ b/embassy-stm32/src/rcc/g4.rs
@@ -3,6 +3,7 @@ use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw};
use stm32_metapac::FLASH;
use crate::pac::{PWR, RCC};
+use crate::rcc::sealed::RccPeripheral;
use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz;
@@ -316,6 +317,27 @@ impl Into for AHBPrescaler {
}
}
+/// Sets the source for the 48MHz clock to the USB and RNG peripherals.
+pub enum Clock48MhzSrc {
+ /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
+ /// oscillator to comply with the USB specification for oscillator tolerance.
+ Hsi48(Option),
+ /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
+ /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
+ /// tolerance.
+ PllQ,
+}
+
+/// Sets the sync source for the Clock Recovery System (CRS).
+pub enum CrsSyncSource {
+ /// Use an external GPIO to sync the CRS.
+ Gpio,
+ /// Use the Low Speed External oscillator to sync the CRS.
+ Lse,
+ /// Use the USB SOF to sync the CRS.
+ Usb,
+}
+
/// Clocks configutation
pub struct Config {
pub mux: ClockSrc,
@@ -326,6 +348,14 @@ pub struct Config {
/// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration
/// MUST turn on the PLLR output.
pub pll: Option,
+ /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
+ pub clock_48mhz_src: Option,
+}
+
+/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
+pub struct CrsConfig {
+ /// Sync source for the CRS.
+ pub sync_src: CrsSyncSource,
}
impl Default for Config {
@@ -338,6 +368,7 @@ impl Default for Config {
apb2_pre: APBPrescaler::NotDivided,
low_power_run: false,
pll: None,
+ clock_48mhz_src: None,
}
}
}
@@ -430,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
assert!(pll_freq.is_some());
assert!(pll_freq.as_ref().unwrap().pll_r.is_some());
- let freq = pll_freq.unwrap().pll_r.unwrap().0;
+ let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0;
assert!(freq <= 170_000_000);
@@ -497,6 +528,50 @@ pub(crate) unsafe fn init(config: Config) {
}
};
+ // Setup the 48 MHz clock if needed
+ if let Some(clock_48mhz_src) = config.clock_48mhz_src {
+ let source = match clock_48mhz_src {
+ Clock48MhzSrc::PllQ => {
+ // Make sure the PLLQ is enabled and running at 48Mhz
+ let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q);
+ assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000);
+
+ crate::pac::rcc::vals::Clk48sel::PLLQCLK
+ }
+ Clock48MhzSrc::Hsi48(crs_config) => {
+ // Enable HSI48
+ RCC.crrcr().modify(|w| w.set_hsi48on(true));
+ // Wait for HSI48 to turn on
+ while RCC.crrcr().read().hsi48rdy() == false {}
+
+ // Enable and setup CRS if needed
+ if let Some(crs_config) = crs_config {
+ crate::peripherals::CRS::enable();
+
+ let sync_src = match crs_config.sync_src {
+ CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
+ CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
+ CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
+ };
+
+ crate::pac::CRS.cfgr().modify(|w| {
+ w.set_syncsrc(sync_src);
+ });
+
+ // These are the correct settings for standard USB operation. If other settings
+ // are needed there will need to be additional config options for the CRS.
+ crate::pac::CRS.cr().modify(|w| {
+ w.set_autotrimen(true);
+ w.set_cen(true);
+ });
+ }
+ crate::pac::rcc::vals::Clk48sel::HSI48
+ }
+ };
+
+ RCC.ccipr().modify(|w| w.set_clk48sel(source));
+ }
+
if config.low_power_run {
assert!(sys_clk <= 2_000_000);
PWR.cr1().modify(|w| w.set_lpr(true));
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index 289d0ed86..77cfa67d3 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -4,10 +4,10 @@
use defmt::{panic, *};
use embassy_executor::Spawner;
-use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllQ, PllR, PllSrc};
+use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc};
use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{self, Driver, Instance};
-use embassy_stm32::{bind_interrupts, pac, peripherals, Config};
+use embassy_stm32::{bind_interrupts, peripherals, Config};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
use embassy_usb::driver::EndpointError;
use embassy_usb::Builder;
@@ -22,25 +22,35 @@ bind_interrupts!(struct Irqs {
async fn main(_spawner: Spawner) {
let mut config = Config::default();
+ // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
+ const USE_HSI48: bool = true;
+
+ let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) };
+
config.rcc.pll = Some(Pll {
- source: PllSrc::HSE(Hertz(8000000)),
+ source: PllSrc::HSE(Hertz(8_000_000)),
prediv_m: PllM::Div2,
mul_n: PllN::Mul72,
div_p: None,
- // USB and CAN at 48 MHz
- div_q: Some(PllQ::Div6),
+ div_q: pllq_div,
// Main system clock at 144 MHz
div_r: Some(PllR::Div2),
});
config.rcc.mux = ClockSrc::PLL;
- let p = embassy_stm32::init(config);
- info!("Hello World!");
+ if USE_HSI48 {
+ // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
+ config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig {
+ sync_src: CrsSyncSource::Usb,
+ })));
+ } else {
+ config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
+ }
- pac::RCC.ccipr().write(|w| {
- w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK);
- });
+ let p = embassy_stm32::init(config);
+
+ info!("Hello World!");
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
From e892014b6572e74b58ea653cfed06614c496e6a5 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 29 Jun 2023 01:51:19 +0200
Subject: [PATCH 64/74] Update stm32-metapac, includes chiptool changes to use
real Rust enums now.
---
embassy-stm32/Cargo.toml | 4 +-
embassy-stm32/src/adc/v3.rs | 8 ++--
embassy-stm32/src/can/bxcan.rs | 8 ++--
embassy-stm32/src/eth/v1/rx_desc.rs | 2 +-
embassy-stm32/src/pwm/complementary_pwm.rs | 2 +-
embassy-stm32/src/rcc/c0.rs | 10 ++--
embassy-stm32/src/rcc/f0.rs | 23 +++++----
embassy-stm32/src/rcc/f1.rs | 36 +++++++-------
embassy-stm32/src/rcc/f2.rs | 2 +-
embassy-stm32/src/rcc/f4.rs | 12 ++---
embassy-stm32/src/rcc/f7.rs | 12 ++---
embassy-stm32/src/rcc/g0.rs | 10 ++--
embassy-stm32/src/rcc/h7.rs | 17 +++----
embassy-stm32/src/rcc/l0.rs | 6 +--
embassy-stm32/src/rcc/l1.rs | 6 +--
embassy-stm32/src/rcc/l4.rs | 6 +--
embassy-stm32/src/rcc/l5.rs | 6 +--
embassy-stm32/src/rcc/u5.rs | 2 +-
embassy-stm32/src/rtc/v2.rs | 4 +-
embassy-stm32/src/rtc/v3.rs | 2 +-
embassy-stm32/src/spi/mod.rs | 4 +-
embassy-stm32/src/usart/mod.rs | 2 +-
embassy-stm32/src/usb/usb.rs | 56 +++++++++++-----------
embassy-stm32/src/usb_otg/usb.rs | 4 +-
embassy-stm32/src/wdg/mod.rs | 2 +-
25 files changed, 121 insertions(+), 125 deletions(-)
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index f15c6d0b7..b3fe9c1f5 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -57,7 +57,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1"
atomic-polyfill = "1.0.1"
-stm32-metapac = "11"
+stm32-metapac = "12"
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies]
proc-macro2 = "1.0.36"
quote = "1.0.15"
-stm32-metapac = { version = "11", default-features = false, features = ["metadata"]}
+stm32-metapac = { version = "12", default-features = false, features = ["metadata"]}
[features]
default = ["rt"]
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index 94cdc86cd..3a6e58cf6 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -211,10 +211,8 @@ impl<'d, T: Instance> Adc<'d, T> {
#[cfg(not(stm32g0))]
fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
let sample_time = sample_time.into();
- if ch <= 9 {
- T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time));
- } else {
- T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time));
- }
+ T::regs()
+ .smpr(ch as usize / 10)
+ .modify(|reg| reg.set_smp(ch as usize % 10, sample_time));
}
}
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs
index 88eef528f..73861776a 100644
--- a/embassy-stm32/src/can/bxcan.rs
+++ b/embassy-stm32/src/can/bxcan.rs
@@ -116,10 +116,10 @@ impl<'d, T: Instance> Can<'d, T> {
T::regs().ier().write(|w| {
// TODO: fix metapac
- w.set_errie(Errie(1));
- w.set_fmpie(0, Fmpie(1));
- w.set_fmpie(1, Fmpie(1));
- w.set_tmeie(Tmeie(1));
+ w.set_errie(Errie::from_bits(1));
+ w.set_fmpie(0, Fmpie::from_bits(1));
+ w.set_fmpie(1, Fmpie::from_bits(1));
+ w.set_tmeie(Tmeie::from_bits(1));
});
T::regs().mcr().write(|w| {
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs
index 01a073bb9..668378bea 100644
--- a/embassy-stm32/src/eth/v1/rx_desc.rs
+++ b/embassy-stm32/src/eth/v1/rx_desc.rs
@@ -174,7 +174,7 @@ impl<'a> RDesRing<'a> {
// Receive descriptor unavailable
Rps::SUSPENDED => RunningState::Stopped,
// Closing receive descriptor
- Rps(0b101) => RunningState::Running,
+ Rps::_RESERVED_5 => RunningState::Running,
// Transferring the receive packet data from receive buffer to host memory
Rps::RUNNINGWRITING => RunningState::Running,
_ => RunningState::Unknown,
diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs
index 0e153202e..4d64d005c 100644
--- a/embassy-stm32/src/pwm/complementary_pwm.rs
+++ b/embassy-stm32/src/pwm/complementary_pwm.rs
@@ -243,7 +243,7 @@ mod tests {
for test_run in fn_results {
let (ckd, bits) = compute_dead_time_value(test_run.value);
- assert_eq!(ckd.0, test_run.ckd.0);
+ assert_eq!(ckd.to_bits(), test_run.ckd.to_bits());
assert_eq!(bits, test_run.bits);
}
}
diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs
index 6c7b36647..df6e9047c 100644
--- a/embassy-stm32/src/rcc/c0.rs
+++ b/embassy-stm32/src/rcc/c0.rs
@@ -126,7 +126,7 @@ pub(crate) unsafe fn init(config: Config) {
});
while !RCC.cr().read().hsirdy() {}
- (HSI_FREQ.0 >> div.0, Sw::HSI)
+ (HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
@@ -157,7 +157,7 @@ pub(crate) unsafe fn init(config: Config) {
let mut set_flash_latency_after = false;
FLASH.acr().modify(|w| {
// Is the current flash latency less than what we need at the new SYSCLK?
- if w.latency().0 <= target_flash_latency.0 {
+ if w.latency().to_bits() <= target_flash_latency.to_bits() {
// We must increase the number of wait states now
w.set_latency(target_flash_latency)
} else {
@@ -171,12 +171,12 @@ pub(crate) unsafe fn init(config: Config) {
// > Flash memory.
//
// Enable flash prefetching if we have at least one wait state, and disable it otherwise.
- w.set_prften(target_flash_latency.0 > 0);
+ w.set_prften(target_flash_latency.to_bits() > 0);
});
if !set_flash_latency_after {
// Spin until the effective flash latency is compatible with the clock change
- while FLASH.acr().read().latency().0 < target_flash_latency.0 {}
+ while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
}
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs
index eb62ab661..ca6eed284 100644
--- a/embassy-stm32/src/rcc/f0.rs
+++ b/embassy-stm32/src/rcc/f0.rs
@@ -1,3 +1,5 @@
+use stm32_metapac::flash::vals::Latency;
+
use super::{set_freqs, Clocks};
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
use crate::pac::{FLASH, RCC};
@@ -85,14 +87,11 @@ pub(crate) unsafe fn init(config: Config) {
let timer_mul = if ppre == 1 { 1 } else { 2 };
FLASH.acr().write(|w| {
- let latency = if real_sysclk <= 24_000_000 {
- 0
- } else if real_sysclk <= 48_000_000 {
- 1
+ w.set_latency(if real_sysclk <= 24_000_000 {
+ Latency::WS0
} else {
- 2
- };
- w.latency().0 = latency;
+ Latency::WS1
+ });
});
match (config.hse.is_some(), use_hsi48) {
@@ -134,20 +133,20 @@ pub(crate) unsafe fn init(config: Config) {
// TODO: Option to use CRS (Clock Recovery)
if let Some(pllmul_bits) = pllmul_bits {
- RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits)));
+ RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits)));
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
RCC.cfgr().modify(|w| {
- w.set_ppre(Ppre(ppre_bits));
- w.set_hpre(Hpre(hpre_bits));
+ w.set_ppre(Ppre::from_bits(ppre_bits));
+ w.set_hpre(Hpre::from_bits(hpre_bits));
w.set_sw(Sw::PLL)
});
} else {
RCC.cfgr().modify(|w| {
- w.set_ppre(Ppre(ppre_bits));
- w.set_hpre(Hpre(hpre_bits));
+ w.set_ppre(Ppre::from_bits(ppre_bits));
+ w.set_hpre(Hpre::from_bits(hpre_bits));
if config.hse.is_some() {
w.set_sw(Sw::HSE);
diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs
index 4769b7059..b6200231e 100644
--- a/embassy-stm32/src/rcc/f1.rs
+++ b/embassy-stm32/src/rcc/f1.rs
@@ -106,11 +106,11 @@ pub(crate) unsafe fn init(config: Config) {
// Only needed for stm32f103?
FLASH.acr().write(|w| {
w.set_latency(if real_sysclk <= 24_000_000 {
- Latency(0b000)
+ Latency::WS0
} else if real_sysclk <= 48_000_000 {
- Latency(0b001)
+ Latency::WS1
} else {
- Latency(0b010)
+ Latency::WS2
});
});
@@ -147,12 +147,13 @@ pub(crate) unsafe fn init(config: Config) {
if let Some(pllmul_bits) = pllmul_bits {
let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 };
- RCC.cfgr().modify(|w| w.set_pllxtpre(Pllxtpre(pllctpre_flag)));
+ RCC.cfgr()
+ .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag)));
// enable PLL and wait for it to be ready
RCC.cfgr().modify(|w| {
- w.set_pllmul(Pllmul(pllmul_bits));
- w.set_pllsrc(Pllsrc(config.hse.is_some() as u8));
+ w.set_pllmul(Pllmul::from_bits(pllmul_bits));
+ w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8));
});
RCC.cr().modify(|w| w.set_pllon(true));
@@ -161,22 +162,19 @@ pub(crate) unsafe fn init(config: Config) {
// Only needed for stm32f103?
RCC.cfgr().modify(|w| {
- w.set_adcpre(Adcpre(apre_bits));
- w.set_ppre2(Ppre1(ppre2_bits));
- w.set_ppre1(Ppre1(ppre1_bits));
- w.set_hpre(Hpre(hpre_bits));
+ w.set_adcpre(Adcpre::from_bits(apre_bits));
+ w.set_ppre2(Ppre1::from_bits(ppre2_bits));
+ w.set_ppre1(Ppre1::from_bits(ppre1_bits));
+ w.set_hpre(Hpre::from_bits(hpre_bits));
#[cfg(not(rcc_f100))]
- w.set_usbpre(Usbpre(usbpre as u8));
- w.set_sw(Sw(if pllmul_bits.is_some() {
- // PLL
- 0b10
+ w.set_usbpre(Usbpre::from_bits(usbpre as u8));
+ w.set_sw(if pllmul_bits.is_some() {
+ Sw::PLL
} else if config.hse.is_some() {
- // HSE
- 0b1
+ Sw::HSE
} else {
- // HSI
- 0b0
- }));
+ Sw::HSI
+ });
});
set_freqs(Clocks {
diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs
index bcae64d0f..1525cc3c3 100644
--- a/embassy-stm32/src/rcc/f2.rs
+++ b/embassy-stm32/src/rcc/f2.rs
@@ -485,7 +485,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_ppre1(config.apb1_pre.into());
w.set_ppre2(config.apb2_pre.into());
});
- while RCC.cfgr().read().sws() != sw.0 {}
+ while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
// Turn off HSI to save power if we don't need it
if !config.hsi {
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs
index bc430afb2..b84470440 100644
--- a/embassy-stm32/src/rcc/f4.rs
+++ b/embassy-stm32/src/rcc/f4.rs
@@ -87,7 +87,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, plli2s: Opti
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
- RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
+ RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
return PllResults {
use_pll: false,
@@ -141,9 +141,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, plli2s: Opti
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
- w.set_pllp(Pllp(pllp as u8));
+ w.set_pllp(Pllp::from_bits(pllp as u8));
w.set_pllq(pllq as u8);
- w.set_pllsrc(Pllsrc(use_hse as u8));
+ w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
@@ -323,7 +323,7 @@ fn flash_setup(sysclk: u32) {
critical_section::with(|_| {
FLASH
.acr()
- .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
+ .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
@@ -440,8 +440,8 @@ pub(crate) unsafe fn init(config: Config) {
}
RCC.cfgr().modify(|w| {
- w.set_ppre2(Ppre(ppre2_bits));
- w.set_ppre1(Ppre(ppre1_bits));
+ w.set_ppre2(Ppre::from_bits(ppre2_bits));
+ w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(hpre_bits);
});
diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs
index 71215cac5..85cb9c661 100644
--- a/embassy-stm32/src/rcc/f7.rs
+++ b/embassy-stm32/src/rcc/f7.rs
@@ -30,7 +30,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bo
let sysclk = pllsysclk.unwrap_or(pllsrcclk);
if pllsysclk.is_none() && !pll48clk {
- RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8)));
+ RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)));
return PllResults {
use_pll: false,
@@ -83,9 +83,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bo
RCC.pllcfgr().modify(|w| {
w.set_pllm(pllm as u8);
w.set_plln(plln as u16);
- w.set_pllp(Pllp(pllp as u8));
+ w.set_pllp(Pllp::from_bits(pllp as u8));
w.set_pllq(pllq as u8);
- w.set_pllsrc(Pllsrc(use_hse as u8));
+ w.set_pllsrc(Pllsrc::from_bits(use_hse as u8));
});
let real_pllsysclk = vco_in * plln / sysclk_div;
@@ -106,7 +106,7 @@ fn flash_setup(sysclk: u32) {
critical_section::with(|_| {
FLASH
.acr()
- .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
+ .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8)));
});
}
@@ -246,8 +246,8 @@ pub(crate) unsafe fn init(config: Config) {
}
RCC.cfgr().modify(|w| {
- w.set_ppre2(Ppre(ppre2_bits));
- w.set_ppre1(Ppre(ppre1_bits));
+ w.set_ppre2(Ppre::from_bits(ppre2_bits));
+ w.set_ppre1(Ppre::from_bits(ppre1_bits));
w.set_hpre(hpre_bits);
});
diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs
index 17c73c36b..5e3a7911a 100644
--- a/embassy-stm32/src/rcc/g0.rs
+++ b/embassy-stm32/src/rcc/g0.rs
@@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) {
});
while !RCC.cr().read().hsirdy() {}
- (HSI_FREQ.0 >> div.0, Sw::HSI)
+ (HSI_FREQ.0 >> div.to_bits(), Sw::HSI)
}
ClockSrc::HSE(freq) => {
// Enable HSE
@@ -381,7 +381,7 @@ pub(crate) unsafe fn init(config: Config) {
let mut set_flash_latency_after = false;
FLASH.acr().modify(|w| {
// Is the current flash latency less than what we need at the new SYSCLK?
- if w.latency().0 <= target_flash_latency.0 {
+ if w.latency().to_bits() <= target_flash_latency.to_bits() {
// We must increase the number of wait states now
w.set_latency(target_flash_latency)
} else {
@@ -395,12 +395,12 @@ pub(crate) unsafe fn init(config: Config) {
// > Flash memory.
//
// Enable flash prefetching if we have at least one wait state, and disable it otherwise.
- w.set_prften(target_flash_latency.0 > 0);
+ w.set_prften(target_flash_latency.to_bits() > 0);
});
if !set_flash_latency_after {
// Spin until the effective flash latency is compatible with the clock change
- while FLASH.acr().read().latency().0 < target_flash_latency.0 {}
+ while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
}
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
@@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs
index daa1cd61f..f3a98c794 100644
--- a/embassy-stm32/src/rcc/h7.rs
+++ b/embassy-stm32/src/rcc/h7.rs
@@ -601,22 +601,22 @@ pub(crate) unsafe fn init(mut config: Config) {
// Core Prescaler / AHB Prescaler / APB3 Prescaler
RCC.d1cfgr().modify(|w| {
- w.set_d1cpre(Hpre(d1cpre_bits));
- w.set_d1ppre(Dppre(ppre3_bits));
+ w.set_d1cpre(Hpre::from_bits(d1cpre_bits));
+ w.set_d1ppre(Dppre::from_bits(ppre3_bits));
w.set_hpre(hpre_bits)
});
// Ensure core prescaler value is valid before future lower
// core voltage
- while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {}
+ while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {}
// APB1 / APB2 Prescaler
RCC.d2cfgr().modify(|w| {
- w.set_d2ppre1(Dppre(ppre1_bits));
- w.set_d2ppre2(Dppre(ppre2_bits));
+ w.set_d2ppre1(Dppre::from_bits(ppre1_bits));
+ w.set_d2ppre2(Dppre::from_bits(ppre2_bits));
});
// APB4 Prescaler
- RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits)));
+ RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits)));
// Peripheral Clock (per_ck)
RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel));
@@ -640,7 +640,7 @@ pub(crate) unsafe fn init(mut config: Config) {
_ => Sw::HSI,
};
RCC.cfgr().modify(|w| w.set_sw(sw));
- while RCC.cfgr().read().sws() != sw.0 {}
+ while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {}
// IO compensation cell - Requires CSI clock and SYSCFG
assert!(RCC.cr().read().csirdy());
@@ -806,7 +806,8 @@ mod pll {
RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false));
let vco_ck = ref_x_ck * pll_x_n;
- RCC.plldivr(plln).modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8)));
+ RCC.plldivr(plln)
+ .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8)));
RCC.pllcfgr().modify(|w| w.set_divpen(plln, true));
// Calulate additional output dividers
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index d53b61069..46a528e31 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -293,7 +293,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
- let pre = 1 << (pre.0 as u32 - 7);
+ let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@@ -302,7 +302,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@@ -312,7 +312,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs
index c907fa88a..59a6eac8f 100644
--- a/embassy-stm32/src/rcc/l1.rs
+++ b/embassy-stm32/src/rcc/l1.rs
@@ -294,7 +294,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
- let pre = 1 << (pre.0 as u32 - 7);
+ let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@@ -303,7 +303,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@@ -313,7 +313,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs
index f8c1a6e06..20cb8c91c 100644
--- a/embassy-stm32/src/rcc/l4.rs
+++ b/embassy-stm32/src/rcc/l4.rs
@@ -635,7 +635,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
- let pre = 1 << (pre.0 as u32 - 7);
+ let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@@ -644,7 +644,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@@ -654,7 +654,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs
index f56fce365..16da65d5e 100644
--- a/embassy-stm32/src/rcc/l5.rs
+++ b/embassy-stm32/src/rcc/l5.rs
@@ -461,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) {
AHBPrescaler::NotDivided => sys_clk,
pre => {
let pre: Hpre = pre.into();
- let pre = 1 << (pre.0 as u32 - 7);
+ let pre = 1 << (pre.to_bits() as u32 - 7);
sys_clk / pre
}
};
@@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
@@ -480,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq),
pre => {
let pre: Ppre = pre.into();
- let pre: u8 = 1 << (pre.0 - 3);
+ let pre: u8 = 1 << (pre.to_bits() - 3);
let freq = ahb_freq / pre as u32;
(freq, freq * 2)
}
diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs
index 81507a4d6..cfc07f069 100644
--- a/embassy-stm32/src/rcc/u5.rs
+++ b/embassy-stm32/src/rcc/u5.rs
@@ -126,7 +126,7 @@ pub enum PllM {
impl Into for PllM {
fn into(self) -> Pllm {
- Pllm(self as u8)
+ Pllm::from_bits(self as u8)
}
}
diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs
index e1615b34c..a2eace6d3 100644
--- a/embassy-stm32/src/rtc/v2.rs
+++ b/embassy-stm32/src/rtc/v2.rs
@@ -36,7 +36,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
#[cfg(rtc_v2wb)]
let rtcsel = reg.rtcsel();
#[cfg(not(rtc_v2wb))]
- let rtcsel = reg.rtcsel().0;
+ let rtcsel = reg.rtcsel().to_bits();
if !reg.rtcen() || rtcsel != clock_config {
#[cfg(not(any(rtc_v2l0, rtc_v2l1)))]
@@ -54,7 +54,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
// Select RTC source
#[cfg(not(rtc_v2wb))]
- w.set_rtcsel(Rtcsel(clock_config));
+ w.set_rtcsel(Rtcsel::from_bits(clock_config));
#[cfg(rtc_v2wb)]
w.set_rtcsel(clock_config);
w.set_rtcen(true);
diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs
index 7c91046a2..7e5c64d90 100644
--- a/embassy-stm32/src/rtc/v3.rs
+++ b/embassy-stm32/src/rtc/v3.rs
@@ -26,7 +26,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> {
let config_rtcsel = rtc_config.clock_config as u8;
#[cfg(not(any(rcc_wl5, rcc_wle)))]
- let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel);
+ let config_rtcsel = crate::pac::rcc::vals::Rtcsel::from_bits(config_rtcsel);
if !reg.rtcen() || reg.rtcsel() != config_rtcsel {
crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true));
diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs
index 1cddac992..c3224073d 100644
--- a/embassy-stm32/src/spi/mod.rs
+++ b/embassy-stm32/src/spi/mod.rs
@@ -650,7 +650,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br {
_ => 0b111,
};
- Br(val)
+ Br::from_bits(val)
}
trait RegsExt {
@@ -772,7 +772,7 @@ fn set_rxdmaen(regs: Regs, val: bool) {
fn finish_dma(regs: Regs) {
#[cfg(spi_v2)]
- while regs.sr().read().ftlvl() > 0 {}
+ while regs.sr().read().ftlvl().to_bits() > 0 {}
#[cfg(any(spi_v3, spi_v4, spi_v5))]
while !regs.sr().read().txc() {}
diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs
index 47a79c187..c97efbf0a 100644
--- a/embassy-stm32/src/usart/mod.rs
+++ b/embassy-stm32/src/usart/mod.rs
@@ -869,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx:
_ => vals::Ps::EVEN,
});
#[cfg(not(usart_v1))]
- w.set_over8(vals::Over8(over8 as _));
+ w.set_over8(vals::Over8::from_bits(over8 as _));
});
#[cfg(not(usart_v1))]
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 01b158b17..ecdd1d0b8 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -97,8 +97,8 @@ impl interrupt::typelevel::Handler for InterruptHandl
}
epr.set_dtog_rx(false);
epr.set_dtog_tx(false);
- epr.set_stat_rx(Stat(0));
- epr.set_stat_tx(Stat(0));
+ epr.set_stat_rx(Stat::from_bits(0));
+ epr.set_stat_tx(Stat::from_bits(0));
epr.set_ctr_rx(!epr.ctr_rx());
epr.set_ctr_tx(!epr.ctr_tx());
regs.epr(index).write_value(epr);
@@ -143,8 +143,8 @@ fn invariant(mut r: regs::Epr) -> regs::Epr {
r.set_ctr_tx(true); // don't clear
r.set_dtog_rx(false); // don't toggle
r.set_dtog_tx(false); // don't toggle
- r.set_stat_rx(Stat(0));
- r.set_stat_tx(Stat(0));
+ r.set_stat_rx(Stat::from_bits(0));
+ r.set_stat_tx(Stat::from_bits(0));
r
}
@@ -551,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
true => Stat::STALL,
};
let mut w = invariant(r);
- w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
+ w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
}
@@ -570,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
true => Stat::STALL,
};
let mut w = invariant(r);
- w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
+ w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
}
@@ -606,7 +606,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
break;
}
let mut w = invariant(r);
- w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0));
+ w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
EP_IN_WAKERS[ep_addr.index()].wake();
@@ -622,7 +622,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
break;
}
let mut w = invariant(r);
- w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0));
+ w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits()));
reg.write_value(w);
}
EP_OUT_WAKERS[ep_addr.index()].wake();
@@ -763,8 +763,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
- w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
- w.set_stat_tx(Stat(0));
+ w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
+ w.set_stat_tx(Stat::from_bits(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@@ -805,8 +805,8 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> {
regs.epr(index).write(|w| {
w.set_ep_type(convert_type(self.info.ep_type));
w.set_ea(self.info.addr.index() as _);
- w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
- w.set_stat_rx(Stat(0));
+ w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
+ w.set_stat_rx(Stat::from_bits(0));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@@ -869,19 +869,19 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let mut stat_tx = 0;
if first {
// change NAK -> VALID
- stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0;
- stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0;
+ stat_rx ^= Stat::NAK.to_bits() ^ Stat::VALID.to_bits();
+ stat_tx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
}
if last {
// change STALL -> VALID
- stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0;
+ stat_tx ^= Stat::STALL.to_bits() ^ Stat::NAK.to_bits();
}
// Note: if this is the first AND last transfer, the above effectively
// changes stat_tx like NAK -> NAK, so noop.
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
- w.set_stat_rx(Stat(stat_rx));
- w.set_stat_tx(Stat(stat_tx));
+ w.set_stat_rx(Stat::from_bits(stat_rx));
+ w.set_stat_tx(Stat::from_bits(stat_tx));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@@ -908,11 +908,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
- w.set_stat_rx(Stat(match last {
+ w.set_stat_rx(Stat::from_bits(match last {
// If last, set STAT_RX=STALL.
- true => Stat::NAK.0 ^ Stat::STALL.0,
+ true => Stat::NAK.to_bits() ^ Stat::STALL.to_bits(),
// Otherwise, set STAT_RX=VALID, to allow the host to send the next packet.
- false => Stat::NAK.0 ^ Stat::VALID.0,
+ false => Stat::NAK.to_bits() ^ Stat::VALID.to_bits(),
}));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
@@ -937,17 +937,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let mut stat_rx = 0;
if first {
// change NAK -> STALL
- stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0;
+ stat_rx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits();
}
if last {
// change STALL -> VALID
- stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0;
+ stat_rx ^= Stat::STALL.to_bits() ^ Stat::VALID.to_bits();
}
// Note: if this is the first AND last transfer, the above effectively
// does a change of NAK -> VALID.
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
- w.set_stat_rx(Stat(stat_rx));
+ w.set_stat_rx(Stat::from_bits(stat_rx));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
@@ -977,7 +977,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let regs = T::regs();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
- w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0));
+ w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits()));
w.set_ep_kind(last); // set OUT_STATUS if last.
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
@@ -998,8 +998,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
- w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
- w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0));
+ w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
+ w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::VALID.to_bits()));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
@@ -1029,8 +1029,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> {
let epr = regs.epr(0).read();
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
- w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0));
- w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0));
+ w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits()));
+ w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::STALL.to_bits()));
w.set_ctr_rx(true); // don't clear
w.set_ctr_tx(true); // don't clear
});
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 6c00c93d6..6783db28d 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -97,7 +97,7 @@ impl interrupt::typelevel::Handler for InterruptHandl
vals::Pktstsd::SETUP_DATA_DONE => {
trace!("SETUP_DATA_DONE ep={}", ep_num);
}
- x => trace!("unknown PKTSTS: {}", x.0),
+ x => trace!("unknown PKTSTS: {}", x.to_bits()),
}
}
@@ -920,7 +920,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
trace!("enumdne");
let speed = r.dsts().read().enumspd();
- trace!(" speed={}", speed.0);
+ trace!(" speed={}", speed.to_bits());
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs
index 5907a4e54..b03e81d6e 100644
--- a/embassy-stm32/src/wdg/mod.rs
+++ b/embassy-stm32/src/wdg/mod.rs
@@ -49,7 +49,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> {
let wdg = T::regs();
wdg.kr().write(|w| w.set_key(Key::ENABLE));
- wdg.pr().write(|w| w.set_pr(Pr(pr)));
+ wdg.pr().write(|w| w.set_pr(Pr::from_bits(pr)));
wdg.rlr().write(|w| w.set_rl(rl));
trace!(
From ce889900d63f9f32f1a6b7540834d6f9558239e4 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 29 Jun 2023 02:08:55 +0200
Subject: [PATCH 65/74] Update rp-pac.
---
embassy-rp/Cargo.toml | 2 +-
embassy-rp/src/clocks.rs | 92 ++++++++++++++++++++--------------------
embassy-rp/src/gpio.rs | 4 +-
embassy-rp/src/pio.rs | 4 +-
4 files changed, 51 insertions(+), 51 deletions(-)
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 49aa6a4d5..66823771a 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -76,7 +76,7 @@ embedded-storage = { version = "0.3" }
rand_core = "0.6.4"
fixed = "1.23.1"
-rp-pac = { version = "5" }
+rp-pac = { version = "6" }
embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] }
embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true}
diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs
index 4c6223107..ddd61d224 100644
--- a/embassy-rp/src/clocks.rs
+++ b/embassy-rp/src/clocks.rs
@@ -46,13 +46,13 @@ static CLOCKS: Clocks = Clocks {
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PeriClkSrc {
- Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0,
- PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0,
- PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0,
- Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0,
- Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0,
- // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0,
- // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0,
+ Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _,
+ PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _,
+ PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _,
+ Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _,
+ Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _,
+ // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
+ // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
}
#[non_exhaustive]
@@ -251,12 +251,12 @@ pub struct SysClkConfig {
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum UsbClkSrc {
- PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0,
- PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0,
- Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0,
- Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0,
- // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0,
- // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0,
+ PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _,
+ PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _,
+ Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _,
+ Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _,
+ // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
+ // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
}
pub struct UsbClkConfig {
@@ -269,12 +269,12 @@ pub struct UsbClkConfig {
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum AdcClkSrc {
- PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0,
- PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0,
- Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0,
- Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0,
- // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0,
- // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0,
+ PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _,
+ PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
+ Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
+ Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _,
+ // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
+ // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
}
pub struct AdcClkConfig {
@@ -287,12 +287,12 @@ pub struct AdcClkConfig {
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RtcClkSrc {
- PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0,
- PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0,
- Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0,
- Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0,
- // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0,
- // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0,
+ PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _,
+ PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _,
+ Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _,
+ Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _,
+ // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
+ // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
}
pub struct RtcClkConfig {
@@ -396,7 +396,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
w.set_src(ref_src);
w.set_auxsrc(ref_aux);
});
- while c.clk_ref_selected().read() != 1 << ref_src.0 {}
+ while c.clk_ref_selected().read() != 1 << ref_src as u32 {}
c.clk_ref_div().write(|w| {
w.set_int(config.ref_clk.div);
});
@@ -425,13 +425,13 @@ pub(crate) unsafe fn init(config: ClockConfig) {
CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed);
if sys_src != ClkSysCtrlSrc::CLK_REF {
c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF));
- while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {}
+ while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {}
}
c.clk_sys_ctrl().write(|w| {
w.set_auxsrc(sys_aux);
w.set_src(sys_src);
});
- while c.clk_sys_selected().read() != 1 << sys_src.0 {}
+ while c.clk_sys_selected().read() != 1 << sys_src as u32 {}
c.clk_sys_div().write(|w| {
w.set_int(config.sys_clk.div_int);
w.set_frac(config.sys_clk.div_frac);
@@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
if let Some(src) = config.peri_clk_src {
c.clk_peri_ctrl().write(|w| {
w.set_enable(true);
- w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _));
+ w.set_auxsrc(ClkPeriCtrlAuxsrc::from_bits(src as _));
});
let peri_freq = match src {
PeriClkSrc::Sys => clk_sys_freq,
@@ -468,7 +468,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_usb_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true);
- w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _));
+ w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _));
});
let usb_freq = match conf.src {
UsbClkSrc::PllUsb => pll_usb_freq,
@@ -491,7 +491,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_adc_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true);
- w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _));
+ w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _));
});
let adc_in_freq = match conf.src {
AdcClkSrc::PllUsb => pll_usb_freq,
@@ -517,7 +517,7 @@ pub(crate) unsafe fn init(config: ClockConfig) {
c.clk_rtc_ctrl().write(|w| {
w.set_phase(conf.phase);
w.set_enable(true);
- w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _));
+ w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _));
});
let rtc_in_freq = match conf.src {
RtcClkSrc::PllUsb => pll_usb_freq,
@@ -718,7 +718,7 @@ impl<'d, T: Pin> Drop for Gpin<'d, T> {
self.gpin
.io()
.ctrl()
- .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
+ .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _));
}
}
@@ -743,17 +743,17 @@ impl_gpoutpin!(PIN_25, 3);
#[repr(u8)]
pub enum GpoutSrc {
- PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0,
- // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0,
- // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0,
- PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0,
- Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0,
- Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0,
- Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0,
- Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0,
- Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0,
- Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0,
- Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0,
+ PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _,
+ // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ ,
+ // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ ,
+ PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _,
+ Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _,
+ Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _,
+ Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _,
+ Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _,
+ Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _,
+ Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _,
+ Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _,
}
pub struct Gpout<'d, T: GpoutPin> {
@@ -780,7 +780,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> {
pub fn set_src(&self, src: GpoutSrc) {
let c = pac::CLOCKS;
c.clk_gpout_ctrl(self.gpout.number()).modify(|w| {
- w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _));
+ w.set_auxsrc(ClkGpoutCtrlAuxsrc::from_bits(src as _));
});
}
@@ -831,7 +831,7 @@ impl<'d, T: GpoutPin> Drop for Gpout<'d, T> {
self.gpout
.io()
.ctrl()
- .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0));
+ .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _));
}
}
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index ce0d02557..f8048a4dd 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -452,7 +452,7 @@ impl<'d, T: Pin> Flex<'d, T> {
});
pin.io().ctrl().write(|w| {
- w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0);
+ w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _);
});
Self { pin }
@@ -618,7 +618,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> {
fn drop(&mut self) {
self.pin.pad_ctrl().write(|_| {});
self.pin.io().ctrl().write(|w| {
- w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0);
+ w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _);
});
}
}
diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs
index 1b36e0a54..30648e8ea 100644
--- a/embassy-rp/src/pio.rs
+++ b/embassy-rp/src/pio.rs
@@ -834,7 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> {
/// of [`Pio`] do not keep pin registrations alive.**
pub fn make_pio_pin(&mut self, pin: impl Peripheral + 'd) -> Pin<'d, PIO> {
into_ref!(pin);
- pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0));
+ pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _));
// we can be relaxed about this because we're &mut here and nothing is cached
PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed);
Pin {
@@ -998,7 +998,7 @@ fn on_pio_drop