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: implement mwe of a DMA write() method for DAC
---
embassy-stm32/build.rs | 2 +
embassy-stm32/src/dac.rs | 278 -----------------------------------
embassy-stm32/src/dac/mod.rs | 340 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 342 insertions(+), 278 deletions(-)
delete mode 100644 embassy-stm32/src/dac.rs
create mode 100644 embassy-stm32/src/dac/mod.rs
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.rs
deleted file mode 100644
index 60e856c78..000000000
--- a/embassy-stm32/src/dac.rs
+++ /dev/null
@@ -1,278 +0,0 @@
-#![macro_use]
-
-use embassy_hal_common::{into_ref, PeripheralRef};
-
-use crate::pac::dac;
-use crate::rcc::RccPeripheral;
-use crate::{peripherals, Peripheral};
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Error {
- UnconfiguredChannel,
- InvalidValue,
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Channel {
- Ch1,
- Ch2,
-}
-
-impl Channel {
- fn index(&self) -> usize {
- match self {
- Channel::Ch1 => 0,
- Channel::Ch2 => 1,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Ch1Trigger {
- Tim6,
- Tim3,
- Tim7,
- Tim15,
- Tim2,
- Exti9,
- Software,
-}
-
-impl Ch1Trigger {
- fn tsel(&self) -> dac::vals::Tsel1 {
- match self {
- Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
- Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
- Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
- Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
- Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
- Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
- Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub enum Ch2Trigger {
- Tim6,
- Tim8,
- Tim7,
- Tim5,
- Tim2,
- Tim4,
- Exti9,
- Software,
-}
-
-impl Ch2Trigger {
- fn tsel(&self) -> dac::vals::Tsel2 {
- match self {
- Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
- Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
- Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
- Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
- Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
- Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
- Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
- Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
- }
- }
-}
-
-#[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 {
- Bit8(u8),
- Bit12(u16, Alignment),
-}
-
-pub struct Dac<'d, T: Instance> {
- channels: u8,
- _peri: PeripheralRef<'d, T>,
-}
-
-impl<'d, T: Instance> Dac<'d, T> {
- pub fn new_1ch(peri: impl Peripheral
+ 'd, _ch1: impl Peripheral
> + 'd) -> Self {
- into_ref!(peri);
- Self::new_inner(peri, 1)
- }
-
- pub fn new_2ch(
- peri: impl Peripheral
+ 'd,
- _ch1: impl Peripheral
> + 'd,
- _ch2: impl Peripheral
> + 'd,
- ) -> Self {
- into_ref!(peri);
- Self::new_inner(peri, 2)
- }
-
- fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self {
- T::enable();
- T::reset();
-
- unsafe {
- T::regs().cr().modify(|reg| {
- for ch in 0..channels {
- reg.set_en(ch as usize, true);
- }
- });
- }
-
- Self { channels, _peri: peri }
- }
-
- /// Check the channel is configured
- fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
- if ch == Channel::Ch2 && self.channels < 2 {
- Err(Error::UnconfiguredChannel)
- } else {
- Ok(())
- }
- }
-
- 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);
- })
- }
- Ok(())
- }
-
- pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
- self.set_channel_enable(ch, true)
- }
-
- pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
- self.set_channel_enable(ch, false)
- }
-
- 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());
- })
- }
- Ok(())
- }
-
- 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());
- })
- }
- Ok(())
- }
-
- 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);
- });
- }
- Ok(())
- }
-
- 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);
- })
- }
- }
-
- 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));
- },
- }
- Ok(())
- }
-}
-
-pub(crate) mod sealed {
- pub trait Instance {
- fn regs() -> &'static crate::pac::dac::Dac;
- }
-}
-
-pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
-
-pub trait DacPin: crate::gpio::Pin + 'static {}
-
-foreach_peripheral!(
- (dac, $inst:ident) => {
- // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
- #[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
- })
- }
-
- fn reset() {
- critical_section::with(|_| unsafe {
- 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 {
- 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));
- })
- }
- }
-
- #[cfg(rcc_h7)]
- impl crate::rcc::RccPeripheral for peripherals::$inst {}
-
- impl crate::dac::sealed::Instance for peripherals::$inst {
- fn regs() -> &'static crate::pac::dac::Dac {
- &crate::pac::$inst
- }
- }
-
- impl crate::dac::Instance for peripherals::$inst {}
- };
-);
-
-macro_rules! impl_dac_pin {
- ($inst:ident, $pin:ident, $ch:expr) => {
- impl crate::dac::DacPin for crate::peripherals::$pin {}
- };
-}
diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs
new file mode 100644
index 000000000..348d8bccd
--- /dev/null
+++ b/embassy-stm32/src/dac/mod.rs
@@ -0,0 +1,340 @@
+#![macro_use]
+
+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};
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Error {
+ UnconfiguredChannel,
+ InvalidValue,
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Channel {
+ Ch1,
+ Ch2,
+}
+
+impl Channel {
+ fn index(&self) -> usize {
+ match self {
+ Channel::Ch1 => 0,
+ Channel::Ch2 => 1,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Ch1Trigger {
+ Tim6,
+ Tim3,
+ Tim7,
+ Tim15,
+ Tim2,
+ Exti9,
+ Software,
+}
+
+impl Ch1Trigger {
+ fn tsel(&self) -> dac::vals::Tsel1 {
+ match self {
+ Ch1Trigger::Tim6 => dac::vals::Tsel1::TIM6_TRGO,
+ Ch1Trigger::Tim3 => dac::vals::Tsel1::TIM3_TRGO,
+ Ch1Trigger::Tim7 => dac::vals::Tsel1::TIM7_TRGO,
+ Ch1Trigger::Tim15 => dac::vals::Tsel1::TIM15_TRGO,
+ Ch1Trigger::Tim2 => dac::vals::Tsel1::TIM2_TRGO,
+ Ch1Trigger::Exti9 => dac::vals::Tsel1::EXTI9,
+ Ch1Trigger::Software => dac::vals::Tsel1::SOFTWARE,
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum Ch2Trigger {
+ Tim6,
+ Tim8,
+ Tim7,
+ Tim5,
+ Tim2,
+ Tim4,
+ Exti9,
+ Software,
+}
+
+impl Ch2Trigger {
+ fn tsel(&self) -> dac::vals::Tsel2 {
+ match self {
+ Ch2Trigger::Tim6 => dac::vals::Tsel2::TIM6_TRGO,
+ Ch2Trigger::Tim8 => dac::vals::Tsel2::TIM8_TRGO,
+ Ch2Trigger::Tim7 => dac::vals::Tsel2::TIM7_TRGO,
+ Ch2Trigger::Tim5 => dac::vals::Tsel2::TIM5_TRGO,
+ Ch2Trigger::Tim2 => dac::vals::Tsel2::TIM2_TRGO,
+ Ch2Trigger::Tim4 => dac::vals::Tsel2::TIM4_TRGO,
+ Ch2Trigger::Exti9 => dac::vals::Tsel2::EXTI9,
+ Ch2Trigger::Software => dac::vals::Tsel2::SOFTWARE,
+ }
+ }
+}
+
+#[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 {
+ Bit8(u8),
+ Bit12(u16, Alignment),
+}
+
+pub struct Dac<'d, T: Instance, Tx> {
+ channels: u8,
+ txdma: PeripheralRef<'d, Tx>,
+ _peri: PeripheralRef<'d, T>,
+}
+
+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, 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, txdma)
+ }
+
+ 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,
+ txdma,
+ _peri: peri,
+ }
+ }
+
+ /// Check the channel is configured
+ fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> {
+ if ch == Channel::Ch2 && self.channels < 2 {
+ Err(Error::UnconfiguredChannel)
+ } else {
+ Ok(())
+ }
+ }
+
+ 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);
+ })
+ }
+ Ok(())
+ }
+
+ pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> {
+ self.set_channel_enable(ch, true)
+ }
+
+ pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> {
+ self.set_channel_enable(ch, false)
+ }
+
+ 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());
+ })
+ }
+ Ok(())
+ }
+
+ 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());
+ })
+ }
+ Ok(())
+ }
+
+ 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);
+ });
+ }
+ Ok(())
+ }
+
+ 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);
+ })
+ }
+ }
+
+ 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));
+ },
+ }
+ 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 {
+ pub trait Instance {
+ fn regs() -> &'static crate::pac::dac::Dac;
+ }
+}
+
+pub trait Instance: sealed::Instance + RccPeripheral + 'static {}
+dma_trait!(Dma, Instance);
+
+pub trait DacPin: crate::gpio::Pin + 'static {}
+
+foreach_peripheral!(
+ (dac, $inst:ident) => {
+ // H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
+ #[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
+ })
+ }
+
+ fn reset() {
+ critical_section::with(|_| unsafe {
+ 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 {
+ 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));
+ })
+ }
+ }
+
+ #[cfg(rcc_h7)]
+ impl crate::rcc::RccPeripheral for peripherals::$inst {}
+
+ impl crate::dac::sealed::Instance for peripherals::$inst {
+ fn regs() -> &'static crate::pac::dac::Dac {
+ &crate::pac::$inst
+ }
+ }
+
+ impl crate::dac::Instance for peripherals::$inst {}
+ };
+);
+
+macro_rules! impl_dac_pin {
+ ($inst:ident, $pin:ident, $ch:expr) => {
+ impl crate::dac::DacPin for crate::peripherals::$pin {}
+ };
+}
--
cgit
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: 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(())
--
cgit
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: 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);
--
cgit
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: 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)
}
--
cgit
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: add ValueArray type and respective write functions
---
embassy-stm32/src/dac/mod.rs | 210 ++++++++++++++++++++++++++-----------------
1 file changed, 126 insertions(+), 84 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().cr().modify(|reg| {
- for ch in 0..channels {
- reg.set_en(ch as usize, true);
- reg.set_ten(ch as usize, true);
- }
- });
- }
+ 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,
@@ -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?
-
- 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);
- });
- }
+ // 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(())
}
}
--
cgit
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: 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(())
}
--
cgit
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: 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");
--
cgit
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: 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,
{
--
cgit
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: 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);
--
cgit
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: 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,
},
)
},
--
cgit
From cd4f8f13a2c533f4e752c2e446661a6d86b19fe6 Mon Sep 17 00:00:00 2001
From: goueslati
Date: Thu, 22 Jun 2023 15:21:14 +0100
Subject: 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
+}
--
cgit
From 810c6af77af037a658186f8b102980ee84164a05 Mon Sep 17 00:00:00 2001
From: goueslati
Date: Thu, 22 Jun 2023 15:31:45 +0100
Subject: 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());
--
cgit
From 3dbd58f40e07eb4b5d41a671aec0fe71ac8c4b34 Mon Sep 17 00:00:00 2001
From: goueslati
Date: Thu, 22 Jun 2023 15:59:03 +0100
Subject: 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();
--
cgit
From 6c123596b7d48ee66ea93e8b1515e91231e9bced Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Fri, 9 Jun 2023 03:36:48 +0200
Subject: wip: esp-hosted net driver.
---
embassy-net-esp-hosted/Cargo.toml | 20 +
embassy-net-esp-hosted/src/control.rs | 141 +++++
embassy-net-esp-hosted/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;
+ }
+ };
+ }
+ }
+}
--
cgit
From ec2c095a76a0f55a031093e98a5283cff0daa576 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 18:13:19 +0200
Subject: 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,
--
cgit
From 082f1ab494587e02d405cad8f186d48943acf16d Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 18:55:29 +0200
Subject: esp-hosted: nicer names for shared state struct.
---
embassy-net-esp-hosted/src/control.rs | 16 +++---
embassy-net-esp-hosted/src/ioctl.rs | 91 ++++++++++++++---------------------
embassy-net-esp-hosted/src/lib.rs | 16 +++---
3 files changed, 52 insertions(+), 71 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,
-}
-
-impl Default for Wakers {
- fn default() -> Self {
- Self {
- control: WakerRegistration::new(),
- runner: WakerRegistration::new(),
- }
- }
-}
+pub struct Shared(RefCell);
-pub struct IoctlState {
- state: Cell,
- wakers: RefCell,
+struct SharedInner {
+ ioctl: IoctlState,
+ control_waker: WakerRegistration,
+ runner_waker: WakerRegistration,
}
-impl IoctlState {
+impl Shared {
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();
+ Self(RefCell::new(SharedInner {
+ ioctl: IoctlState::Done { resp_len: 0 },
+ control_waker: WakerRegistration::new(),
+ runner_waker: WakerRegistration::new(),
+ }))
}
- 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),
--
cgit
From 764b43e82c7b61c21621c1fd9f5fd2f6a3dc419c Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 19:05:20 +0200
Subject: 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;
--
cgit
From 1ed909ea74bfff75bd91b35739a44c5128271571 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Wed, 21 Jun 2023 19:08:09 +0200
Subject: 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;
--
cgit
From 0d02298ea628b9d2154fd05db7975f62b8d12edb Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 22 Jun 2023 15:30:26 +0200
Subject: 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 }
--
cgit
From 6e65282f185d94a8c449374e6d4ed4eefa5793a4 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 22 Jun 2023 21:10:58 +0200
Subject: 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;
}
--
cgit
From 8bbfa6827cd68f67a50a89b13947542e632d5411 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Thu, 22 Jun 2023 21:11:53 +0200
Subject: 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
));
--
cgit
From 23c51a18741c4c500c46955b5cd028ec0eb7d53a Mon Sep 17 00:00:00 2001
From: Dietrich Beck
Date: Thu, 22 Jun 2023 23:02:16 +0200
Subject: 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 {
--
cgit
From 558247d8f60dbdebf5f3df3a632d9e32fe0f0277 Mon Sep 17 00:00:00 2001
From: GhaithOueslati
Date: Thu, 22 Jun 2023 22:51:38 +0100
Subject: 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]) {
--
cgit
From 64ff1a6b75aa13797cf64bb97e597f333a2ae9b6 Mon Sep 17 00:00:00 2001
From: GhaithOueslati
Date: Thu, 22 Jun 2023 22:53:07 +0100
Subject: 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"]
--
cgit
From caf63b9e7336ed3ddb0dc997d431f15a26ae7693 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Thu, 22 Jun 2023 21:05:51 -0500
Subject: 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 | 221 ++++++++++++++++++++++++++++----
5 files changed, 207 insertions(+), 26 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);
-
- 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
+ let mut mbox = TlMbox::init(p.IPCC, Irqs, config);
- info!("sys event {:x} : {:x}", ready_event.stub().kind, ready_event.payload());
+ // spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap();
- // 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;
+
+ info!("resetting BLE...");
+ mbox.ble_subsystem.reset().await;
+ let response = mbox.ble_subsystem.read().await.unwrap();
+ 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();
+ 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();
+ 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();
+ 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 result = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await;
- info!("subsystem initialization: {}", result);
+ 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;
- info!("starting ble...");
- mbox.ble_subsystem.tl_write(0x0c, &[]).await;
+ BdAddr(bytes)
+}
- info!("waiting for ble...");
- let ble_event = mbox.ble_subsystem.tl_read().await;
+fn get_random_addr() -> BdAddr {
+ let mut bytes = [0u8; 6];
- info!("ble event {:x} : {:x}", ble_event.stub().kind, ble_event.payload());
+ 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;
- info!("Test OK");
- cortex_m::asm::bkpt();
+ 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
}
--
cgit
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: 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,
}
}
}
--
cgit
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: allow independent use of ch1 and ch2 on dac
---
embassy-stm32/src/dac/mod.rs | 150 ++++++++++++++++++++++++++++---------------
1 file changed, 100 insertions(+), 50 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
+ /// **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,
+ {
+ 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.
///
- pub async fn write(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error>
+ /// **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,
{
- // TODO: Make this a parameter or get it from the struct or so...
- const CHANNEL: usize = 0;
+ 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(())
--
cgit
From 29f32ce00ec0f50ef5e3b29c7e50f7f5479b4967 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 17:54:06 -0500
Subject: stm32/wpan: reorg subsystems
---
embassy-stm32-wpan/src/ble.rs | 79 -------------------
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/mac.rs | 111 ---------------------------
embassy-stm32-wpan/src/mm.rs | 79 -------------------
embassy-stm32-wpan/src/sub/ble.rs | 79 +++++++++++++++++++
embassy-stm32-wpan/src/sub/mac.rs | 111 +++++++++++++++++++++++++++
embassy-stm32-wpan/src/sub/mm.rs | 79 +++++++++++++++++++
embassy-stm32-wpan/src/sub/mod.rs | 6 ++
embassy-stm32-wpan/src/sub/sys.rs | 86 +++++++++++++++++++++
embassy-stm32-wpan/src/sys.rs | 86 ---------------------
examples/stm32wb/src/bin/eddystone_beacon.rs | 14 ++--
tests/stm32/src/bin/tl_mbox.rs | 17 ++--
14 files changed, 396 insertions(+), 389 deletions(-)
delete mode 100644 embassy-stm32-wpan/src/ble.rs
delete mode 100644 embassy-stm32-wpan/src/mac.rs
delete mode 100644 embassy-stm32-wpan/src/mm.rs
create mode 100644 embassy-stm32-wpan/src/sub/ble.rs
create mode 100644 embassy-stm32-wpan/src/sub/mac.rs
create mode 100644 embassy-stm32-wpan/src/sub/mm.rs
create mode 100644 embassy-stm32-wpan/src/sub/mod.rs
create mode 100644 embassy-stm32-wpan/src/sub/sys.rs
delete mode 100644 embassy-stm32-wpan/src/sys.rs
diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs
deleted file mode 100644
index 619cd66a0..000000000
--- a/embassy-stm32-wpan/src/ble.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-use core::marker::PhantomData;
-
-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::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
-use crate::unsafe_linked_list::LinkedListNode;
-
-pub struct Ble {
- phantom: PhantomData,
-}
-
-impl Ble {
- pub(crate) fn new() -> Self {
- unsafe {
- LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
-
- TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
- pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
- pcs_buffer: CS_BUFFER.as_ptr().cast(),
- pevt_queue: EVT_QUEUE.as_ptr().cast(),
- phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
- });
- }
-
- Self { phantom: PhantomData }
- }
- /// `HW_IPCC_BLE_EvtNot`
- 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()))
- } else {
- None
- }
- })
- .await
- }
-
- /// `TL_BLE_SendCmd`
- 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);
- })
- .await;
- }
-
- /// `TL_BLE_SendAclData`
- pub async fn acl_write(&self, handle: u16, payload: &[u8]) {
- Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe {
- CmdPacket::write_into(
- HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _,
- TlPacketType::AclData,
- handle,
- payload,
- );
- })
- .await;
- }
-}
-
-pub extern crate stm32wb_hci 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_into(&self, buf: &mut [u8]) {
- let evt_box = self.tl_read().await;
- let evt_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 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/mac.rs b/embassy-stm32-wpan/src/mac.rs
deleted file mode 100644
index d2be1b85c..000000000
--- a/embassy-stm32-wpan/src/mac.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-use core::future::poll_fn;
-use core::marker::PhantomData;
-use core::ptr;
-use core::sync::atomic::{AtomicBool, Ordering};
-use core::task::Poll;
-
-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,
-};
-
-static MAC_WAKER: AtomicWaker = AtomicWaker::new();
-static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
-
-pub struct Mac {
- phantom: PhantomData,
-}
-
-impl Mac {
- pub(crate) fn new() -> Self {
- unsafe {
- TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
- p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
- p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
- evt_queue: ptr::null_mut(),
- });
- }
-
- 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 {
- // Wait for the last event box to be dropped
- poll_fn(|cx| {
- MAC_WAKER.register(cx.waker());
- if MAC_EVT_OUT.load(Ordering::SeqCst) {
- Poll::Pending
- } else {
- Poll::Ready(())
- }
- })
- .await;
-
- // Return a new event box
- Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe {
- // The closure is not async, therefore the closure must execute to completion (cannot be dropped)
- // Therefore, the event box is guaranteed to be cleaned up if it's not leaked
- MAC_EVT_OUT.store(true, Ordering::SeqCst);
-
- Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _))
- })
- .await
- }
-
- /// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
- pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
- self.write(opcode, payload).await;
- Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
-
- unsafe {
- let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
- let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8;
-
- ptr::read_volatile(p_mac_rsp_evt)
- }
- }
-
- /// `TL_MAC_802_15_4_SendCmd`
- pub async fn write(&self, opcode: u16, payload: &[u8]) {
- Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
- CmdPacket::write_into(
- MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
- TlPacketType::OtCmd,
- opcode,
- payload,
- );
- })
- .await;
- }
-}
diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/mm.rs
deleted file mode 100644
index 047fddcd4..000000000
--- a/embassy-stm32-wpan/src/mm.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-//! Memory manager routines
-use core::future::poll_fn;
-use core::marker::PhantomData;
-use core::mem::MaybeUninit;
-use core::task::Poll;
-
-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;
-
-static MM_WAKER: AtomicWaker = AtomicWaker::new();
-static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit();
-
-pub struct MemoryManager {
- phantom: PhantomData,
-}
-
-impl MemoryManager {
- pub(crate) fn new() -> Self {
- unsafe {
- LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
- LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
-
- TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
- spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
- spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
- blepool: EVT_POOL.as_ptr().cast(),
- blepoolsize: POOL_SIZE as u32,
- pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
- traces_evt_pool: core::ptr::null(),
- tracespoolsize: 0,
- });
- }
-
- 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 {
- MM_WAKER.register(cx.waker());
- if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
- Poll::Pending
- } else {
- Poll::Ready(())
- }
- })
- .await;
-
- Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || {
- interrupt::free(|_| unsafe {
- // CS required while moving nodes
- while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
- LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
- }
- })
- })
- .await;
- }
- }
-}
diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs
new file mode 100644
index 000000000..619cd66a0
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/ble.rs
@@ -0,0 +1,79 @@
+use core::marker::PhantomData;
+
+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::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE};
+use crate::unsafe_linked_list::LinkedListNode;
+
+pub struct Ble {
+ phantom: PhantomData,
+}
+
+impl Ble {
+ pub(crate) fn new() -> Self {
+ unsafe {
+ LinkedListNode::init_head(EVT_QUEUE.as_mut_ptr());
+
+ TL_BLE_TABLE.as_mut_ptr().write_volatile(BleTable {
+ pcmd_buffer: BLE_CMD_BUFFER.as_mut_ptr().cast(),
+ pcs_buffer: CS_BUFFER.as_ptr().cast(),
+ pevt_queue: EVT_QUEUE.as_ptr().cast(),
+ phci_acl_data_buffer: HCI_ACL_DATA_BUFFER.as_mut_ptr().cast(),
+ });
+ }
+
+ Self { phantom: PhantomData }
+ }
+ /// `HW_IPCC_BLE_EvtNot`
+ 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()))
+ } else {
+ None
+ }
+ })
+ .await
+ }
+
+ /// `TL_BLE_SendCmd`
+ 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);
+ })
+ .await;
+ }
+
+ /// `TL_BLE_SendAclData`
+ pub async fn acl_write(&self, handle: u16, payload: &[u8]) {
+ Ipcc::send(channels::cpu1::IPCC_HCI_ACL_DATA_CHANNEL, || unsafe {
+ CmdPacket::write_into(
+ HCI_ACL_DATA_BUFFER.as_mut_ptr() as *mut _,
+ TlPacketType::AclData,
+ handle,
+ payload,
+ );
+ })
+ .await;
+ }
+}
+
+pub extern crate stm32wb_hci 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_into(&self, buf: &mut [u8]) {
+ let evt_box = self.tl_read().await;
+ let evt_serial = evt_box.serial();
+
+ buf[..evt_serial.len()].copy_from_slice(evt_serial);
+ }
+}
diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs
new file mode 100644
index 000000000..d2be1b85c
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mac.rs
@@ -0,0 +1,111 @@
+use core::future::poll_fn;
+use core::marker::PhantomData;
+use core::ptr;
+use core::sync::atomic::{AtomicBool, Ordering};
+use core::task::Poll;
+
+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,
+};
+
+static MAC_WAKER: AtomicWaker = AtomicWaker::new();
+static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false);
+
+pub struct Mac {
+ phantom: PhantomData,
+}
+
+impl Mac {
+ pub(crate) fn new() -> Self {
+ unsafe {
+ TL_MAC_802_15_4_TABLE.as_mut_ptr().write_volatile(Mac802_15_4Table {
+ p_cmdrsp_buffer: MAC_802_15_4_CMD_BUFFER.as_mut_ptr().cast(),
+ p_notack_buffer: MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr().cast(),
+ evt_queue: ptr::null_mut(),
+ });
+ }
+
+ 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 {
+ // Wait for the last event box to be dropped
+ poll_fn(|cx| {
+ MAC_WAKER.register(cx.waker());
+ if MAC_EVT_OUT.load(Ordering::SeqCst) {
+ Poll::Pending
+ } else {
+ Poll::Ready(())
+ }
+ })
+ .await;
+
+ // Return a new event box
+ Ipcc::receive(channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, || unsafe {
+ // The closure is not async, therefore the closure must execute to completion (cannot be dropped)
+ // Therefore, the event box is guaranteed to be cleaned up if it's not leaked
+ MAC_EVT_OUT.store(true, Ordering::SeqCst);
+
+ Some(EvtBox::new(MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _))
+ })
+ .await
+ }
+
+ /// `HW_IPCC_MAC_802_15_4_CmdEvtNot`
+ pub async fn write_and_get_response(&self, opcode: u16, payload: &[u8]) -> u8 {
+ self.write(opcode, payload).await;
+ Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
+
+ unsafe {
+ let p_event_packet = MAC_802_15_4_CMD_BUFFER.as_ptr() as *const EvtPacket;
+ let p_mac_rsp_evt = &((*p_event_packet).evt_serial.evt.payload) as *const u8;
+
+ ptr::read_volatile(p_mac_rsp_evt)
+ }
+ }
+
+ /// `TL_MAC_802_15_4_SendCmd`
+ pub async fn write(&self, opcode: u16, payload: &[u8]) {
+ Ipcc::send(channels::cpu1::IPCC_MAC_802_15_4_CMD_RSP_CHANNEL, || unsafe {
+ CmdPacket::write_into(
+ MAC_802_15_4_CMD_BUFFER.as_mut_ptr(),
+ TlPacketType::OtCmd,
+ opcode,
+ payload,
+ );
+ })
+ .await;
+ }
+}
diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs
new file mode 100644
index 000000000..047fddcd4
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/mm.rs
@@ -0,0 +1,79 @@
+//! Memory manager routines
+use core::future::poll_fn;
+use core::marker::PhantomData;
+use core::mem::MaybeUninit;
+use core::task::Poll;
+
+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;
+
+static MM_WAKER: AtomicWaker = AtomicWaker::new();
+static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit();
+
+pub struct MemoryManager {
+ phantom: PhantomData,
+}
+
+impl MemoryManager {
+ pub(crate) fn new() -> Self {
+ unsafe {
+ LinkedListNode::init_head(FREE_BUF_QUEUE.as_mut_ptr());
+ LinkedListNode::init_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr());
+
+ TL_MEM_MANAGER_TABLE.as_mut_ptr().write_volatile(MemManagerTable {
+ spare_ble_buffer: BLE_SPARE_EVT_BUF.as_ptr().cast(),
+ spare_sys_buffer: SYS_SPARE_EVT_BUF.as_ptr().cast(),
+ blepool: EVT_POOL.as_ptr().cast(),
+ blepoolsize: POOL_SIZE as u32,
+ pevt_free_buffer_queue: FREE_BUF_QUEUE.as_mut_ptr(),
+ traces_evt_pool: core::ptr::null(),
+ tracespoolsize: 0,
+ });
+ }
+
+ 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 {
+ MM_WAKER.register(cx.waker());
+ if LinkedListNode::is_empty(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
+ Poll::Pending
+ } else {
+ Poll::Ready(())
+ }
+ })
+ .await;
+
+ Ipcc::send(channels::cpu1::IPCC_MM_RELEASE_BUFFER_CHANNEL, || {
+ interrupt::free(|_| unsafe {
+ // CS required while moving nodes
+ while let Some(node_ptr) = LinkedListNode::remove_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr()) {
+ LinkedListNode::insert_head(FREE_BUF_QUEUE.as_mut_ptr(), node_ptr);
+ }
+ })
+ })
+ .await;
+ }
+ }
+}
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/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs
new file mode 100644
index 000000000..2b699b725
--- /dev/null
+++ b/embassy-stm32-wpan/src/sub/sys.rs
@@ -0,0 +1,86 @@
+use core::marker::PhantomData;
+use core::ptr;
+
+use crate::cmd::CmdPacket;
+use crate::consts::TlPacketType;
+use crate::evt::{CcEvt, EvtBox, EvtPacket};
+#[allow(unused_imports)]
+use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode};
+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};
+
+pub struct Sys {
+ phantom: PhantomData,
+}
+
+impl Sys {
+ /// TL_Sys_Init
+ pub(crate) fn new() -> Self {
+ unsafe {
+ LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
+
+ TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
+ pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
+ sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
+ });
+ }
+
+ Self { phantom: PhantomData }
+ }
+
+ /// Returns CPU2 wireless firmware information (if present).
+ pub fn wireless_fw_info(&self) -> Option {
+ let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table };
+
+ // Zero version indicates that CPU2 wasn't active and didn't fill the information table
+ if info.version != 0 {
+ Some(info)
+ } else {
+ None
+ }
+ }
+
+ pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) {
+ Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || unsafe {
+ CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode as u16, payload);
+ })
+ .await;
+ }
+
+ /// `HW_IPCC_SYS_CmdEvtNot`
+ pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus {
+ self.write(opcode, payload).await;
+ Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
+
+ unsafe {
+ let p_event_packet = SYS_CMD_BUF.as_ptr() as *const EvtPacket;
+ let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
+ let p_payload = &((*p_command_event).payload) as *const u8;
+
+ ptr::read_volatile(p_payload).try_into().unwrap()
+ }
+ }
+
+ #[cfg(feature = "mac")]
+ pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus {
+ self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await
+ }
+
+ #[cfg(feature = "ble")]
+ pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus {
+ self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
+ }
+
+ /// `HW_IPCC_SYS_EvtNot`
+ 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()))
+ } else {
+ None
+ }
+ })
+ .await
+ }
+}
diff --git a/embassy-stm32-wpan/src/sys.rs b/embassy-stm32-wpan/src/sys.rs
deleted file mode 100644
index 2b699b725..000000000
--- a/embassy-stm32-wpan/src/sys.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use core::marker::PhantomData;
-use core::ptr;
-
-use crate::cmd::CmdPacket;
-use crate::consts::TlPacketType;
-use crate::evt::{CcEvt, EvtBox, EvtPacket};
-#[allow(unused_imports)]
-use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode};
-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};
-
-pub struct Sys {
- phantom: PhantomData,
-}
-
-impl Sys {
- /// TL_Sys_Init
- pub(crate) fn new() -> Self {
- unsafe {
- LinkedListNode::init_head(SYSTEM_EVT_QUEUE.as_mut_ptr());
-
- TL_SYS_TABLE.as_mut_ptr().write_volatile(SysTable {
- pcmd_buffer: SYS_CMD_BUF.as_mut_ptr(),
- sys_queue: SYSTEM_EVT_QUEUE.as_ptr(),
- });
- }
-
- Self { phantom: PhantomData }
- }
-
- /// Returns CPU2 wireless firmware information (if present).
- pub fn wireless_fw_info(&self) -> Option {
- let info = unsafe { TL_DEVICE_INFO_TABLE.as_mut_ptr().read_volatile().wireless_fw_info_table };
-
- // Zero version indicates that CPU2 wasn't active and didn't fill the information table
- if info.version != 0 {
- Some(info)
- } else {
- None
- }
- }
-
- pub async fn write(&self, opcode: ShciOpcode, payload: &[u8]) {
- Ipcc::send(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL, || unsafe {
- CmdPacket::write_into(SYS_CMD_BUF.as_mut_ptr(), TlPacketType::SysCmd, opcode as u16, payload);
- })
- .await;
- }
-
- /// `HW_IPCC_SYS_CmdEvtNot`
- pub async fn write_and_get_response(&self, opcode: ShciOpcode, payload: &[u8]) -> SchiCommandStatus {
- self.write(opcode, payload).await;
- Ipcc::flush(channels::cpu1::IPCC_SYSTEM_CMD_RSP_CHANNEL).await;
-
- unsafe {
- let p_event_packet = SYS_CMD_BUF.as_ptr() as *const EvtPacket;
- let p_command_event = &((*p_event_packet).evt_serial.evt.payload) as *const _ as *const CcEvt;
- let p_payload = &((*p_command_event).payload) as *const u8;
-
- ptr::read_volatile(p_payload).try_into().unwrap()
- }
- }
-
- #[cfg(feature = "mac")]
- pub async fn shci_c2_mac_802_15_4_init(&self) -> SchiCommandStatus {
- self.write_and_get_response(ShciOpcode::Mac802_15_4Init, &[]).await
- }
-
- #[cfg(feature = "ble")]
- pub async fn shci_c2_ble_init(&self, param: ShciBleInitCmdParam) -> SchiCommandStatus {
- self.write_and_get_response(ShciOpcode::BleInit, param.payload()).await
- }
-
- /// `HW_IPCC_SYS_EvtNot`
- 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()))
- } else {
- None
- }
- })
- .await
- }
-}
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{
--
cgit
From f23b34951a20f569997bbe028048f3943d7e4c56 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 17:55:47 -0500
Subject: 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;
--
cgit
From 91fdd76053c747c569b0eefe0715522465fe0194 Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 18:08:42 -0500
Subject: 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();
--
cgit
From d43417e97c4de487b4ebf018830825e034c5394e Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 19:59:48 -0500
Subject: 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());
--
cgit
From 49333ce6adf28ff6c3eb1a632c0d4860379ef3ef Mon Sep 17 00:00:00 2001
From: xoviat
Date: Fri, 23 Jun 2023 20:09:13 -0500
Subject: stm32/wpan: move linker file into pkg
---
embassy-stm32-wpan/build.rs | 13 ++++++++++++-
embassy-stm32-wpan/tl_mbox.x.in | 15 +++++++++++++++
embassy-stm32/build.rs | 10 ----------
embassy-stm32/tl_mbox.x.in | 15 ---------------
4 files changed, 27 insertions(+), 26 deletions(-)
create mode 100644 embassy-stm32-wpan/tl_mbox.x.in
delete mode 100644 embassy-stm32/tl_mbox.x.in
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-wpan/tl_mbox.x.in b/embassy-stm32-wpan/tl_mbox.x.in
new file mode 100644
index 000000000..b6eecb429
--- /dev/null
+++ b/embassy-stm32-wpan/tl_mbox.x.in
@@ -0,0 +1,15 @@
+MEMORY
+{
+ RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
+}
+
+/*
+ * Scatter the mailbox interface memory sections in shared memory
+ */
+SECTIONS
+{
+ TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
+
+ MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
+ MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
+}
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
diff --git a/embassy-stm32/tl_mbox.x.in b/embassy-stm32/tl_mbox.x.in
deleted file mode 100644
index b6eecb429..000000000
--- a/embassy-stm32/tl_mbox.x.in
+++ /dev/null
@@ -1,15 +0,0 @@
-MEMORY
-{
- RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 10K
-}
-
-/*
- * Scatter the mailbox interface memory sections in shared memory
- */
-SECTIONS
-{
- TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
-
- MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAM_SHARED
- MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAM_SHARED
-}
--
cgit
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: first attempt at fixing the 2nd channel problem
---
embassy-stm32/src/dac/mod.rs | 366 ++++++++++++++++++++++++++-----------------
1 file changed, 224 insertions(+), 142 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,127 @@ 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
+ 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(())
}
+}
- /// Write `data` to the DAC CH2 via DMA.
+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 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>
+ /// **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.index();
+ let channel = Channel::Ch2.index();
+ debug!("Writing to channel {}", channel);
// Enable DAC and DMA
T::regs().cr().modify(|w| {
@@ -313,11 +348,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 +409,53 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> {
}
}
+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;
--
cgit
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: 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> {
--
cgit
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: 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!(
--
cgit
From 018622f607a17037903ef7c5592dda762002f89b Mon Sep 17 00:00:00 2001
From: xoviat
Date: Sun, 25 Jun 2023 11:38:48 -0500
Subject: 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;
--
cgit
From aa0ab06645446bcb4b99a9407dc9c6c58030d8de Mon Sep 17 00:00:00 2001
From: Dániel Buga
Date: Sun, 25 Jun 2023 22:24:48 +0200
Subject: 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);
--
cgit
From 2809e926cf8a3a1556c674a7b17c8db4b926f243 Mon Sep 17 00:00:00 2001
From: Dániel Buga
Date: Sun, 25 Jun 2023 22:32:24 +0200
Subject: 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,)*)) }
}
};
--
cgit
From 12872ce49b3945c1a28ae362f78bcfb334a9eeb8 Mon Sep 17 00:00:00 2001
From: Dániel Buga
Date: Sun, 25 Jun 2023 23:03:14 +0200
Subject: 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);
--
cgit
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: 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
--
cgit
From 64cba950e55dd5cdd7d6ef13c2dbb03825bc6d01 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Mon, 26 Jun 2023 01:59:25 +0200
Subject: 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());
--
cgit
From 715bf20c4159f2b11f4edf0cd3b1b999ef19b56b Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Mon, 26 Jun 2023 20:13:55 +0200
Subject: 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",
] }
--
cgit
From 28fb492c402c74add5c650b9d65687816585c923 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 00:42:24 +0200
Subject: 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()`
--
cgit
From a575e40a3503f4bf500b7ee3cadcce44727c7c6f Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 02:12:06 +0200
Subject: 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.
})
});
--
cgit
From 80407aa930279a7d23bd1295c7703d0d9064aa58 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 02:12:33 +0200
Subject: 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);
}
});
});
--
cgit
From 5e6e18b310ef3c19fd4cdc42fa74dd8ed455e444 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 03:56:09 +0200
Subject: stm32/usb: add TODO: implement VBUS detection.
---
embassy-stm32/src/usb/usb.rs | 85 ++++++++++++++++++++++----------------------
1 file changed, 43 insertions(+), 42 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);
- }
+ // TODO: implement VBUS detection.
+ if !self.inited {
+ self.inited = true;
+ return Poll::Ready(Event::PowerDetected);
+ }
- 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]);
- })
- }
+ let regs = T::regs();
- for w in &EP_IN_WAKERS {
- w.wake()
- }
- for w in &EP_OUT_WAKERS {
- w.wake()
- }
+ if IRQ_RESUME.load(Ordering::Acquire) {
+ IRQ_RESUME.store(false, Ordering::Relaxed);
+ return Poll::Ready(Event::Resume);
+ }
- return Poll::Ready(Event::Reset);
+ 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]);
+ })
}
- if IRQ_SUSPEND.load(Ordering::Acquire) {
- IRQ_SUSPEND.store(false, Ordering::Relaxed);
- return Poll::Ready(Event::Suspend);
+ for w in &EP_IN_WAKERS {
+ w.wake()
+ }
+ for w in &EP_OUT_WAKERS {
+ w.wake()
}
- Poll::Pending
- } else {
- self.inited = true;
- return Poll::Ready(Event::PowerDetected);
+ 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
}
--
cgit
From a2d1e7f02ca8d94c755ced56f1db11646ac2aa72 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 03:56:25 +0200
Subject: 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);
--
cgit
From 219ef5b37a1dff5f6e770da252ec010d55c43257 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 08:42:51 +0200
Subject: 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);
--
cgit
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: 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,
--
cgit
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: 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());
--
cgit
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: 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
///
--
cgit
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: 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() {
--
cgit
From f5ca687e9bbeb81ce24f56db6cd7defbcb5c2db2 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 23:49:12 +0200
Subject: 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
--
cgit
From ed493be869fa653dc14d31060375e17e2469ce11 Mon Sep 17 00:00:00 2001
From: Dario Nieuwenhuis
Date: Tue, 27 Jun 2023 23:49:30 +0200
Subject: 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);
--
cgit
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: 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() -> ! {
- info!("Hello World!");
-
- pac::RCC.apb1enr1().modify(|w| {
- w.set_dac1en(true);
- });
-
let p = embassy_stm32::init(Default::default());
+ info!("Hello World!");
- 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
+}
--
cgit
From 59f829c6cce3427f95b7c5b137f62f8af0c3c40f Mon Sep 17 00:00:00 2001
From: Dániel Buga
Date: Wed, 28 Jun 2023 15:03:57 +0200
Subject: 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 {
--
cgit
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: 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
--
cgit
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: 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);
--
cgit
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: 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]
--
cgit
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: 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
}
--
cgit
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: 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)
--
cgit
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: 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());
--
cgit
From 5666c569033d59fc894230ed4161e6c686733b2d Mon Sep 17 00:00:00 2001
From: Kevin Lannen