From f5d084552d9f44d24f020269cc605de0fb4d1041 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sat, 17 Jun 2023 11:48:21 +0200 Subject: [PATCH 01/74] implement mwe of a DMA write() method for DAC --- embassy-stm32/build.rs | 2 + embassy-stm32/src/{dac.rs => dac/mod.rs} | 76 +++++++++++++++++++++--- 2 files changed, 71 insertions(+), 7 deletions(-) rename embassy-stm32/src/{dac.rs => dac/mod.rs} (76%) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 9e597f187..e2bd01d7b 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -699,6 +699,8 @@ fn main() { // SDMMCv1 uses the same channel for both directions, so just implement for RX (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), + (("dac", "CH1"), quote!(crate::dac::Dma)), + (("dac", "CH2"), quote!(crate::dac::Dma)), ] .into(); diff --git a/embassy-stm32/src/dac.rs b/embassy-stm32/src/dac/mod.rs similarity index 76% rename from embassy-stm32/src/dac.rs rename to embassy-stm32/src/dac/mod.rs index 60e856c78..348d8bccd 100644 --- a/embassy-stm32/src/dac.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -2,6 +2,7 @@ use embassy_hal_common::{into_ref, PeripheralRef}; +use crate::dma::{slice_ptr_parts, word, Transfer}; use crate::pac::dac; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -97,39 +98,58 @@ pub enum Value { Bit12(u16, Alignment), } -pub struct Dac<'d, T: Instance> { +pub struct Dac<'d, T: Instance, Tx> { channels: u8, + txdma: PeripheralRef<'d, Tx>, _peri: PeripheralRef<'d, T>, } -impl<'d, T: Instance> Dac<'d, T> { - pub fn new_1ch(peri: impl Peripheral

+ 'd, _ch1: impl Peripheral

> + 'd) -> Self { +impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { + pub fn new_1ch( + peri: impl Peripheral

+ 'd, + txdma: impl Peripheral

+ 'd, + _ch1: impl Peripheral

> + 'd, + ) -> Self { into_ref!(peri); - Self::new_inner(peri, 1) + Self::new_inner(peri, 1, txdma) } pub fn new_2ch( peri: impl Peripheral

+ 'd, + txdma: impl Peripheral

+ 'd, _ch1: impl Peripheral

> + 'd, _ch2: impl Peripheral

> + 'd, ) -> Self { into_ref!(peri); - Self::new_inner(peri, 2) + Self::new_inner(peri, 2, txdma) } - fn new_inner(peri: PeripheralRef<'d, T>, channels: u8) -> Self { + fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral

+ 'd) -> Self { + into_ref!(txdma); T::enable(); T::reset(); unsafe { + T::regs().mcr().modify(|reg| { + for ch in 0..channels { + reg.set_mode(ch as usize, 0); + reg.set_mode(ch as usize, 0); + } + }); + T::regs().cr().modify(|reg| { for ch in 0..channels { reg.set_en(ch as usize, true); + reg.set_ten(ch as usize, true); } }); } - Self { channels, _peri: peri } + Self { + channels, + txdma, + _peri: peri, + } } /// Check the channel is configured @@ -215,6 +235,47 @@ impl<'d, T: Instance> Dac<'d, T> { } Ok(()) } + + /// TODO: Allow an array of Value instead of only u16, right-aligned + pub async fn write(&mut self, data: &[u16]) -> Result<(), Error> + where + Tx: Dma, + { + // TODO: Make this a parameter or get it from the struct or so... + const CHANNEL: usize = 0; + + //debug!("Starting DAC"); + unsafe { + T::regs().cr().modify(|w| { + w.set_en(CHANNEL, true); + w.set_dmaen(CHANNEL, true); + }); + } + + let tx_request = self.txdma.request(); + + // Use the 12 bit right-aligned register for now. TODO: distinguish values + let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16; + + let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; + + //debug!("Awaiting tx_f"); + + tx_f.await; + + // finish dma + unsafe { + // TODO: Do we need to check any status registers here? + + T::regs().cr().modify(|w| { + // Disable the dac peripheral + //w.set_en(CHANNEL, false); + // Disable the DMA. TODO: Is this necessary? + //w.set_dmaen(CHANNEL, false); + }); + } + Ok(()) + } } pub(crate) mod sealed { @@ -224,6 +285,7 @@ pub(crate) mod sealed { } pub trait Instance: sealed::Instance + RccPeripheral + 'static {} +dma_trait!(Dma, Instance); pub trait DacPin: crate::gpio::Pin + 'static {} From 78a2ca8a0e5af3fe2c76a6cd025b74ea4322f6cf Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sat, 17 Jun 2023 11:51:57 +0200 Subject: [PATCH 02/74] remove unnecessary use, disable DAC and DMA after transfer --- embassy-stm32/src/dac/mod.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 348d8bccd..7b81ec1f2 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -2,7 +2,7 @@ use embassy_hal_common::{into_ref, PeripheralRef}; -use crate::dma::{slice_ptr_parts, word, Transfer}; +use crate::dma::Transfer; use crate::pac::dac; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -269,9 +269,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { T::regs().cr().modify(|w| { // Disable the dac peripheral - //w.set_en(CHANNEL, false); + w.set_en(CHANNEL, false); // Disable the DMA. TODO: Is this necessary? - //w.set_dmaen(CHANNEL, false); + w.set_dmaen(CHANNEL, false); }); } Ok(()) From f8ee33abb9943d6fe57c126eeecb36db9935c4ba Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sun, 18 Jun 2023 18:51:36 +0200 Subject: [PATCH 03/74] add half transfer interrupt and circular dma --- embassy-stm32/src/dac/mod.rs | 17 ++++++++++++++--- embassy-stm32/src/dma/bdma.rs | 26 ++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 7b81ec1f2..525d45d72 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -2,7 +2,7 @@ use embassy_hal_common::{into_ref, PeripheralRef}; -use crate::dma::Transfer; +use crate::dma::{Transfer, TransferOptions}; use crate::pac::dac; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -237,7 +237,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { } /// TODO: Allow an array of Value instead of only u16, right-aligned - pub async fn write(&mut self, data: &[u16]) -> Result<(), Error> + pub async fn write(&mut self, data: &[u16], circular: bool) -> Result<(), Error> where Tx: Dma, { @@ -257,7 +257,18 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { // Use the 12 bit right-aligned register for now. TODO: distinguish values let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16; - let tx_f = unsafe { Transfer::new_write(&mut self.txdma, tx_request, data, tx_dst, Default::default()) }; + let tx_f = unsafe { + Transfer::new_write( + &mut self.txdma, + tx_request, + data, + tx_dst, + TransferOptions { + circular, + halt_transfer_ir: false, + }, + ) + }; //debug!("Awaiting tx_f"); diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index c0a503e25..ca18047e7 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -1,6 +1,7 @@ #![macro_use] use core::future::Future; +use core::option; use core::pin::Pin; use core::sync::atomic::{fence, Ordering}; use core::task::{Context, Poll, Waker}; @@ -21,11 +22,17 @@ use crate::pac::bdma::{regs, vals}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] -pub struct TransferOptions {} +pub struct TransferOptions { + pub circular: bool, + pub halt_transfer_ir: bool, +} impl Default for TransferOptions { fn default() -> Self { - Self {} + Self { + circular: false, + halt_transfer_ir: false, + } } } @@ -253,7 +260,7 @@ impl<'a, C: Channel> Transfer<'a, C> { mem_len: usize, incr_mem: bool, data_size: WordSize, - _options: TransferOptions, + options: TransferOptions, ) -> Self { let ch = channel.regs().ch(channel.num()); @@ -284,6 +291,14 @@ impl<'a, C: Channel> Transfer<'a, C> { w.set_dir(dir.into()); w.set_teie(true); w.set_tcie(true); + w.set_htie(options.halt_transfer_ir); + if options.circular { + w.set_circ(vals::Circ::ENABLED); + debug!("Setting circular mode"); + } else { + w.set_circ(vals::Circ::DISABLED); + } + w.set_pl(vals::Pl::VERYHIGH); w.set_en(true); }); @@ -314,8 +329,9 @@ impl<'a, C: Channel> Transfer<'a, C> { pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); let en = unsafe { ch.cr().read() }.en(); + let circular = unsafe { ch.cr().read() }.circ() == vals::Circ::ENABLED; let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; - en && !tcif + en && (circular || !tcif) } /// Gets the total remaining transfers for the channel @@ -482,6 +498,8 @@ impl<'a, C: Channel, W: Word> RingBuffer<'a, C, W> { let ch = self.channel.regs().ch(self.channel.num()); // Disable the channel. Keep the IEs enabled so the irqs still fire. + // If the channel is enabled and transfer is not completed, we need to perform + // two separate write access to the CR register to disable the channel. unsafe { ch.cr().write(|w| { w.set_teie(true); From e0747e937f06ed280594e17c97d19784410b6e85 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Mon, 19 Jun 2023 11:15:09 +0200 Subject: [PATCH 04/74] remove unsafe for circular dma reg access --- embassy-stm32/src/dma/bdma.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index be4571440..3d315e20b 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -325,7 +325,7 @@ impl<'a, C: Channel> Transfer<'a, C> { pub fn is_running(&mut self) -> bool { let ch = self.channel.regs().ch(self.channel.num()); let en = ch.cr().read().en(); - let circular = unsafe { ch.cr().read() }.circ() == vals::Circ::ENABLED; + let circular = ch.cr().read().circ() == vals::Circ::ENABLED; let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; en && (circular || !tcif) } From fe7b72948ab5d3682f23e305f3eb7186cc308b1b Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:42:25 +0200 Subject: [PATCH 05/74] add ValueArray type and respective write functions --- embassy-stm32/src/dac/mod.rs | 206 +++++++++++++++++++++-------------- 1 file changed, 124 insertions(+), 82 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 525d45d72..4384a7c34 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -98,6 +98,14 @@ pub enum Value { Bit12(u16, Alignment), } +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum ValueArray<'a> { + Bit8(&'a [u8]), + Bit12Left(&'a [u16]), + Bit12Right(&'a [u16]), +} + pub struct Dac<'d, T: Instance, Tx> { channels: u8, txdma: PeripheralRef<'d, Tx>, @@ -129,21 +137,19 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { T::enable(); T::reset(); - unsafe { - T::regs().mcr().modify(|reg| { - for ch in 0..channels { - reg.set_mode(ch as usize, 0); - reg.set_mode(ch as usize, 0); - } - }); + T::regs().mcr().modify(|reg| { + for ch in 0..channels { + reg.set_mode(ch as usize, 0); + reg.set_mode(ch as usize, 0); + } + }); - T::regs().cr().modify(|reg| { - for ch in 0..channels { - reg.set_en(ch as usize, true); - reg.set_ten(ch as usize, true); - } - }); - } + T::regs().cr().modify(|reg| { + for ch in 0..channels { + reg.set_en(ch as usize, true); + reg.set_ten(ch as usize, true); + } + }); Self { channels, @@ -161,13 +167,12 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { } } + /// Set the enable register of the given channel fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { self.check_channel_exists(ch)?; - unsafe { - T::regs().cr().modify(|reg| { - reg.set_en(ch.index(), on); - }) - } + T::regs().cr().modify(|reg| { + reg.set_en(ch.index(), on); + }); Ok(()) } @@ -179,112 +184,149 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { self.set_channel_enable(ch, false) } + /// Performs all register accesses necessary to select a new trigger for CH1 pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { self.check_channel_exists(Channel::Ch1)?; unwrap!(self.disable_channel(Channel::Ch1)); - unsafe { - T::regs().cr().modify(|reg| { - reg.set_tsel1(trigger.tsel()); - }) - } + T::regs().cr().modify(|reg| { + reg.set_tsel1(trigger.tsel()); + }); Ok(()) } + /// Performs all register accesses necessary to select a new trigger for CH2 pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { self.check_channel_exists(Channel::Ch2)?; unwrap!(self.disable_channel(Channel::Ch2)); - unsafe { - T::regs().cr().modify(|reg| { - reg.set_tsel2(trigger.tsel()); - }) - } + T::regs().cr().modify(|reg| { + reg.set_tsel2(trigger.tsel()); + }); Ok(()) } + /// Perform a software trigger on a given channel pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { self.check_channel_exists(ch)?; - unsafe { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig(ch.index(), true); - }); - } + T::regs().swtrigr().write(|reg| { + reg.set_swtrig(ch.index(), true); + }); Ok(()) } + /// Perform a software trigger on all channels pub fn trigger_all(&mut self) { - unsafe { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig(Channel::Ch1.index(), true); - reg.set_swtrig(Channel::Ch2.index(), true); - }) - } + T::regs().swtrigr().write(|reg| { + reg.set_swtrig(Channel::Ch1.index(), true); + reg.set_swtrig(Channel::Ch2.index(), true); + }); } pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { self.check_channel_exists(ch)?; match value { - Value::Bit8(v) => unsafe { - T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)); - }, - Value::Bit12(v, Alignment::Left) => unsafe { - T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)); - }, - Value::Bit12(v, Alignment::Right) => unsafe { - T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)); - }, + Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), + Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), + Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), } Ok(()) } + /// Write `data` to the DAC via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// + /// ## Current limitations + /// - Only CH1 Supported + /// /// TODO: Allow an array of Value instead of only u16, right-aligned - pub async fn write(&mut self, data: &[u16], circular: bool) -> Result<(), Error> + pub async fn write_8bit(&mut self, data_ch1: &[u8], circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + self.write_inner(ValueArray::Bit8(data_ch1), circular).await + } + + pub async fn write_12bit_right_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + self.write_inner(ValueArray::Bit12Right(data_ch1), circular).await + } + + pub async fn write_12bit_left_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + self.write_inner(ValueArray::Bit12Left(data_ch1), circular).await + } + + async fn write_inner(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: Dma, { // TODO: Make this a parameter or get it from the struct or so... const CHANNEL: usize = 0; - //debug!("Starting DAC"); - unsafe { - T::regs().cr().modify(|w| { - w.set_en(CHANNEL, true); - w.set_dmaen(CHANNEL, true); - }); - } + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(CHANNEL, true); + w.set_dmaen(CHANNEL, true); + }); let tx_request = self.txdma.request(); - // Use the 12 bit right-aligned register for now. TODO: distinguish values - let tx_dst = T::regs().dhr12r(CHANNEL).ptr() as *mut u16; - - let tx_f = unsafe { - Transfer::new_write( - &mut self.txdma, - tx_request, - data, - tx_dst, - TransferOptions { - circular, - halt_transfer_ir: false, - }, - ) + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data_ch1 { + ValueArray::Bit8(buf) => unsafe { + Transfer::new_write( + &mut self.txdma, + tx_request, + buf, + T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8, + TransferOptions { + circular, + halt_transfer_ir: false, + }, + ) + }, + ValueArray::Bit12Left(buf) => unsafe { + Transfer::new_write( + &mut self.txdma, + tx_request, + buf, + T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16, + TransferOptions { + circular, + halt_transfer_ir: false, + }, + ) + }, + ValueArray::Bit12Right(buf) => unsafe { + Transfer::new_write( + &mut self.txdma, + tx_request, + buf, + T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16, + TransferOptions { + circular, + halt_transfer_ir: false, + }, + ) + }, }; - //debug!("Awaiting tx_f"); - tx_f.await; // finish dma - unsafe { - // TODO: Do we need to check any status registers here? + // TODO: Do we need to check any status registers here? + T::regs().cr().modify(|w| { + // Disable the DAC peripheral + w.set_en(CHANNEL, false); + // Disable the DMA. TODO: Is this necessary? + w.set_dmaen(CHANNEL, false); + }); - T::regs().cr().modify(|w| { - // Disable the dac peripheral - w.set_en(CHANNEL, false); - // Disable the DMA. TODO: Is this necessary? - w.set_dmaen(CHANNEL, false); - }); - } Ok(()) } } From 218b102b2840c9786944aa6f613450c876b6110b Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:46:17 +0200 Subject: [PATCH 06/74] remove Alignment and make Value and Value array look the same --- embassy-stm32/src/dac/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 4384a7c34..0fbf67673 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -84,25 +84,25 @@ impl Ch2Trigger { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Alignment { - Left, - Right, -} - #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Value { + // 8 bit value Bit8(u8), - Bit12(u16, Alignment), + // 12 bit value stored in a u16, left-aligned + Bit12Left(u16), + // 12 bit value stored in a u16, right-aligned + Bit12Right(u16), } #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ValueArray<'a> { + // 8 bit values Bit8(&'a [u8]), + // 12 bit value stored in a u16, left-aligned Bit12Left(&'a [u16]), + // 12 bit values stored in a u16, right-aligned Bit12Right(&'a [u16]), } @@ -225,8 +225,8 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { self.check_channel_exists(ch)?; match value { Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), - Value::Bit12(v, Alignment::Left) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), - Value::Bit12(v, Alignment::Right) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), + Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), + Value::Bit12Right(v) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), } Ok(()) } From 88052480b14b8dd38e7c4ba179b7035390f59618 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:50:17 +0200 Subject: [PATCH 07/74] fix typo, minor cleanup --- embassy-stm32/src/dac/mod.rs | 13 +++++++------ embassy-stm32/src/dma/bdma.rs | 7 +++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 0fbf67673..704b77b37 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -275,42 +275,43 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { }); let tx_request = self.txdma.request(); + let channel = &mut self.txdma; // Initiate the correct type of DMA transfer depending on what data is passed let tx_f = match data_ch1 { ValueArray::Bit8(buf) => unsafe { Transfer::new_write( - &mut self.txdma, + channel, tx_request, buf, T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8, TransferOptions { circular, - halt_transfer_ir: false, + half_transfer_ir: false, }, ) }, ValueArray::Bit12Left(buf) => unsafe { Transfer::new_write( - &mut self.txdma, + channel, tx_request, buf, T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16, TransferOptions { circular, - halt_transfer_ir: false, + half_transfer_ir: false, }, ) }, ValueArray::Bit12Right(buf) => unsafe { Transfer::new_write( - &mut self.txdma, + channel, tx_request, buf, T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16, TransferOptions { circular, - halt_transfer_ir: false, + half_transfer_ir: false, }, ) }, diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 3d315e20b..0ad20579a 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -1,7 +1,6 @@ #![macro_use] use core::future::Future; -use core::option; use core::pin::Pin; use core::sync::atomic::{fence, Ordering}; use core::task::{Context, Poll, Waker}; @@ -24,14 +23,14 @@ use crate::pac::bdma::{regs, vals}; #[non_exhaustive] pub struct TransferOptions { pub circular: bool, - pub halt_transfer_ir: bool, + pub half_transfer_ir: bool, } impl Default for TransferOptions { fn default() -> Self { Self { circular: false, - halt_transfer_ir: false, + half_transfer_ir: false, } } } @@ -291,7 +290,7 @@ impl<'a, C: Channel> Transfer<'a, C> { w.set_dir(dir.into()); w.set_teie(true); w.set_tcie(true); - w.set_htie(options.halt_transfer_ir); + w.set_htie(options.half_transfer_ir); if options.circular { w.set_circ(vals::Circ::ENABLED); debug!("Setting circular mode"); From 56ab6d9f143ecc3041ac9726e621eedea729ca4d Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Mon, 19 Jun 2023 13:54:22 +0200 Subject: [PATCH 08/74] remove write_X variants --- embassy-stm32/src/dac/mod.rs | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 704b77b37..f02adeed9 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -86,6 +86,7 @@ impl Ch2Trigger { #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Single 8 or 12 bit value that can be output by the DAC pub enum Value { // 8 bit value Bit8(u8), @@ -97,6 +98,7 @@ pub enum Value { #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Array variant of [`Value`] pub enum ValueArray<'a> { // 8 bit values Bit8(&'a [u8]), @@ -239,29 +241,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// ## Current limitations /// - Only CH1 Supported /// - /// TODO: Allow an array of Value instead of only u16, right-aligned - pub async fn write_8bit(&mut self, data_ch1: &[u8], circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - self.write_inner(ValueArray::Bit8(data_ch1), circular).await - } - - pub async fn write_12bit_right_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - self.write_inner(ValueArray::Bit12Right(data_ch1), circular).await - } - - pub async fn write_12bit_left_aligned(&mut self, data_ch1: &[u16], circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - self.write_inner(ValueArray::Bit12Left(data_ch1), circular).await - } - - async fn write_inner(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error> + pub async fn write(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: Dma, { From 8d0095c61808b88ad95349c7f24e91797d93dc83 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Thu, 22 Jun 2023 10:43:45 +0200 Subject: [PATCH 09/74] add option to enable/disable complete transfer interrupt --- embassy-stm32/src/dma/bdma.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 162ca9adb..32b75bb68 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -22,8 +22,12 @@ use crate::pac::bdma::{regs, vals}; #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub struct TransferOptions { + /// Enable circular DMA pub circular: bool, + /// Enable half transfer interrupt pub half_transfer_ir: bool, + /// Enable transfer complete interrupt + pub complete_transfer_ir: bool, } impl Default for TransferOptions { @@ -31,6 +35,7 @@ impl Default for TransferOptions { Self { circular: false, half_transfer_ir: false, + complete_transfer_ir: false, } } } @@ -289,7 +294,7 @@ impl<'a, C: Channel> Transfer<'a, C> { } w.set_dir(dir.into()); w.set_teie(true); - w.set_tcie(true); + w.set_tcie(options.complete_transfer_ir); w.set_htie(options.half_transfer_ir); if options.circular { w.set_circ(vals::Circ::ENABLED); From 78736328a042e7c7f6565ed44ac301be22953f7a Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Thu, 22 Jun 2023 10:44:08 +0200 Subject: [PATCH 10/74] update docs and update to new dma interface --- embassy-stm32/src/dac/mod.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index f02adeed9..42646d20d 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -115,6 +115,7 @@ pub struct Dac<'d, T: Instance, Tx> { } impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { + /// Create a new instance with one channel pub fn new_1ch( peri: impl Peripheral

+ 'd, txdma: impl Peripheral

+ 'd, @@ -124,6 +125,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { Self::new_inner(peri, 1, txdma) } + /// Create a new instance with two channels pub fn new_2ch( peri: impl Peripheral

+ 'd, txdma: impl Peripheral

+ 'd, @@ -134,6 +136,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { Self::new_inner(peri, 2, txdma) } + /// Perform initialisation steps for the DAC fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral

+ 'd) -> Self { into_ref!(txdma); T::enable(); @@ -178,15 +181,17 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { Ok(()) } + /// Enable the DAC channel `ch` pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> { self.set_channel_enable(ch, true) } + /// Disable the DAC channel `ch` pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> { self.set_channel_enable(ch, false) } - /// Performs all register accesses necessary to select a new trigger for CH1 + /// Select a new trigger for CH1 (disables the channel) pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { self.check_channel_exists(Channel::Ch1)?; unwrap!(self.disable_channel(Channel::Ch1)); @@ -196,7 +201,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { Ok(()) } - /// Performs all register accesses necessary to select a new trigger for CH2 + /// Select a new trigger for CH2 (disables the channel) pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { self.check_channel_exists(Channel::Ch2)?; unwrap!(self.disable_channel(Channel::Ch2)); @@ -206,7 +211,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { Ok(()) } - /// Perform a software trigger on a given channel + /// Perform a software trigger on `ch` pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { self.check_channel_exists(ch)?; T::regs().swtrigr().write(|reg| { @@ -223,6 +228,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { }); } + /// Set a value to be output by the DAC on trigger. + /// + /// The `value` is written to the corresponding "data holding register" pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { self.check_channel_exists(ch)?; match value { @@ -237,6 +245,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// /// ## Current limitations /// - Only CH1 Supported @@ -255,7 +264,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { }); let tx_request = self.txdma.request(); - let channel = &mut self.txdma; + let channel = &self.txdma; // Initiate the correct type of DMA transfer depending on what data is passed let tx_f = match data_ch1 { @@ -268,6 +277,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { TransferOptions { circular, half_transfer_ir: false, + complete_transfer_ir: !circular, }, ) }, @@ -280,6 +290,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { TransferOptions { circular, half_transfer_ir: false, + complete_transfer_ir: !circular, }, ) }, @@ -292,6 +303,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { TransferOptions { circular, half_transfer_ir: false, + complete_transfer_ir: !circular, }, ) }, From cd4f8f13a2c533f4e752c2e446661a6d86b19fe6 Mon Sep 17 00:00:00 2001 From: goueslati Date: Thu, 22 Jun 2023 15:21:14 +0100 Subject: [PATCH 11/74] wpan: add BLE HCI --- embassy-stm32-wpan/Cargo.toml | 4 +- embassy-stm32-wpan/src/ble.rs | 19 +- embassy-stm32-wpan/src/cmd.rs | 2 +- embassy-stm32-wpan/src/evt.rs | 23 ++ embassy-stm32-wpan/src/lhci.rs | 111 +++++++++ embassy-stm32-wpan/src/lib.rs | 2 + examples/stm32wb/.cargo/config.toml | 2 +- examples/stm32wb/Cargo.toml | 6 +- examples/stm32wb/src/bin/eddystone_beacon.rs | 249 +++++++++++++++++++ 9 files changed, 412 insertions(+), 6 deletions(-) create mode 100644 embassy-stm32-wpan/src/lhci.rs create mode 100644 examples/stm32wb/src/bin/eddystone_beacon.rs diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index f9023ed79..fda4189ca 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -23,11 +23,13 @@ cortex-m = "0.7.6" heapless = "0.7.16" bit_field = "0.10.2" +stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } +bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", optional = true } [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] -ble = [] +ble = ["dep:bluetooth-hci-async"] mac = [] stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs index 60e0cbdf8..297ee4cdf 100644 --- a/embassy-stm32-wpan/src/ble.rs +++ b/embassy-stm32-wpan/src/ble.rs @@ -1,6 +1,7 @@ use core::marker::PhantomData; use embassy_stm32::ipcc::Ipcc; +use hci::Opcode; use crate::channels; use crate::cmd::CmdPacket; @@ -29,7 +30,7 @@ impl Ble { Self { phantom: PhantomData } } /// `HW_IPCC_BLE_EvtNot` - pub async fn read(&self) -> EvtBox { + pub async fn tl_read(&self) -> EvtBox { Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) { Some(EvtBox::new(node_ptr.cast())) @@ -41,7 +42,7 @@ impl Ble { } /// `TL_BLE_SendCmd` - pub async fn write(&self, opcode: u16, payload: &[u8]) { + pub async fn tl_write(&self, opcode: u16, payload: &[u8]) { Ipcc::send(channels::cpu1::IPCC_BLE_CMD_CHANNEL, || unsafe { CmdPacket::write_into(BLE_CMD_BUFFER.as_mut_ptr(), TlPacketType::BleCmd, opcode, payload); }) @@ -61,3 +62,17 @@ impl Ble { .await; } } + +pub extern crate bluetooth_hci_async as hci; + +impl hci::Controller for Ble { + async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) { + self.tl_write(opcode.0, payload).await; + } + + async fn controller_read(&self) -> &[u8] { + let evt_box = self.tl_read().await; + + evt_box.serial() + } +} diff --git a/embassy-stm32-wpan/src/cmd.rs b/embassy-stm32-wpan/src/cmd.rs index c8056aaa7..8428b6ffc 100644 --- a/embassy-stm32-wpan/src/cmd.rs +++ b/embassy-stm32-wpan/src/cmd.rs @@ -52,7 +52,7 @@ impl CmdPacket { p_cmd_serial, CmdSerialStub { ty: packet_type as u8, - cmd_code: cmd_code, + cmd_code, payload_len: payload.len() as u8, }, ); diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs index 47bdc49bf..7a4738b7a 100644 --- a/embassy-stm32-wpan/src/evt.rs +++ b/embassy-stm32-wpan/src/evt.rs @@ -1,6 +1,7 @@ use core::{ptr, slice}; use super::PacketHeader; +use crate::consts::TL_EVT_HEADER_SIZE; /** * The payload of `Evt` for a command status event @@ -105,6 +106,14 @@ impl EvtBox { Self { ptr } } + pub fn evt<'a>(&self) -> &'a [u8] { + unsafe { + let evt_packet = &(*self.ptr); + + core::slice::from_raw_parts(evt_packet as *const _ as *const u8, core::mem::size_of::()) + } + } + /// Returns information about the event pub fn stub(&self) -> EvtStub { unsafe { @@ -124,6 +133,20 @@ impl EvtBox { slice::from_raw_parts(p_payload, payload_len as usize) } } + + /// writes an underlying [`EvtPacket`] into the provided buffer. + /// Returns the number of bytes that were written. + /// Returns an error if event kind is unknown or if provided buffer size is not enough. + pub fn serial<'a>(&self) -> &'a [u8] { + unsafe { + let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial; + let evt_serial_buf: *const u8 = evt_serial.cast(); + + let len = (*evt_serial).evt.payload_len as usize + TL_EVT_HEADER_SIZE; + + slice::from_raw_parts(evt_serial_buf, len) + } + } } impl Drop for EvtBox { diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs new file mode 100644 index 000000000..62116a695 --- /dev/null +++ b/embassy-stm32-wpan/src/lhci.rs @@ -0,0 +1,111 @@ +use crate::cmd::CmdPacket; +use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE}; +use crate::evt::{CcEvt, EvtPacket, EvtSerial}; +use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable}; +use crate::TL_REF_TABLE; + +const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; +const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62; + +const PACKAGE_DATA_PTR: *const u8 = 0x1FFF_7500 as _; +const UID64_PTR: *const u32 = 0x1FFF_7580 as _; + +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct LhciC1DeviceInformationCcrp { + pub status: u8, + pub rev_id: u16, + pub dev_code_id: u16, + pub package_type: u8, + pub device_type_id: u8, + pub st_company_id: u32, + pub uid64: u32, + + pub uid96_0: u32, + pub uid96_1: u32, + pub uid96_2: u32, + + pub safe_boot_info_table: SafeBootInfoTable, + pub rss_info_table: RssInfoTable, + pub wireless_fw_info_table: WirelessFwInfoTable, + + pub app_fw_inf: u32, +} + +impl Default for LhciC1DeviceInformationCcrp { + fn default() -> Self { + let DeviceInfoTable { + safe_boot_info_table, + rss_info_table, + wireless_fw_info_table, + } = unsafe { &*(*TL_REF_TABLE.as_ptr()).device_info_table }.clone(); + + let device_id = stm32_device_signature::device_id(); + let uid96_0 = (device_id[3] as u32) << 24 + | (device_id[2] as u32) << 16 + | (device_id[1] as u32) << 8 + | device_id[0] as u32; + let uid96_1 = (device_id[7] as u32) << 24 + | (device_id[6] as u32) << 16 + | (device_id[5] as u32) << 8 + | device_id[4] as u32; + let uid96_2 = (device_id[11] as u32) << 24 + | (device_id[10] as u32) << 16 + | (device_id[9] as u32) << 8 + | device_id[8] as u32; + + let package_type = unsafe { *PACKAGE_DATA_PTR }; + let uid64 = unsafe { *UID64_PTR }; + let st_company_id = unsafe { *UID64_PTR.offset(1) } >> 8 & 0x00FF_FFFF; + let device_type_id = (unsafe { *UID64_PTR.offset(1) } & 0x000000FF) as u8; + + LhciC1DeviceInformationCcrp { + status: 0, + rev_id: 0, + dev_code_id: 0, + package_type, + device_type_id, + st_company_id, + uid64, + uid96_0, + uid96_1, + uid96_2, + safe_boot_info_table, + rss_info_table, + wireless_fw_info_table, + app_fw_inf: (1 << 8), // 0.0.1 + } + } +} + +impl LhciC1DeviceInformationCcrp { + pub fn new() -> Self { + Self::default() + } + + pub fn write(&self, cmd_packet: &mut CmdPacket) { + let self_size = core::mem::size_of::(); + + unsafe { + let cmd_packet_ptr: *mut CmdPacket = cmd_packet; + let evet_packet_ptr: *mut EvtPacket = cmd_packet_ptr.cast(); + + let evt_serial: *mut EvtSerial = &mut (*evet_packet_ptr).evt_serial; + let evt_payload = (*evt_serial).evt.payload.as_mut_ptr(); + let evt_cc: *mut CcEvt = evt_payload.cast(); + let evt_cc_payload_buf = (*evt_cc).payload.as_mut_ptr(); + + (*evt_serial).kind = TlPacketType::LocRsp as u8; + (*evt_serial).evt.evt_code = TL_BLEEVT_CC_OPCODE; + (*evt_serial).evt.payload_len = TL_EVT_HEADER_SIZE as u8 + self_size as u8; + + (*evt_cc).cmd_code = LHCI_OPCODE_C1_DEVICE_INF; + (*evt_cc).num_cmd = 1; + + let self_ptr: *const LhciC1DeviceInformationCcrp = self; + let self_buf = self_ptr.cast(); + + core::ptr::copy(self_buf, evt_cc_payload_buf, self_size); + } + } +} diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index 5aec9933c..bf0f0466e 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![cfg_attr(feature = "ble", feature(async_fn_in_trait))] // This must go FIRST so that all the other modules see its macros. pub mod fmt; @@ -21,6 +22,7 @@ pub mod channels; pub mod cmd; pub mod consts; pub mod evt; +pub mod lhci; #[cfg(feature = "mac")] pub mod mac; pub mod mm; diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml index d23fdc513..35317a297 100644 --- a/examples/stm32wb/.cargo/config.toml +++ b/examples/stm32wb/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32WB55CCUx with your chip as listed in `probe-rs-cli chip list` -# runner = "probe-rs-cli run --chip STM32WB55CCUx --speed 1000 --connect-under-reset" +# runner = "probe-rs-cli run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" runner = "teleprobe local run --chip STM32WB55RG --elf" [build] diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index e41424aad..726cd10d4 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -33,4 +33,8 @@ required-features = ["ble"] [[bin]] name = "tl_mbox_mac" -required-features = ["mac"] \ No newline at end of file +required-features = ["mac"] + +[[bin]] +name = "eddystone_beacon" +required-features = ["ble"] \ No newline at end of file diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs new file mode 100644 index 000000000..fdd5be4a2 --- /dev/null +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -0,0 +1,249 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::time::Duration; + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; +use embassy_stm32_wpan::ble::hci::host::uart::UartHci; +use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; +use embassy_stm32_wpan::ble::hci::types::AdvertisingType; +use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{ + AdvertisingDataType, DiscoverableParameters, GapCommands, Role, +}; +use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands; +use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::ble::hci::BdAddr; +use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; +use embassy_stm32_wpan::TlMbox; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs{ + IPCC_C1_RX => ReceiveInterruptHandler; + IPCC_C1_TX => TransmitInterruptHandler; +}); + +const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + /* + How to make this work: + + - Obtain a NUCLEO-STM32WB55 from your preferred supplier. + - Download and Install STM32CubeProgrammer. + - Download stm32wb5x_FUS_fw.bin, stm32wb5x_BLE_Stack_full_fw.bin, and Release_Notes.html from + gh:STMicroelectronics/STM32CubeWB@2234d97/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x + - Open STM32CubeProgrammer + - On the right-hand pane, click "firmware upgrade" to upgrade the st-link firmware. + - Once complete, click connect to connect to the device. + - On the left hand pane, click the RSS signal icon to open "Firmware Upgrade Services". + - In the Release_Notes.html, find the memory address that corresponds to your device for the stm32wb5x_FUS_fw.bin file + - Select that file, the memory address, "verify download", and then "Firmware Upgrade". + - Once complete, in the Release_Notes.html, find the memory address that corresponds to your device for the + stm32wb5x_BLE_Stack_full_fw.bin file. It should not be the same memory address. + - Select that file, the memory address, "verify download", and then "Firmware Upgrade". + - Select "Start Wireless Stack". + - Disconnect from the device. + - In the examples folder for stm32wb, modify the memory.x file to match your target device. + - Run this example. + + Note: extended stack versions are not supported at this time. Do not attempt to install a stack with "extended" in the name. + */ + + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let config = Config::default(); + let mut mbox = TlMbox::init(p.IPCC, Irqs, config); + + let sys_event = mbox.sys_subsystem.read().await; + info!("sys event: {}", sys_event.payload()); + + mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; + + info!("resetting BLE..."); + mbox.ble_subsystem.reset().await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("config public address..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::public_address(get_bd_addr()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("config random address..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::random_address(get_random_addr()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("config identity root..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::identity_root(&get_irk()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("config encryption root..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::encryption_root(&get_erk()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("config tx power level..."); + mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("GATT init..."); + mbox.ble_subsystem.init_gatt().await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("GAP init..."); + mbox.ble_subsystem + .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + // info!("set scan response..."); + // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap(); + // let response = mbox.ble_subsystem.read().await.unwrap(); + // defmt::info!("{}", response); + + info!("set discoverable..."); + mbox.ble_subsystem + .set_discoverable(&DiscoverableParameters { + advertising_type: AdvertisingType::NonConnectableUndirected, + advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))), + address_type: OwnAddressType::Public, + filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan, + local_name: None, + advertising_data: &[], + conn_interval: (None, None), + }) + .await + .unwrap(); + + let response = mbox.ble_subsystem.read().await; + defmt::info!("{}", response); + + // remove some advertisement to decrease the packet size + info!("delete tx power ad type..."); + mbox.ble_subsystem + .delete_ad_type(AdvertisingDataType::TxPowerLevel) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("delete conn interval ad type..."); + mbox.ble_subsystem + .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("update advertising data..."); + mbox.ble_subsystem + .update_advertising_data(&eddystone_advertising_data()) + .await + .unwrap(); + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("update advertising data type..."); + mbox.ble_subsystem + .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe]) + .await + .unwrap(); + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + info!("update advertising data flags..."); + mbox.ble_subsystem + .update_advertising_data(&[ + 2, + AdvertisingDataType::Flags as u8, + (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support + ]) + .await + .unwrap(); + let response = mbox.ble_subsystem.read().await.unwrap(); + defmt::info!("{}", response); + + cortex_m::asm::wfi(); +} + +fn get_bd_addr() -> BdAddr { + let mut bytes = [0u8; 6]; + + let lhci_info = LhciC1DeviceInformationCcrp::new(); + bytes[0] = (lhci_info.uid64 & 0xff) as u8; + bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8; + bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8; + bytes[3] = lhci_info.device_type_id; + bytes[4] = (lhci_info.st_company_id & 0xff) as u8; + bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8; + + BdAddr(bytes) +} + +fn get_random_addr() -> BdAddr { + let mut bytes = [0u8; 6]; + + let lhci_info = LhciC1DeviceInformationCcrp::new(); + bytes[0] = (lhci_info.uid64 & 0xff) as u8; + bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8; + bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8; + bytes[3] = 0; + bytes[4] = 0x6E; + bytes[5] = 0xED; + + BdAddr(bytes) +} + +const BLE_CFG_IRK: [u8; 16] = [ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, +]; +const BLE_CFG_ERK: [u8; 16] = [ + 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, +]; + +fn get_irk() -> EncryptionKey { + EncryptionKey(BLE_CFG_IRK) +} + +fn get_erk() -> EncryptionKey { + EncryptionKey(BLE_CFG_ERK) +} + +fn eddystone_advertising_data() -> [u8; 24] { + const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com"; + + let mut service_data = [0u8; 24]; + let url_len = EDDYSTONE_URL.len(); + + service_data[0] = 6 + url_len as u8; + service_data[1] = AdvertisingDataType::ServiceData as u8; + + // 16-bit eddystone uuid + service_data[2] = 0xaa; + service_data[3] = 0xFE; + + service_data[4] = 0x10; // URL frame type + service_data[5] = 22_i8 as u8; // calibrated TX power at 0m + service_data[6] = 0x03; // eddystone url prefix = https + + service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL); + + service_data +} From 810c6af77af037a658186f8b102980ee84164a05 Mon Sep 17 00:00:00 2001 From: goueslati Date: Thu, 22 Jun 2023 15:31:45 +0100 Subject: [PATCH 12/74] fix build --- examples/stm32wb/src/bin/tl_mbox_ble.rs | 4 ++-- examples/stm32wb/src/bin/tl_mbox_mac.rs | 6 +++--- tests/stm32/src/bin/tl_mbox.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/stm32wb/src/bin/tl_mbox_ble.rs b/examples/stm32wb/src/bin/tl_mbox_ble.rs index 439bd01ac..a511e89aa 100644 --- a/examples/stm32wb/src/bin/tl_mbox_ble.rs +++ b/examples/stm32wb/src/bin/tl_mbox_ble.rs @@ -52,10 +52,10 @@ async fn main(_spawner: Spawner) { mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; info!("starting ble..."); - mbox.ble_subsystem.write(0x0c, &[]).await; + mbox.ble_subsystem.tl_write(0x0c, &[]).await; info!("waiting for ble..."); - let ble_event = mbox.ble_subsystem.read().await; + let ble_event = mbox.ble_subsystem.tl_read().await; info!("ble event: {}", ble_event.payload()); diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index a42939bbd..6c8653cf4 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -46,16 +46,16 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let mbox = TlMbox::init(p.IPCC, Irqs, config); - let sys_event = mbox.sys_subsystem.read().await; + let sys_event = mbox.sys_subsystem.tl_read().await; info!("sys event: {}", sys_event.payload()); mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; // // info!("starting ble..."); - // mbox.ble_subsystem.write(0x0c, &[]).await; + // mbox.ble_subsystem.t_write(0x0c, &[]).await; // // info!("waiting for ble..."); - // let ble_event = mbox.ble_subsystem.read().await; + // let ble_event = mbox.ble_subsystem.tl_read().await; // // info!("ble event: {}", ble_event.payload()); diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs index f47a89b6f..f55c0292a 100644 --- a/tests/stm32/src/bin/tl_mbox.rs +++ b/tests/stm32/src/bin/tl_mbox.rs @@ -63,10 +63,10 @@ async fn main(spawner: Spawner) { info!("subsystem initialization: {}", result); info!("starting ble..."); - mbox.ble_subsystem.write(0x0c, &[]).await; + mbox.ble_subsystem.tl_write(0x0c, &[]).await; info!("waiting for ble..."); - let ble_event = mbox.ble_subsystem.read().await; + let ble_event = mbox.ble_subsystem.tl_read().await; info!("ble event {:x} : {:x}", ble_event.stub().kind, ble_event.payload()); From 3dbd58f40e07eb4b5d41a671aec0fe71ac8c4b34 Mon Sep 17 00:00:00 2001 From: goueslati Date: Thu, 22 Jun 2023 15:59:03 +0100 Subject: [PATCH 13/74] fix unsound access in `EvtBox` --- embassy-stm32-wpan/Cargo.toml | 2 +- embassy-stm32-wpan/src/ble.rs | 5 +++-- embassy-stm32-wpan/src/evt.rs | 10 +--------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index fda4189ca..3659d7135 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -24,7 +24,7 @@ heapless = "0.7.16" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", optional = true } +bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true } [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs index 297ee4cdf..04acf0aff 100644 --- a/embassy-stm32-wpan/src/ble.rs +++ b/embassy-stm32-wpan/src/ble.rs @@ -70,9 +70,10 @@ impl hci::Controller for Ble { self.tl_write(opcode.0, payload).await; } - async fn controller_read(&self) -> &[u8] { + async fn controller_read_into(&self, buf: &mut [u8]) { let evt_box = self.tl_read().await; + let evt_serial = evt_box.serial(); - evt_box.serial() + buf[..evt_serial.len()].copy_from_slice(evt_serial); } } diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs index 7a4738b7a..25249a13a 100644 --- a/embassy-stm32-wpan/src/evt.rs +++ b/embassy-stm32-wpan/src/evt.rs @@ -106,14 +106,6 @@ impl EvtBox { Self { ptr } } - pub fn evt<'a>(&self) -> &'a [u8] { - unsafe { - let evt_packet = &(*self.ptr); - - core::slice::from_raw_parts(evt_packet as *const _ as *const u8, core::mem::size_of::()) - } - } - /// Returns information about the event pub fn stub(&self) -> EvtStub { unsafe { @@ -137,7 +129,7 @@ impl EvtBox { /// writes an underlying [`EvtPacket`] into the provided buffer. /// Returns the number of bytes that were written. /// Returns an error if event kind is unknown or if provided buffer size is not enough. - pub fn serial<'a>(&self) -> &'a [u8] { + pub fn serial<'a>(&'a self) -> &'a [u8] { unsafe { let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial; let evt_serial_buf: *const u8 = evt_serial.cast(); From 6c123596b7d48ee66ea93e8b1515e91231e9bced Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 9 Jun 2023 03:36:48 +0200 Subject: [PATCH 14/74] wip: esp-hosted net driver. --- embassy-net-esp-hosted/Cargo.toml | 20 + embassy-net-esp-hosted/src/control.rs | 141 +++++ .../src/esp_hosted_config.proto | 432 +++++++++++++ embassy-net-esp-hosted/src/fmt.rs | 257 ++++++++ embassy-net-esp-hosted/src/ioctl.rs | 119 ++++ embassy-net-esp-hosted/src/lib.rs | 300 +++++++++ embassy-net-esp-hosted/src/proto.rs | 598 ++++++++++++++++++ examples/nrf52840/Cargo.toml | 2 + examples/nrf52840/src/bin/wifi_esp_hosted.rs | 143 +++++ 9 files changed, 2012 insertions(+) create mode 100644 embassy-net-esp-hosted/Cargo.toml create mode 100644 embassy-net-esp-hosted/src/control.rs create mode 100644 embassy-net-esp-hosted/src/esp_hosted_config.proto create mode 100644 embassy-net-esp-hosted/src/fmt.rs create mode 100644 embassy-net-esp-hosted/src/ioctl.rs create mode 100644 embassy-net-esp-hosted/src/lib.rs create mode 100644 embassy-net-esp-hosted/src/proto.rs create mode 100644 examples/nrf52840/src/bin/wifi_esp_hosted.rs diff --git a/embassy-net-esp-hosted/Cargo.toml b/embassy-net-esp-hosted/Cargo.toml new file mode 100644 index 000000000..a7e18ee09 --- /dev/null +++ b/embassy-net-esp-hosted/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "embassy-net-esp-hosted" +version = "0.1.0" +edition = "2021" + +[dependencies] +defmt = { version = "0.3", optional = true } +log = { version = "0.4.14", optional = true } + +embassy-time = { version = "0.1.0", path = "../embassy-time" } +embassy-sync = { version = "0.2.0", path = "../embassy-sync"} +embassy-futures = { version = "0.1.0", path = "../embassy-futures"} +embassy-net-driver-channel = { version = "0.1.0", path = "../embassy-net-driver-channel"} + +embedded-hal = { version = "1.0.0-alpha.10" } +embedded-hal-async = { version = "=0.2.0-alpha.1" } + +noproto = { git="https://github.com/embassy-rs/noproto", default-features = false, features = ["derive"] } +#noproto = { version = "0.1", path = "/home/dirbaio/noproto", default-features = false, features = ["derive"] } +heapless = "0.7.16" diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs new file mode 100644 index 000000000..2381c6b84 --- /dev/null +++ b/embassy-net-esp-hosted/src/control.rs @@ -0,0 +1,141 @@ +use ch::driver::LinkState; +use defmt::Debug2Format; +use embassy_net_driver_channel as ch; +use heapless::String; + +use crate::ioctl::IoctlState; +use crate::proto::{self, CtrlMsg}; + +#[derive(Debug)] +pub struct Error { + pub status: u32, +} + +pub struct Control<'a> { + state_ch: ch::StateRunner<'a>, + ioctl_state: &'a IoctlState, +} + +enum WifiMode { + None = 0, + Sta = 1, + Ap = 2, + ApSta = 3, +} + +impl<'a> Control<'a> { + pub(crate) fn new(state_ch: ch::StateRunner<'a>, ioctl_state: &'a IoctlState) -> Self { + Self { state_ch, ioctl_state } + } + + pub async fn init(&mut self) { + debug!("set wifi mode"); + self.set_wifi_mode(WifiMode::Sta as _).await; + let mac_addr = self.get_mac_addr().await; + debug!("mac addr: {:02x}", mac_addr); + self.state_ch.set_ethernet_address(mac_addr); + } + + pub async fn join(&mut self, ssid: &str, password: &str) { + let req = proto::CtrlMsg { + msg_id: proto::CtrlMsgId::ReqConnectAp as _, + msg_type: proto::CtrlMsgType::Req as _, + payload: Some(proto::CtrlMsgPayload::ReqConnectAp(proto::CtrlMsgReqConnectAp { + ssid: String::from(ssid), + pwd: String::from(password), + bssid: String::new(), + listen_interval: 3, + is_wpa3_supported: false, + })), + }; + let resp = self.ioctl(req).await; + let proto::CtrlMsgPayload::RespConnectAp(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; + debug!("======= {:?}", Debug2Format(&resp)); + assert_eq!(resp.resp, 0); + self.state_ch.set_link_state(LinkState::Up); + } + + async fn get_mac_addr(&mut self) -> [u8; 6] { + let req = proto::CtrlMsg { + msg_id: proto::CtrlMsgId::ReqGetMacAddress as _, + msg_type: proto::CtrlMsgType::Req as _, + payload: Some(proto::CtrlMsgPayload::ReqGetMacAddress( + proto::CtrlMsgReqGetMacAddress { + mode: WifiMode::Sta as _, + }, + )), + }; + let resp = self.ioctl(req).await; + let proto::CtrlMsgPayload::RespGetMacAddress(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; + assert_eq!(resp.resp, 0); + + // WHY IS THIS A STRING? WHYYYY + fn nibble_from_hex(b: u8) -> u8 { + match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' => b + 0xa - b'a', + b'A'..=b'F' => b + 0xa - b'A', + _ => panic!("invalid hex digit {}", b), + } + } + + let mac = resp.mac.as_bytes(); + let mut res = [0; 6]; + assert_eq!(mac.len(), 17); + for (i, b) in res.iter_mut().enumerate() { + *b = (nibble_from_hex(mac[i * 3]) << 4) | nibble_from_hex(mac[i * 3 + 1]) + } + res + } + + async fn get_wifi_mode(&mut self) -> u32 { + let req = proto::CtrlMsg { + msg_id: proto::CtrlMsgId::ReqGetWifiMode as _, + msg_type: proto::CtrlMsgType::Req as _, + payload: Some(proto::CtrlMsgPayload::ReqGetWifiMode(proto::CtrlMsgReqGetMode {})), + }; + let resp = self.ioctl(req).await; + let proto::CtrlMsgPayload::RespGetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; + assert_eq!(resp.resp, 0); + resp.mode + } + + async fn set_wifi_mode(&mut self, mode: u32) { + let req = proto::CtrlMsg { + msg_id: proto::CtrlMsgId::ReqSetWifiMode as _, + msg_type: proto::CtrlMsgType::Req as _, + payload: Some(proto::CtrlMsgPayload::ReqSetWifiMode(proto::CtrlMsgReqSetMode { mode })), + }; + let resp = self.ioctl(req).await; + let proto::CtrlMsgPayload::RespSetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; + assert_eq!(resp.resp, 0); + } + + async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg { + let mut buf = [0u8; 128]; + + let req_len = noproto::write(&req, &mut buf).unwrap(); + + struct CancelOnDrop<'a>(&'a IoctlState); + + impl CancelOnDrop<'_> { + fn defuse(self) { + core::mem::forget(self); + } + } + + impl Drop for CancelOnDrop<'_> { + fn drop(&mut self) { + self.0.cancel_ioctl(); + } + } + + let ioctl = CancelOnDrop(self.ioctl_state); + + let resp_len = ioctl.0.do_ioctl(&mut buf, req_len).await; + + ioctl.defuse(); + + noproto::read(&buf[..resp_len]).unwrap() + } +} diff --git a/embassy-net-esp-hosted/src/esp_hosted_config.proto b/embassy-net-esp-hosted/src/esp_hosted_config.proto new file mode 100644 index 000000000..aa1bfde64 --- /dev/null +++ b/embassy-net-esp-hosted/src/esp_hosted_config.proto @@ -0,0 +1,432 @@ +syntax = "proto3"; + +/* Enums similar to ESP IDF */ +enum Ctrl_VendorIEType { + Beacon = 0; + Probe_req = 1; + Probe_resp = 2; + Assoc_req = 3; + Assoc_resp = 4; +} + +enum Ctrl_VendorIEID { + ID_0 = 0; + ID_1 = 1; +} + +enum Ctrl_WifiMode { + NONE = 0; + STA = 1; + AP = 2; + APSTA = 3; +} + +enum Ctrl_WifiBw { + BW_Invalid = 0; + HT20 = 1; + HT40 = 2; +} + +enum Ctrl_WifiPowerSave { + PS_Invalid = 0; + MIN_MODEM = 1; + MAX_MODEM = 2; +} + +enum Ctrl_WifiSecProt { + Open = 0; + WEP = 1; + WPA_PSK = 2; + WPA2_PSK = 3; + WPA_WPA2_PSK = 4; + WPA2_ENTERPRISE = 5; + WPA3_PSK = 6; + WPA2_WPA3_PSK = 7; +} + +/* enums for Control path */ +enum Ctrl_Status { + Connected = 0; + Not_Connected = 1; + No_AP_Found = 2; + Connection_Fail = 3; + Invalid_Argument = 4; + Out_Of_Range = 5; +} + + +enum CtrlMsgType { + MsgType_Invalid = 0; + Req = 1; + Resp = 2; + Event = 3; + MsgType_Max = 4; +} + +enum CtrlMsgId { + MsgId_Invalid = 0; + + /** Request Msgs **/ + Req_Base = 100; + + Req_GetMACAddress = 101; + Req_SetMacAddress = 102; + Req_GetWifiMode = 103; + Req_SetWifiMode = 104; + + Req_GetAPScanList = 105; + Req_GetAPConfig = 106; + Req_ConnectAP = 107; + Req_DisconnectAP = 108; + + Req_GetSoftAPConfig = 109; + Req_SetSoftAPVendorSpecificIE = 110; + Req_StartSoftAP = 111; + Req_GetSoftAPConnectedSTAList = 112; + Req_StopSoftAP = 113; + + Req_SetPowerSaveMode = 114; + Req_GetPowerSaveMode = 115; + + Req_OTABegin = 116; + Req_OTAWrite = 117; + Req_OTAEnd = 118; + + Req_SetWifiMaxTxPower = 119; + Req_GetWifiCurrTxPower = 120; + + Req_ConfigHeartbeat = 121; + /* Add new control path command response before Req_Max + * and update Req_Max */ + Req_Max = 122; + + /** Response Msgs **/ + Resp_Base = 200; + + Resp_GetMACAddress = 201; + Resp_SetMacAddress = 202; + Resp_GetWifiMode = 203; + Resp_SetWifiMode = 204; + + Resp_GetAPScanList = 205; + Resp_GetAPConfig = 206; + Resp_ConnectAP = 207; + Resp_DisconnectAP = 208; + + Resp_GetSoftAPConfig = 209; + Resp_SetSoftAPVendorSpecificIE = 210; + Resp_StartSoftAP = 211; + Resp_GetSoftAPConnectedSTAList = 212; + Resp_StopSoftAP = 213; + + Resp_SetPowerSaveMode = 214; + Resp_GetPowerSaveMode = 215; + + Resp_OTABegin = 216; + Resp_OTAWrite = 217; + Resp_OTAEnd = 218; + + Resp_SetWifiMaxTxPower = 219; + Resp_GetWifiCurrTxPower = 220; + + Resp_ConfigHeartbeat = 221; + /* Add new control path command response before Resp_Max + * and update Resp_Max */ + Resp_Max = 222; + + /** Event Msgs **/ + Event_Base = 300; + Event_ESPInit = 301; + Event_Heartbeat = 302; + Event_StationDisconnectFromAP = 303; + Event_StationDisconnectFromESPSoftAP = 304; + /* Add new control path command notification before Event_Max + * and update Event_Max */ + Event_Max = 305; +} + +/* internal supporting structures for CtrlMsg */ +message ScanResult { + bytes ssid = 1; + uint32 chnl = 2; + int32 rssi = 3; + bytes bssid = 4; + Ctrl_WifiSecProt sec_prot = 5; +} + +message ConnectedSTAList { + bytes mac = 1; + int32 rssi = 2; +} + + +/* Control path structures */ +/** Req/Resp structure **/ +message CtrlMsg_Req_GetMacAddress { + int32 mode = 1; +} + +message CtrlMsg_Resp_GetMacAddress { + bytes mac = 1; + int32 resp = 2; +} + +message CtrlMsg_Req_GetMode { +} + +message CtrlMsg_Resp_GetMode { + int32 mode = 1; + int32 resp = 2; +} + +message CtrlMsg_Req_SetMode { + int32 mode = 1; +} + +message CtrlMsg_Resp_SetMode { + int32 resp = 1; +} + +message CtrlMsg_Req_GetStatus { +} + +message CtrlMsg_Resp_GetStatus { + int32 resp = 1; +} + +message CtrlMsg_Req_SetMacAddress { + bytes mac = 1; + int32 mode = 2; +} + +message CtrlMsg_Resp_SetMacAddress { + int32 resp = 1; +} + +message CtrlMsg_Req_GetAPConfig { +} + +message CtrlMsg_Resp_GetAPConfig { + bytes ssid = 1; + bytes bssid = 2; + int32 rssi = 3; + int32 chnl = 4; + Ctrl_WifiSecProt sec_prot = 5; + int32 resp = 6; +} + +message CtrlMsg_Req_ConnectAP { + string ssid = 1; + string pwd = 2; + string bssid = 3; + bool is_wpa3_supported = 4; + int32 listen_interval = 5; +} + +message CtrlMsg_Resp_ConnectAP { + int32 resp = 1; + bytes mac = 2; +} + +message CtrlMsg_Req_GetSoftAPConfig { +} + +message CtrlMsg_Resp_GetSoftAPConfig { + bytes ssid = 1; + bytes pwd = 2; + int32 chnl = 3; + Ctrl_WifiSecProt sec_prot = 4; + int32 max_conn = 5; + bool ssid_hidden = 6; + int32 bw = 7; + int32 resp = 8; +} + +message CtrlMsg_Req_StartSoftAP { + string ssid = 1; + string pwd = 2; + int32 chnl = 3; + Ctrl_WifiSecProt sec_prot = 4; + int32 max_conn = 5; + bool ssid_hidden = 6; + int32 bw = 7; +} + +message CtrlMsg_Resp_StartSoftAP { + int32 resp = 1; + bytes mac = 2; +} + +message CtrlMsg_Req_ScanResult { +} + +message CtrlMsg_Resp_ScanResult { + uint32 count = 1; + repeated ScanResult entries = 2; + int32 resp = 3; +} + +message CtrlMsg_Req_SoftAPConnectedSTA { +} + +message CtrlMsg_Resp_SoftAPConnectedSTA { + uint32 num = 1; + repeated ConnectedSTAList stations = 2; + int32 resp = 3; +} + +message CtrlMsg_Req_OTABegin { +} + +message CtrlMsg_Resp_OTABegin { + int32 resp = 1; +} + +message CtrlMsg_Req_OTAWrite { + bytes ota_data = 1; +} + +message CtrlMsg_Resp_OTAWrite { + int32 resp = 1; +} + +message CtrlMsg_Req_OTAEnd { +} + +message CtrlMsg_Resp_OTAEnd { + int32 resp = 1; +} + +message CtrlMsg_Req_VendorIEData { + int32 element_id = 1; + int32 length = 2; + bytes vendor_oui = 3; + int32 vendor_oui_type = 4; + bytes payload = 5; +} + +message CtrlMsg_Req_SetSoftAPVendorSpecificIE { + bool enable = 1; + Ctrl_VendorIEType type = 2; + Ctrl_VendorIEID idx = 3; + CtrlMsg_Req_VendorIEData vendor_ie_data = 4; +} + +message CtrlMsg_Resp_SetSoftAPVendorSpecificIE { + int32 resp = 1; +} + +message CtrlMsg_Req_SetWifiMaxTxPower { + int32 wifi_max_tx_power = 1; +} + +message CtrlMsg_Resp_SetWifiMaxTxPower { + int32 resp = 1; +} + +message CtrlMsg_Req_GetWifiCurrTxPower { +} + +message CtrlMsg_Resp_GetWifiCurrTxPower { + int32 wifi_curr_tx_power = 1; + int32 resp = 2; +} + +message CtrlMsg_Req_ConfigHeartbeat { + bool enable = 1; + int32 duration = 2; +} + +message CtrlMsg_Resp_ConfigHeartbeat { + int32 resp = 1; +} + +/** Event structure **/ +message CtrlMsg_Event_ESPInit { + bytes init_data = 1; +} + +message CtrlMsg_Event_Heartbeat { + int32 hb_num = 1; +} + +message CtrlMsg_Event_StationDisconnectFromAP { + int32 resp = 1; +} + +message CtrlMsg_Event_StationDisconnectFromESPSoftAP { + int32 resp = 1; + bytes mac = 2; +} + +message CtrlMsg { + /* msg_type could be req, resp or Event */ + CtrlMsgType msg_type = 1; + + /* msg id */ + CtrlMsgId msg_id = 2; + + /* union of all msg ids */ + oneof payload { + /** Requests **/ + CtrlMsg_Req_GetMacAddress req_get_mac_address = 101; + CtrlMsg_Req_SetMacAddress req_set_mac_address = 102; + CtrlMsg_Req_GetMode req_get_wifi_mode = 103; + CtrlMsg_Req_SetMode req_set_wifi_mode = 104; + + CtrlMsg_Req_ScanResult req_scan_ap_list = 105; + CtrlMsg_Req_GetAPConfig req_get_ap_config = 106; + CtrlMsg_Req_ConnectAP req_connect_ap = 107; + CtrlMsg_Req_GetStatus req_disconnect_ap = 108; + + CtrlMsg_Req_GetSoftAPConfig req_get_softap_config = 109; + CtrlMsg_Req_SetSoftAPVendorSpecificIE req_set_softap_vendor_specific_ie = 110; + CtrlMsg_Req_StartSoftAP req_start_softap = 111; + CtrlMsg_Req_SoftAPConnectedSTA req_softap_connected_stas_list = 112; + CtrlMsg_Req_GetStatus req_stop_softap = 113; + + CtrlMsg_Req_SetMode req_set_power_save_mode = 114; + CtrlMsg_Req_GetMode req_get_power_save_mode = 115; + + CtrlMsg_Req_OTABegin req_ota_begin = 116; + CtrlMsg_Req_OTAWrite req_ota_write = 117; + CtrlMsg_Req_OTAEnd req_ota_end = 118; + + CtrlMsg_Req_SetWifiMaxTxPower req_set_wifi_max_tx_power = 119; + CtrlMsg_Req_GetWifiCurrTxPower req_get_wifi_curr_tx_power = 120; + CtrlMsg_Req_ConfigHeartbeat req_config_heartbeat = 121; + + /** Responses **/ + CtrlMsg_Resp_GetMacAddress resp_get_mac_address = 201; + CtrlMsg_Resp_SetMacAddress resp_set_mac_address = 202; + CtrlMsg_Resp_GetMode resp_get_wifi_mode = 203; + CtrlMsg_Resp_SetMode resp_set_wifi_mode = 204; + + CtrlMsg_Resp_ScanResult resp_scan_ap_list = 205; + CtrlMsg_Resp_GetAPConfig resp_get_ap_config = 206; + CtrlMsg_Resp_ConnectAP resp_connect_ap = 207; + CtrlMsg_Resp_GetStatus resp_disconnect_ap = 208; + + CtrlMsg_Resp_GetSoftAPConfig resp_get_softap_config = 209; + CtrlMsg_Resp_SetSoftAPVendorSpecificIE resp_set_softap_vendor_specific_ie = 210; + CtrlMsg_Resp_StartSoftAP resp_start_softap = 211; + CtrlMsg_Resp_SoftAPConnectedSTA resp_softap_connected_stas_list = 212; + CtrlMsg_Resp_GetStatus resp_stop_softap = 213; + + CtrlMsg_Resp_SetMode resp_set_power_save_mode = 214; + CtrlMsg_Resp_GetMode resp_get_power_save_mode = 215; + + CtrlMsg_Resp_OTABegin resp_ota_begin = 216; + CtrlMsg_Resp_OTAWrite resp_ota_write = 217; + CtrlMsg_Resp_OTAEnd resp_ota_end = 218; + CtrlMsg_Resp_SetWifiMaxTxPower resp_set_wifi_max_tx_power = 219; + CtrlMsg_Resp_GetWifiCurrTxPower resp_get_wifi_curr_tx_power = 220; + CtrlMsg_Resp_ConfigHeartbeat resp_config_heartbeat = 221; + + /** Notifications **/ + CtrlMsg_Event_ESPInit event_esp_init = 301; + CtrlMsg_Event_Heartbeat event_heartbeat = 302; + CtrlMsg_Event_StationDisconnectFromAP event_station_disconnect_from_AP = 303; + CtrlMsg_Event_StationDisconnectFromESPSoftAP event_station_disconnect_from_ESP_SoftAP = 304; + } +} diff --git a/embassy-net-esp-hosted/src/fmt.rs b/embassy-net-esp-hosted/src/fmt.rs new file mode 100644 index 000000000..91984bde1 --- /dev/null +++ b/embassy-net-esp-hosted/src/fmt.rs @@ -0,0 +1,257 @@ +#![macro_use] +#![allow(unused_macros)] + +use core::fmt::{Debug, Display, LowerHex}; + +#[cfg(all(feature = "defmt", feature = "log"))] +compile_error!("You may not enable both `defmt` and `log` features."); + +macro_rules! assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert!($($x)*); + } + }; +} + +macro_rules! assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_eq!($($x)*); + } + }; +} + +macro_rules! assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::assert_ne!($($x)*); + } + }; +} + +macro_rules! debug_assert { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert!($($x)*); + } + }; +} + +macro_rules! debug_assert_eq { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_eq!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_eq!($($x)*); + } + }; +} + +macro_rules! debug_assert_ne { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::debug_assert_ne!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::debug_assert_ne!($($x)*); + } + }; +} + +macro_rules! todo { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::todo!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::todo!($($x)*); + } + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unreachable { + ($($x:tt)*) => { + ::core::unreachable!($($x)*) + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unreachable { + ($($x:tt)*) => { + ::defmt::unreachable!($($x)*); + }; +} + +macro_rules! panic { + ($($x:tt)*) => { + { + #[cfg(not(feature = "defmt"))] + ::core::panic!($($x)*); + #[cfg(feature = "defmt")] + ::defmt::panic!($($x)*); + } + }; +} + +macro_rules! trace { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::trace!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::trace!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! debug { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::debug!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::debug!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! info { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::info!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::info!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! warn { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::warn!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::warn!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +macro_rules! error { + ($s:literal $(, $x:expr)* $(,)?) => { + { + #[cfg(feature = "log")] + ::log::error!($s $(, $x)*); + #[cfg(feature = "defmt")] + ::defmt::error!($s $(, $x)*); + #[cfg(not(any(feature = "log", feature="defmt")))] + let _ = ($( & $x ),*); + } + }; +} + +#[cfg(feature = "defmt")] +macro_rules! unwrap { + ($($x:tt)*) => { + ::defmt::unwrap!($($x)*) + }; +} + +#[cfg(not(feature = "defmt"))] +macro_rules! unwrap { + ($arg:expr) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); + } + } + }; + ($arg:expr, $($msg:expr),+ $(,)? ) => { + match $crate::fmt::Try::into_result($arg) { + ::core::result::Result::Ok(t) => t, + ::core::result::Result::Err(e) => { + ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct NoneError; + +pub trait Try { + type Ok; + type Error; + fn into_result(self) -> Result; +} + +impl Try for Option { + type Ok = T; + type Error = NoneError; + + #[inline] + fn into_result(self) -> Result { + self.ok_or(NoneError) + } +} + +impl Try for Result { + type Ok = T; + type Error = E; + + #[inline] + fn into_result(self) -> Self { + self + } +} + +pub struct Bytes<'a>(pub &'a [u8]); + +impl<'a> Debug for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> Display for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +impl<'a> LowerHex for Bytes<'a> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:#02x?}", self.0) + } +} + +#[cfg(feature = "defmt")] +impl<'a> defmt::Format for Bytes<'a> { + fn format(&self, fmt: defmt::Formatter) { + defmt::write!(fmt, "{:02x}", self.0) + } +} diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs new file mode 100644 index 000000000..59bdabf37 --- /dev/null +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -0,0 +1,119 @@ +use core::cell::{Cell, RefCell}; +use core::future::poll_fn; +use core::task::{Poll, Waker}; + +use embassy_sync::waitqueue::WakerRegistration; + +use crate::fmt::Bytes; + +#[derive(Clone, Copy)] +pub struct PendingIoctl { + pub buf: *mut [u8], + pub req_len: usize, +} + +#[derive(Clone, Copy)] +enum IoctlStateInner { + Pending(PendingIoctl), + Sent { buf: *mut [u8] }, + Done { resp_len: usize }, +} + +struct Wakers { + control: WakerRegistration, + runner: WakerRegistration, +} + +impl Default for Wakers { + fn default() -> Self { + Self { + control: WakerRegistration::new(), + runner: WakerRegistration::new(), + } + } +} + +pub struct IoctlState { + state: Cell, + wakers: RefCell, +} + +impl IoctlState { + pub fn new() -> Self { + Self { + state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), + wakers: Default::default(), + } + } + + fn wake_control(&self) { + self.wakers.borrow_mut().control.wake(); + } + + fn register_control(&self, waker: &Waker) { + self.wakers.borrow_mut().control.register(waker); + } + + fn wake_runner(&self) { + self.wakers.borrow_mut().runner.wake(); + } + + fn register_runner(&self, waker: &Waker) { + self.wakers.borrow_mut().runner.register(waker); + } + + pub async fn wait_complete(&self) -> usize { + poll_fn(|cx| { + if let IoctlStateInner::Done { resp_len } = self.state.get() { + Poll::Ready(resp_len) + } else { + self.register_control(cx.waker()); + Poll::Pending + } + }) + .await + } + + pub async fn wait_pending(&self) -> PendingIoctl { + let pending = poll_fn(|cx| { + if let IoctlStateInner::Pending(pending) = self.state.get() { + Poll::Ready(pending) + } else { + self.register_runner(cx.waker()); + Poll::Pending + } + }) + .await; + + self.state.set(IoctlStateInner::Sent { buf: pending.buf }); + pending + } + + pub fn cancel_ioctl(&self) { + self.state.set(IoctlStateInner::Done { resp_len: 0 }); + } + + pub async fn do_ioctl(&self, buf: &mut [u8], req_len: usize) -> usize { + debug!("IOCTL Request: {:02x}", Bytes(&buf[..req_len])); + + self.state.set(IoctlStateInner::Pending(PendingIoctl { buf, req_len })); + self.wake_runner(); + self.wait_complete().await + } + + pub fn ioctl_done(&self, response: &[u8]) { + if let IoctlStateInner::Sent { buf } = self.state.get() { + debug!("IOCTL Response: {:02x}", Bytes(response)); + + // TODO fix this + (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); + + self.state.set(IoctlStateInner::Done { + resp_len: response.len(), + }); + self.wake_control(); + } else { + warn!("IOCTL Response but no pending Ioctl"); + } + } +} diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs new file mode 100644 index 000000000..2cf05a7df --- /dev/null +++ b/embassy-net-esp-hosted/src/lib.rs @@ -0,0 +1,300 @@ +#![no_std] + +use control::Control; +use embassy_futures::select::{select3, Either3}; +use embassy_net_driver_channel as ch; +use embassy_time::{Duration, Instant, Timer}; +use embedded_hal::digital::{InputPin, OutputPin}; +use embedded_hal_async::digital::Wait; +use embedded_hal_async::spi::SpiDevice; +use ioctl::IoctlState; + +use crate::ioctl::PendingIoctl; + +mod proto; + +// must be first +mod fmt; + +mod control; +mod ioctl; + +const MTU: usize = 1514; + +macro_rules! impl_bytes { + ($t:ident) => { + impl $t { + pub const SIZE: usize = core::mem::size_of::(); + + #[allow(unused)] + pub fn to_bytes(&self) -> [u8; Self::SIZE] { + unsafe { core::mem::transmute(*self) } + } + + #[allow(unused)] + pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self { + let alignment = core::mem::align_of::(); + assert_eq!( + bytes.as_ptr().align_offset(alignment), + 0, + "{} is not aligned", + core::any::type_name::() + ); + unsafe { core::mem::transmute(bytes) } + } + + #[allow(unused)] + pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self { + let alignment = core::mem::align_of::(); + assert_eq!( + bytes.as_ptr().align_offset(alignment), + 0, + "{} is not aligned", + core::any::type_name::() + ); + + unsafe { core::mem::transmute(bytes) } + } + } + }; +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug, Default)] +struct PayloadHeader { + /// InterfaceType on lower 4 bits, number on higher 4 bits. + if_type_and_num: u8, + + /// Flags. + /// + /// bit 0: more fragments. + flags: u8, + + len: u16, + offset: u16, + checksum: u16, + seq_num: u16, + reserved2: u8, + + /// Packet type for HCI or PRIV interface, reserved otherwise + hci_priv_packet_type: u8, +} +impl_bytes!(PayloadHeader); + +#[repr(u8)] +enum InterfaceType { + Sta = 0, + Ap = 1, + Serial = 2, + Hci = 3, + Priv = 4, + Test = 5, +} + +const MAX_SPI_BUFFER_SIZE: usize = 1600; + +pub struct State { + ioctl_state: IoctlState, + ch: ch::State, +} + +impl State { + pub fn new() -> Self { + Self { + ioctl_state: IoctlState::new(), + ch: ch::State::new(), + } + } +} + +pub type NetDriver<'a> = ch::Device<'a, MTU>; + +pub async fn new<'a, SPI, IN, OUT>( + state: &'a mut State, + spi: SPI, + handshake: IN, + ready: IN, + reset: OUT, +) -> (NetDriver<'a>, Control<'a>, Runner<'a, SPI, IN, OUT>) +where + SPI: SpiDevice, + IN: InputPin + Wait, + OUT: OutputPin, +{ + let (ch_runner, device) = ch::new(&mut state.ch, [0; 6]); + let state_ch = ch_runner.state_runner(); + + let mut runner = Runner { + ch: ch_runner, + ioctl_state: &state.ioctl_state, + next_seq: 1, + handshake, + ready, + reset, + spi, + }; + runner.init().await; + + (device, Control::new(state_ch, &state.ioctl_state), runner) +} + +pub struct Runner<'a, SPI, IN, OUT> { + ch: ch::Runner<'a, MTU>, + ioctl_state: &'a IoctlState, + + next_seq: u16, + + spi: SPI, + handshake: IN, + ready: IN, + reset: OUT, +} + +impl<'a, SPI, IN, OUT> Runner<'a, SPI, IN, OUT> +where + SPI: SpiDevice, + IN: InputPin + Wait, + OUT: OutputPin, +{ + async fn init(&mut self) {} + + pub async fn run(mut self) -> ! { + debug!("resetting..."); + self.reset.set_low().unwrap(); + Timer::after(Duration::from_millis(100)).await; + self.reset.set_high().unwrap(); + Timer::after(Duration::from_millis(1000)).await; + + let mut tx_buf = [0u8; MAX_SPI_BUFFER_SIZE]; + let mut rx_buf = [0u8; MAX_SPI_BUFFER_SIZE]; + + loop { + self.handshake.wait_for_high().await.unwrap(); + + let ioctl = self.ioctl_state.wait_pending(); + let tx = self.ch.tx_buf(); + let ev = async { self.ready.wait_for_high().await.unwrap() }; + + match select3(ioctl, tx, ev).await { + Either3::First(PendingIoctl { buf, req_len }) => { + tx_buf[12..24].copy_from_slice(b"\x01\x08\x00ctrlResp\x02"); + tx_buf[24..26].copy_from_slice(&(req_len as u16).to_le_bytes()); + tx_buf[26..][..req_len].copy_from_slice(&unsafe { &*buf }[..req_len]); + + let mut header = PayloadHeader { + if_type_and_num: InterfaceType::Serial as _, + len: (req_len + 14) as _, + offset: PayloadHeader::SIZE as _, + seq_num: self.next_seq, + ..Default::default() + }; + self.next_seq = self.next_seq.wrapping_add(1); + + // Calculate checksum + tx_buf[0..12].copy_from_slice(&header.to_bytes()); + header.checksum = checksum(&tx_buf[..26 + req_len]); + tx_buf[0..12].copy_from_slice(&header.to_bytes()); + + debug!("====== SENDING IOCTL"); + } + Either3::Second(packet) => { + tx_buf[12..][..packet.len()].copy_from_slice(packet); + + let mut header = PayloadHeader { + if_type_and_num: InterfaceType::Sta as _, + len: packet.len() as _, + offset: PayloadHeader::SIZE as _, + seq_num: self.next_seq, + ..Default::default() + }; + self.next_seq = self.next_seq.wrapping_add(1); + + // Calculate checksum + tx_buf[0..12].copy_from_slice(&header.to_bytes()); + header.checksum = checksum(&tx_buf[..12 + packet.len()]); + tx_buf[0..12].copy_from_slice(&header.to_bytes()); + + self.ch.tx_done(); + } + Either3::Third(()) => { + tx_buf[..PayloadHeader::SIZE].fill(0); + } + } + + if tx_buf[0] != 0 { + trace!("tx: {:02x}", &tx_buf[..40]); + } + + self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); + let delay_until = Instant::now() + Duration::from_millis(1); + self.handle_rx(&mut rx_buf); + Timer::at(delay_until).await; + } + } + + fn handle_rx(&mut self, buf: &mut [u8]) { + trace!("rx: {:02x}", &buf[..40]); + + let buf_len = buf.len(); + let h = PayloadHeader::from_bytes_mut((&mut buf[..PayloadHeader::SIZE]).try_into().unwrap()); + + if h.len == 0 || h.offset as usize != PayloadHeader::SIZE { + return; + } + + let payload_len = h.len as usize; + if buf_len < PayloadHeader::SIZE + payload_len { + warn!("rx: len too big"); + return; + } + + let if_type_and_num = h.if_type_and_num; + let want_checksum = h.checksum; + h.checksum = 0; + let got_checksum = checksum(&buf[..PayloadHeader::SIZE + payload_len]); + if want_checksum != got_checksum { + warn!("rx: bad checksum. Got {:04x}, want {:04x}", got_checksum, want_checksum); + return; + } + + let payload = &mut buf[PayloadHeader::SIZE..][..payload_len]; + + match if_type_and_num & 0x0f { + // STA + 0 => match self.ch.try_rx_buf() { + Some(buf) => { + buf[..payload.len()].copy_from_slice(payload); + self.ch.rx_done(payload.len()) + } + None => warn!("failed to push rxd packet to the channel."), + }, + // serial + 2 => { + debug!("serial rx: {:02x}", payload); + if payload.len() < 14 { + warn!("serial rx: too short"); + return; + } + if &payload[..12] != b"\x01\x08\x00ctrlResp\x02" { + warn!("serial rx: bad tlv"); + return; + } + let len = u16::from_le_bytes(payload[12..14].try_into().unwrap()) as usize; + if payload.len() < 14 + len { + warn!("serial rx: too short 2"); + return; + } + self.ioctl_state.ioctl_done(&payload[14..][..len]); + } + _ => warn!("unknown iftype {}", if_type_and_num), + } + } +} + +fn checksum(buf: &[u8]) -> u16 { + let mut res = 0u16; + for &b in buf { + res = res.wrapping_add(b as _); + } + res +} diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs new file mode 100644 index 000000000..e105e393c --- /dev/null +++ b/embassy-net-esp-hosted/src/proto.rs @@ -0,0 +1,598 @@ +use heapless::{String, Vec}; + +/// internal supporting structures for CtrlMsg + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct ScanResult { + #[noproto(tag = "1")] + pub ssid: String<32>, + #[noproto(tag = "2")] + pub chnl: u32, + #[noproto(tag = "3")] + pub rssi: u32, + #[noproto(tag = "4")] + pub bssid: String<32>, + #[noproto(tag = "5")] + pub sec_prot: CtrlWifiSecProt, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct ConnectedStaList { + #[noproto(tag = "1")] + pub mac: String<32>, + #[noproto(tag = "2")] + pub rssi: u32, +} +/// * Req/Resp structure * + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqGetMacAddress { + #[noproto(tag = "1")] + pub mode: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespGetMacAddress { + #[noproto(tag = "1")] + pub mac: String<32>, + #[noproto(tag = "2")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqGetMode {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespGetMode { + #[noproto(tag = "1")] + pub mode: u32, + #[noproto(tag = "2")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqSetMode { + #[noproto(tag = "1")] + pub mode: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespSetMode { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqGetStatus {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespGetStatus { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqSetMacAddress { + #[noproto(tag = "1")] + pub mac: String<32>, + #[noproto(tag = "2")] + pub mode: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespSetMacAddress { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqGetApConfig {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespGetApConfig { + #[noproto(tag = "1")] + pub ssid: String<32>, + #[noproto(tag = "2")] + pub bssid: String<32>, + #[noproto(tag = "3")] + pub rssi: u32, + #[noproto(tag = "4")] + pub chnl: u32, + #[noproto(tag = "5")] + pub sec_prot: CtrlWifiSecProt, + #[noproto(tag = "6")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqConnectAp { + #[noproto(tag = "1")] + pub ssid: String<32>, + #[noproto(tag = "2")] + pub pwd: String<32>, + #[noproto(tag = "3")] + pub bssid: String<32>, + #[noproto(tag = "4")] + pub is_wpa3_supported: bool, + #[noproto(tag = "5")] + pub listen_interval: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespConnectAp { + #[noproto(tag = "1")] + pub resp: u32, + #[noproto(tag = "2")] + pub mac: String<32>, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqGetSoftApConfig {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespGetSoftApConfig { + #[noproto(tag = "1")] + pub ssid: String<32>, + #[noproto(tag = "2")] + pub pwd: String<32>, + #[noproto(tag = "3")] + pub chnl: u32, + #[noproto(tag = "4")] + pub sec_prot: CtrlWifiSecProt, + #[noproto(tag = "5")] + pub max_conn: u32, + #[noproto(tag = "6")] + pub ssid_hidden: bool, + #[noproto(tag = "7")] + pub bw: u32, + #[noproto(tag = "8")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqStartSoftAp { + #[noproto(tag = "1")] + pub ssid: String<32>, + #[noproto(tag = "2")] + pub pwd: String<32>, + #[noproto(tag = "3")] + pub chnl: u32, + #[noproto(tag = "4")] + pub sec_prot: CtrlWifiSecProt, + #[noproto(tag = "5")] + pub max_conn: u32, + #[noproto(tag = "6")] + pub ssid_hidden: bool, + #[noproto(tag = "7")] + pub bw: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespStartSoftAp { + #[noproto(tag = "1")] + pub resp: u32, + #[noproto(tag = "2")] + pub mac: String<32>, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqScanResult {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespScanResult { + #[noproto(tag = "1")] + pub count: u32, + #[noproto(repeated, tag = "2")] + pub entries: Vec, + #[noproto(tag = "3")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqSoftApConnectedSta {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespSoftApConnectedSta { + #[noproto(tag = "1")] + pub num: u32, + #[noproto(repeated, tag = "2")] + pub stations: Vec, + #[noproto(tag = "3")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqOtaBegin {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespOtaBegin { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqOtaWrite { + #[noproto(tag = "1")] + pub ota_data: Vec, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespOtaWrite { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqOtaEnd {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespOtaEnd { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqVendorIeData { + #[noproto(tag = "1")] + pub element_id: u32, + #[noproto(tag = "2")] + pub length: u32, + #[noproto(tag = "3")] + pub vendor_oui: Vec, + #[noproto(tag = "4")] + pub vendor_oui_type: u32, + #[noproto(tag = "5")] + pub payload: Vec, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqSetSoftApVendorSpecificIe { + #[noproto(tag = "1")] + pub enable: bool, + #[noproto(tag = "2")] + pub r#type: CtrlVendorIeType, + #[noproto(tag = "3")] + pub idx: CtrlVendorIeid, + #[noproto(optional, tag = "4")] + pub vendor_ie_data: Option, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespSetSoftApVendorSpecificIe { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqSetWifiMaxTxPower { + #[noproto(tag = "1")] + pub wifi_max_tx_power: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespSetWifiMaxTxPower { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqGetWifiCurrTxPower {} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespGetWifiCurrTxPower { + #[noproto(tag = "1")] + pub wifi_curr_tx_power: u32, + #[noproto(tag = "2")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgReqConfigHeartbeat { + #[noproto(tag = "1")] + pub enable: bool, + #[noproto(tag = "2")] + pub duration: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgRespConfigHeartbeat { + #[noproto(tag = "1")] + pub resp: u32, +} +/// * Event structure * + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgEventEspInit { + #[noproto(tag = "1")] + pub init_data: Vec, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgEventHeartbeat { + #[noproto(tag = "1")] + pub hb_num: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgEventStationDisconnectFromAp { + #[noproto(tag = "1")] + pub resp: u32, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { + #[noproto(tag = "1")] + pub resp: u32, + #[noproto(tag = "2")] + pub mac: String<32>, +} + +#[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +pub struct CtrlMsg { + /// msg_type could be req, resp or Event + #[noproto(tag = "1")] + pub msg_type: CtrlMsgType, + /// msg id + #[noproto(tag = "2")] + pub msg_id: CtrlMsgId, + /// union of all msg ids + #[noproto( + oneof, + tags = "101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 301, 302, 303, 304" + )] + pub payload: Option, +} + +/// union of all msg ids +#[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)] +pub enum CtrlMsgPayload { + /// * Requests * + #[noproto(tag = "101")] + ReqGetMacAddress(CtrlMsgReqGetMacAddress), + #[noproto(tag = "102")] + ReqSetMacAddress(CtrlMsgReqSetMacAddress), + #[noproto(tag = "103")] + ReqGetWifiMode(CtrlMsgReqGetMode), + #[noproto(tag = "104")] + ReqSetWifiMode(CtrlMsgReqSetMode), + #[noproto(tag = "105")] + ReqScanApList(CtrlMsgReqScanResult), + #[noproto(tag = "106")] + ReqGetApConfig(CtrlMsgReqGetApConfig), + #[noproto(tag = "107")] + ReqConnectAp(CtrlMsgReqConnectAp), + #[noproto(tag = "108")] + ReqDisconnectAp(CtrlMsgReqGetStatus), + #[noproto(tag = "109")] + ReqGetSoftapConfig(CtrlMsgReqGetSoftApConfig), + #[noproto(tag = "110")] + ReqSetSoftapVendorSpecificIe(CtrlMsgReqSetSoftApVendorSpecificIe), + #[noproto(tag = "111")] + ReqStartSoftap(CtrlMsgReqStartSoftAp), + #[noproto(tag = "112")] + ReqSoftapConnectedStasList(CtrlMsgReqSoftApConnectedSta), + #[noproto(tag = "113")] + ReqStopSoftap(CtrlMsgReqGetStatus), + #[noproto(tag = "114")] + ReqSetPowerSaveMode(CtrlMsgReqSetMode), + #[noproto(tag = "115")] + ReqGetPowerSaveMode(CtrlMsgReqGetMode), + #[noproto(tag = "116")] + ReqOtaBegin(CtrlMsgReqOtaBegin), + #[noproto(tag = "117")] + ReqOtaWrite(CtrlMsgReqOtaWrite), + #[noproto(tag = "118")] + ReqOtaEnd(CtrlMsgReqOtaEnd), + #[noproto(tag = "119")] + ReqSetWifiMaxTxPower(CtrlMsgReqSetWifiMaxTxPower), + #[noproto(tag = "120")] + ReqGetWifiCurrTxPower(CtrlMsgReqGetWifiCurrTxPower), + #[noproto(tag = "121")] + ReqConfigHeartbeat(CtrlMsgReqConfigHeartbeat), + /// * Responses * + #[noproto(tag = "201")] + RespGetMacAddress(CtrlMsgRespGetMacAddress), + #[noproto(tag = "202")] + RespSetMacAddress(CtrlMsgRespSetMacAddress), + #[noproto(tag = "203")] + RespGetWifiMode(CtrlMsgRespGetMode), + #[noproto(tag = "204")] + RespSetWifiMode(CtrlMsgRespSetMode), + #[noproto(tag = "205")] + RespScanApList(CtrlMsgRespScanResult), + #[noproto(tag = "206")] + RespGetApConfig(CtrlMsgRespGetApConfig), + #[noproto(tag = "207")] + RespConnectAp(CtrlMsgRespConnectAp), + #[noproto(tag = "208")] + RespDisconnectAp(CtrlMsgRespGetStatus), + #[noproto(tag = "209")] + RespGetSoftapConfig(CtrlMsgRespGetSoftApConfig), + #[noproto(tag = "210")] + RespSetSoftapVendorSpecificIe(CtrlMsgRespSetSoftApVendorSpecificIe), + #[noproto(tag = "211")] + RespStartSoftap(CtrlMsgRespStartSoftAp), + #[noproto(tag = "212")] + RespSoftapConnectedStasList(CtrlMsgRespSoftApConnectedSta), + #[noproto(tag = "213")] + RespStopSoftap(CtrlMsgRespGetStatus), + #[noproto(tag = "214")] + RespSetPowerSaveMode(CtrlMsgRespSetMode), + #[noproto(tag = "215")] + RespGetPowerSaveMode(CtrlMsgRespGetMode), + #[noproto(tag = "216")] + RespOtaBegin(CtrlMsgRespOtaBegin), + #[noproto(tag = "217")] + RespOtaWrite(CtrlMsgRespOtaWrite), + #[noproto(tag = "218")] + RespOtaEnd(CtrlMsgRespOtaEnd), + #[noproto(tag = "219")] + RespSetWifiMaxTxPower(CtrlMsgRespSetWifiMaxTxPower), + #[noproto(tag = "220")] + RespGetWifiCurrTxPower(CtrlMsgRespGetWifiCurrTxPower), + #[noproto(tag = "221")] + RespConfigHeartbeat(CtrlMsgRespConfigHeartbeat), + /// * Notifications * + #[noproto(tag = "301")] + EventEspInit(CtrlMsgEventEspInit), + #[noproto(tag = "302")] + EventHeartbeat(CtrlMsgEventHeartbeat), + #[noproto(tag = "303")] + EventStationDisconnectFromAp(CtrlMsgEventStationDisconnectFromAp), + #[noproto(tag = "304")] + EventStationDisconnectFromEspSoftAp(CtrlMsgEventStationDisconnectFromEspSoftAp), +} + +/// Enums similar to ESP IDF +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlVendorIeType { + #[default] + Beacon = 0, + ProbeReq = 1, + ProbeResp = 2, + AssocReq = 3, + AssocResp = 4, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlVendorIeid { + #[default] + Id0 = 0, + Id1 = 1, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlWifiMode { + #[default] + None = 0, + Sta = 1, + Ap = 2, + Apsta = 3, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlWifiBw { + #[default] + BwInvalid = 0, + Ht20 = 1, + Ht40 = 2, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlWifiPowerSave { + #[default] + PsInvalid = 0, + MinModem = 1, + MaxModem = 2, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlWifiSecProt { + #[default] + Open = 0, + Wep = 1, + WpaPsk = 2, + Wpa2Psk = 3, + WpaWpa2Psk = 4, + Wpa2Enterprise = 5, + Wpa3Psk = 6, + Wpa2Wpa3Psk = 7, +} + +/// enums for Control path +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlStatus { + #[default] + Connected = 0, + NotConnected = 1, + NoApFound = 2, + ConnectionFail = 3, + InvalidArgument = 4, + OutOfRange = 5, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlMsgType { + #[default] + MsgTypeInvalid = 0, + Req = 1, + Resp = 2, + Event = 3, + MsgTypeMax = 4, +} + +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] +#[repr(u32)] +pub enum CtrlMsgId { + #[default] + MsgIdInvalid = 0, + /// * Request Msgs * + ReqBase = 100, + ReqGetMacAddress = 101, + ReqSetMacAddress = 102, + ReqGetWifiMode = 103, + ReqSetWifiMode = 104, + ReqGetApScanList = 105, + ReqGetApConfig = 106, + ReqConnectAp = 107, + ReqDisconnectAp = 108, + ReqGetSoftApConfig = 109, + ReqSetSoftApVendorSpecificIe = 110, + ReqStartSoftAp = 111, + ReqGetSoftApConnectedStaList = 112, + ReqStopSoftAp = 113, + ReqSetPowerSaveMode = 114, + ReqGetPowerSaveMode = 115, + ReqOtaBegin = 116, + ReqOtaWrite = 117, + ReqOtaEnd = 118, + ReqSetWifiMaxTxPower = 119, + ReqGetWifiCurrTxPower = 120, + ReqConfigHeartbeat = 121, + /// Add new control path command response before Req_Max + /// and update Req_Max + ReqMax = 122, + /// * Response Msgs * + RespBase = 200, + RespGetMacAddress = 201, + RespSetMacAddress = 202, + RespGetWifiMode = 203, + RespSetWifiMode = 204, + RespGetApScanList = 205, + RespGetApConfig = 206, + RespConnectAp = 207, + RespDisconnectAp = 208, + RespGetSoftApConfig = 209, + RespSetSoftApVendorSpecificIe = 210, + RespStartSoftAp = 211, + RespGetSoftApConnectedStaList = 212, + RespStopSoftAp = 213, + RespSetPowerSaveMode = 214, + RespGetPowerSaveMode = 215, + RespOtaBegin = 216, + RespOtaWrite = 217, + RespOtaEnd = 218, + RespSetWifiMaxTxPower = 219, + RespGetWifiCurrTxPower = 220, + RespConfigHeartbeat = 221, + /// Add new control path command response before Resp_Max + /// and update Resp_Max + RespMax = 222, + /// * Event Msgs * + EventBase = 300, + EventEspInit = 301, + EventHeartbeat = 302, + EventStationDisconnectFromAp = 303, + EventStationDisconnectFromEspSoftAp = 304, + /// Add new control path command notification before Event_Max + /// and update Event_Max + EventMax = 305, +} diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 6627b7861..7c9d48bad 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -22,6 +22,7 @@ embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["ti lora-phy = { version = "1", optional = true } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } +embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } defmt = "0.3" defmt-rtt = "0.4" @@ -35,3 +36,4 @@ rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.0" usbd-hid = "0.6.0" serde = { version = "1.0.136", default-features = false } +embedded-hal-async = "0.2.0-alpha.1" diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs new file mode 100644 index 000000000..401dbd33c --- /dev/null +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -0,0 +1,143 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::{info, unwrap, warn}; +use embassy_executor::Spawner; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Stack, StackResources}; +use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; +use embassy_nrf::rng::Rng; +use embassy_nrf::spim::{self, Spim}; +use embassy_nrf::{bind_interrupts, peripherals}; +use embassy_time::{Duration, Timer}; +use embedded_hal_async::spi::ExclusiveDevice; +use embedded_io::asynch::Write; +use static_cell::make_static; +use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; + +bind_interrupts!(struct Irqs { + SPIM3 => spim::InterruptHandler; + RNG => embassy_nrf::rng::InterruptHandler; +}); + +#[embassy_executor::task] +async fn wifi_task( + runner: hosted::Runner< + 'static, + ExclusiveDevice, Output<'static, peripherals::P0_31>>, + Input<'static, AnyPin>, + Output<'static, peripherals::P1_03>, + >, +) -> ! { + runner.run().await +} + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack>) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Hello World!"); + + let p = embassy_nrf::init(Default::default()); + + let miso = p.P0_28; + let sck = p.P0_29; + let mosi = p.P0_30; + let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); + let handshake = Input::new(p.P1_01.degrade(), Pull::Up); + let ready = Input::new(p.P1_02.degrade(), Pull::None); + let reset = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); + + let mut config = spim::Config::default(); + config.frequency = spim::Frequency::M1; + config.mode = spim::MODE_2; // !!! + let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); + let spi = ExclusiveDevice::new(spi, cs); + + let (device, mut control, runner) = embassy_net_esp_hosted::new( + make_static!(embassy_net_esp_hosted::State::new()), + spi, + handshake, + ready, + reset, + ) + .await; + + unwrap!(spawner.spawn(wifi_task(runner))); + + // TODO: wait for ESP_INIT event instead of hardcoding delay. + Timer::after(Duration::from_secs(3)).await; + + control.init().await; + control.join(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await; + + let config = embassy_net::Config::dhcpv4(Default::default()); + // let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { + // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + // }); + + // Generate random seed + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.blocking_fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + config, + make_static!(StackResources::<2>::new()), + seed + )); + + unwrap!(spawner.spawn(net_task(stack))); + + // And now we can use it! + + let mut rx_buffer = [0; 4096]; + let mut tx_buffer = [0; 4096]; + let mut buf = [0; 4096]; + + loop { + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(embassy_time::Duration::from_secs(10))); + + info!("Listening on TCP:1234..."); + if let Err(e) = socket.accept(1234).await { + warn!("accept error: {:?}", e); + continue; + } + + info!("Received connection from {:?}", socket.remote_endpoint()); + + loop { + let n = match socket.read(&mut buf).await { + Ok(0) => { + warn!("read EOF"); + break; + } + Ok(n) => n, + Err(e) => { + warn!("read error: {:?}", e); + break; + } + }; + + info!("rxd {:02x}", &buf[..n]); + + match socket.write_all(&buf[..n]).await { + Ok(()) => {} + Err(e) => { + warn!("write error: {:?}", e); + break; + } + }; + } + } +} From ec2c095a76a0f55a031093e98a5283cff0daa576 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Jun 2023 18:13:19 +0200 Subject: [PATCH 15/74] esp-hosted: print events. --- embassy-net-esp-hosted/src/control.rs | 7 +++- embassy-net-esp-hosted/src/ioctl.rs | 4 +- embassy-net-esp-hosted/src/lib.rs | 36 ++++++++++++++---- embassy-net-esp-hosted/src/proto.rs | 54 +++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 11 deletions(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index 2381c6b84..ec51933b3 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -112,6 +112,8 @@ impl<'a> Control<'a> { } async fn ioctl(&mut self, req: CtrlMsg) -> CtrlMsg { + debug!("ioctl req: {:?}", &req); + let mut buf = [0u8; 128]; let req_len = noproto::write(&req, &mut buf).unwrap(); @@ -136,6 +138,9 @@ impl<'a> Control<'a> { ioctl.defuse(); - noproto::read(&buf[..resp_len]).unwrap() + let res = noproto::read(&buf[..resp_len]).unwrap(); + debug!("ioctl resp: {:?}", &res); + + res } } diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index 59bdabf37..689dd2a88 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -94,7 +94,7 @@ impl IoctlState { } pub async fn do_ioctl(&self, buf: &mut [u8], req_len: usize) -> usize { - debug!("IOCTL Request: {:02x}", Bytes(&buf[..req_len])); + trace!("ioctl req bytes: {:02x}", Bytes(&buf[..req_len])); self.state.set(IoctlStateInner::Pending(PendingIoctl { buf, req_len })); self.wake_runner(); @@ -103,7 +103,7 @@ impl IoctlState { pub fn ioctl_done(&self, response: &[u8]) { if let IoctlStateInner::Sent { buf } = self.state.get() { - debug!("IOCTL Response: {:02x}", Bytes(response)); + trace!("ioctl resp bytes: {:02x}", Bytes(response)); // TODO fix this (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index 2cf05a7df..084009966 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -8,6 +8,7 @@ use embedded_hal::digital::{InputPin, OutputPin}; use embedded_hal_async::digital::Wait; use embedded_hal_async::spi::SpiDevice; use ioctl::IoctlState; +use proto::CtrlMsg; use crate::ioctl::PendingIoctl; @@ -194,8 +195,6 @@ where tx_buf[0..12].copy_from_slice(&header.to_bytes()); header.checksum = checksum(&tx_buf[..26 + req_len]); tx_buf[0..12].copy_from_slice(&header.to_bytes()); - - debug!("====== SENDING IOCTL"); } Either3::Second(packet) => { tx_buf[12..][..packet.len()].copy_from_slice(packet); @@ -270,25 +269,46 @@ where }, // serial 2 => { - debug!("serial rx: {:02x}", payload); + trace!("serial rx: {:02x}", payload); if payload.len() < 14 { warn!("serial rx: too short"); return; } - if &payload[..12] != b"\x01\x08\x00ctrlResp\x02" { - warn!("serial rx: bad tlv"); - return; - } + + let isEvent = match &payload[..12] { + b"\x01\x08\x00ctrlResp\x02" => false, + b"\x01\x08\x00ctrlEvnt\x02" => true, + _ => { + warn!("serial rx: bad tlv"); + return; + } + }; + let len = u16::from_le_bytes(payload[12..14].try_into().unwrap()) as usize; if payload.len() < 14 + len { warn!("serial rx: too short 2"); return; } - self.ioctl_state.ioctl_done(&payload[14..][..len]); + let data = &payload[14..][..len]; + + if isEvent { + self.handle_event(data); + } else { + self.ioctl_state.ioctl_done(data); + } } _ => warn!("unknown iftype {}", if_type_and_num), } } + + fn handle_event(&self, data: &[u8]) { + let Ok(event) = noproto::read::(data) else { + warn!("failed to parse event"); + return + }; + + debug!("event: {:?}", &event); + } } fn checksum(buf: &[u8]) -> u16 { diff --git a/embassy-net-esp-hosted/src/proto.rs b/embassy-net-esp-hosted/src/proto.rs index e105e393c..8ceb1579d 100644 --- a/embassy-net-esp-hosted/src/proto.rs +++ b/embassy-net-esp-hosted/src/proto.rs @@ -3,6 +3,7 @@ use heapless::{String, Vec}; /// internal supporting structures for CtrlMsg #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ScanResult { #[noproto(tag = "1")] pub ssid: String<32>, @@ -17,6 +18,7 @@ pub struct ScanResult { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct ConnectedStaList { #[noproto(tag = "1")] pub mac: String<32>, @@ -26,12 +28,14 @@ pub struct ConnectedStaList { /// * Req/Resp structure * #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqGetMacAddress { #[noproto(tag = "1")] pub mode: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespGetMacAddress { #[noproto(tag = "1")] pub mac: String<32>, @@ -40,9 +44,11 @@ pub struct CtrlMsgRespGetMacAddress { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqGetMode {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespGetMode { #[noproto(tag = "1")] pub mode: u32, @@ -51,27 +57,32 @@ pub struct CtrlMsgRespGetMode { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqSetMode { #[noproto(tag = "1")] pub mode: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespSetMode { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqGetStatus {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespGetStatus { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqSetMacAddress { #[noproto(tag = "1")] pub mac: String<32>, @@ -80,15 +91,18 @@ pub struct CtrlMsgReqSetMacAddress { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespSetMacAddress { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqGetApConfig {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespGetApConfig { #[noproto(tag = "1")] pub ssid: String<32>, @@ -105,6 +119,7 @@ pub struct CtrlMsgRespGetApConfig { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqConnectAp { #[noproto(tag = "1")] pub ssid: String<32>, @@ -119,6 +134,7 @@ pub struct CtrlMsgReqConnectAp { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespConnectAp { #[noproto(tag = "1")] pub resp: u32, @@ -127,9 +143,11 @@ pub struct CtrlMsgRespConnectAp { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqGetSoftApConfig {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespGetSoftApConfig { #[noproto(tag = "1")] pub ssid: String<32>, @@ -150,6 +168,7 @@ pub struct CtrlMsgRespGetSoftApConfig { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqStartSoftAp { #[noproto(tag = "1")] pub ssid: String<32>, @@ -168,6 +187,7 @@ pub struct CtrlMsgReqStartSoftAp { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespStartSoftAp { #[noproto(tag = "1")] pub resp: u32, @@ -176,9 +196,11 @@ pub struct CtrlMsgRespStartSoftAp { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqScanResult {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespScanResult { #[noproto(tag = "1")] pub count: u32, @@ -189,9 +211,11 @@ pub struct CtrlMsgRespScanResult { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqSoftApConnectedSta {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespSoftApConnectedSta { #[noproto(tag = "1")] pub num: u32, @@ -202,36 +226,43 @@ pub struct CtrlMsgRespSoftApConnectedSta { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqOtaBegin {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespOtaBegin { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqOtaWrite { #[noproto(tag = "1")] pub ota_data: Vec, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespOtaWrite { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqOtaEnd {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespOtaEnd { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqVendorIeData { #[noproto(tag = "1")] pub element_id: u32, @@ -246,6 +277,7 @@ pub struct CtrlMsgReqVendorIeData { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqSetSoftApVendorSpecificIe { #[noproto(tag = "1")] pub enable: bool, @@ -258,27 +290,32 @@ pub struct CtrlMsgReqSetSoftApVendorSpecificIe { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespSetSoftApVendorSpecificIe { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqSetWifiMaxTxPower { #[noproto(tag = "1")] pub wifi_max_tx_power: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespSetWifiMaxTxPower { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqGetWifiCurrTxPower {} #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespGetWifiCurrTxPower { #[noproto(tag = "1")] pub wifi_curr_tx_power: u32, @@ -287,6 +324,7 @@ pub struct CtrlMsgRespGetWifiCurrTxPower { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgReqConfigHeartbeat { #[noproto(tag = "1")] pub enable: bool, @@ -295,6 +333,7 @@ pub struct CtrlMsgReqConfigHeartbeat { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgRespConfigHeartbeat { #[noproto(tag = "1")] pub resp: u32, @@ -302,24 +341,28 @@ pub struct CtrlMsgRespConfigHeartbeat { /// * Event structure * #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgEventEspInit { #[noproto(tag = "1")] pub init_data: Vec, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgEventHeartbeat { #[noproto(tag = "1")] pub hb_num: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgEventStationDisconnectFromAp { #[noproto(tag = "1")] pub resp: u32, } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { #[noproto(tag = "1")] pub resp: u32, @@ -328,6 +371,7 @@ pub struct CtrlMsgEventStationDisconnectFromEspSoftAp { } #[derive(Debug, Default, Clone, Eq, PartialEq, noproto::Message)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct CtrlMsg { /// msg_type could be req, resp or Event #[noproto(tag = "1")] @@ -345,6 +389,7 @@ pub struct CtrlMsg { /// union of all msg ids #[derive(Debug, Clone, Eq, PartialEq, noproto::Oneof)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlMsgPayload { /// * Requests * #[noproto(tag = "101")] @@ -446,6 +491,7 @@ pub enum CtrlMsgPayload { /// Enums similar to ESP IDF #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlVendorIeType { #[default] Beacon = 0, @@ -457,6 +503,7 @@ pub enum CtrlVendorIeType { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlVendorIeid { #[default] Id0 = 0, @@ -465,6 +512,7 @@ pub enum CtrlVendorIeid { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlWifiMode { #[default] None = 0, @@ -475,6 +523,7 @@ pub enum CtrlWifiMode { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlWifiBw { #[default] BwInvalid = 0, @@ -484,6 +533,7 @@ pub enum CtrlWifiBw { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlWifiPowerSave { #[default] PsInvalid = 0, @@ -493,6 +543,7 @@ pub enum CtrlWifiPowerSave { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlWifiSecProt { #[default] Open = 0, @@ -508,6 +559,7 @@ pub enum CtrlWifiSecProt { /// enums for Control path #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlStatus { #[default] Connected = 0, @@ -520,6 +572,7 @@ pub enum CtrlStatus { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlMsgType { #[default] MsgTypeInvalid = 0, @@ -531,6 +584,7 @@ pub enum CtrlMsgType { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord, noproto::Enumeration)] #[repr(u32)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum CtrlMsgId { #[default] MsgIdInvalid = 0, From 082f1ab494587e02d405cad8f186d48943acf16d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Jun 2023 18:55:29 +0200 Subject: [PATCH 16/74] esp-hosted: nicer names for shared state struct. --- embassy-net-esp-hosted/src/control.rs | 16 ++--- embassy-net-esp-hosted/src/ioctl.rs | 93 +++++++++++---------------- embassy-net-esp-hosted/src/lib.rs | 16 ++--- 3 files changed, 53 insertions(+), 72 deletions(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index ec51933b3..c98d0ebf4 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -3,7 +3,7 @@ use defmt::Debug2Format; use embassy_net_driver_channel as ch; use heapless::String; -use crate::ioctl::IoctlState; +use crate::ioctl::Shared; use crate::proto::{self, CtrlMsg}; #[derive(Debug)] @@ -13,7 +13,7 @@ pub struct Error { pub struct Control<'a> { state_ch: ch::StateRunner<'a>, - ioctl_state: &'a IoctlState, + shared: &'a Shared, } enum WifiMode { @@ -24,8 +24,8 @@ enum WifiMode { } impl<'a> Control<'a> { - pub(crate) fn new(state_ch: ch::StateRunner<'a>, ioctl_state: &'a IoctlState) -> Self { - Self { state_ch, ioctl_state } + pub(crate) fn new(state_ch: ch::StateRunner<'a>, shared: &'a Shared) -> Self { + Self { state_ch, shared } } pub async fn init(&mut self) { @@ -118,7 +118,7 @@ impl<'a> Control<'a> { let req_len = noproto::write(&req, &mut buf).unwrap(); - struct CancelOnDrop<'a>(&'a IoctlState); + struct CancelOnDrop<'a>(&'a Shared); impl CancelOnDrop<'_> { fn defuse(self) { @@ -128,13 +128,13 @@ impl<'a> Control<'a> { impl Drop for CancelOnDrop<'_> { fn drop(&mut self) { - self.0.cancel_ioctl(); + self.0.ioctl_cancel(); } } - let ioctl = CancelOnDrop(self.ioctl_state); + let ioctl = CancelOnDrop(self.shared); - let resp_len = ioctl.0.do_ioctl(&mut buf, req_len).await; + let resp_len = ioctl.0.ioctl(&mut buf, req_len).await; ioctl.defuse(); diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index 689dd2a88..7cbe80b2a 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -13,105 +13,86 @@ pub struct PendingIoctl { } #[derive(Clone, Copy)] -enum IoctlStateInner { +enum IoctlState { Pending(PendingIoctl), Sent { buf: *mut [u8] }, Done { resp_len: usize }, } -struct Wakers { - control: WakerRegistration, - runner: WakerRegistration, +pub struct Shared(RefCell); + +struct SharedInner { + ioctl: IoctlState, + control_waker: WakerRegistration, + runner_waker: WakerRegistration, } -impl Default for Wakers { - fn default() -> Self { - Self { - control: WakerRegistration::new(), - runner: WakerRegistration::new(), - } - } -} - -pub struct IoctlState { - state: Cell, - wakers: RefCell, -} - -impl IoctlState { +impl Shared { pub fn new() -> Self { - Self { - state: Cell::new(IoctlStateInner::Done { resp_len: 0 }), - wakers: Default::default(), - } + Self(RefCell::new(SharedInner { + ioctl: IoctlState::Done { resp_len: 0 }, + control_waker: WakerRegistration::new(), + runner_waker: WakerRegistration::new(), + })) } - fn wake_control(&self) { - self.wakers.borrow_mut().control.wake(); - } - - fn register_control(&self, waker: &Waker) { - self.wakers.borrow_mut().control.register(waker); - } - - fn wake_runner(&self) { - self.wakers.borrow_mut().runner.wake(); - } - - fn register_runner(&self, waker: &Waker) { - self.wakers.borrow_mut().runner.register(waker); - } - - pub async fn wait_complete(&self) -> usize { + pub async fn ioctl_wait_complete(&self) -> usize { poll_fn(|cx| { - if let IoctlStateInner::Done { resp_len } = self.state.get() { + let mut this = self.0.borrow_mut(); + if let IoctlState::Done { resp_len } = this.ioctl { Poll::Ready(resp_len) } else { - self.register_control(cx.waker()); + this.control_waker.register(cx.waker()); Poll::Pending } }) .await } - pub async fn wait_pending(&self) -> PendingIoctl { + pub async fn ioctl_wait_pending(&self) -> PendingIoctl { let pending = poll_fn(|cx| { - if let IoctlStateInner::Pending(pending) = self.state.get() { + let mut this = self.0.borrow_mut(); + if let IoctlState::Pending(pending) = this.ioctl { Poll::Ready(pending) } else { - self.register_runner(cx.waker()); + this.runner_waker.register(cx.waker()); Poll::Pending } }) .await; - self.state.set(IoctlStateInner::Sent { buf: pending.buf }); + self.0.borrow_mut().ioctl = IoctlState::Sent { buf: pending.buf }; pending } - pub fn cancel_ioctl(&self) { - self.state.set(IoctlStateInner::Done { resp_len: 0 }); + pub fn ioctl_cancel(&self) { + self.0.borrow_mut().ioctl = IoctlState::Done { resp_len: 0 }; } - pub async fn do_ioctl(&self, buf: &mut [u8], req_len: usize) -> usize { + pub async fn ioctl(&self, buf: &mut [u8], req_len: usize) -> usize { trace!("ioctl req bytes: {:02x}", Bytes(&buf[..req_len])); - self.state.set(IoctlStateInner::Pending(PendingIoctl { buf, req_len })); - self.wake_runner(); - self.wait_complete().await + { + let mut this = self.0.borrow_mut(); + this.ioctl = IoctlState::Pending(PendingIoctl { buf, req_len }); + this.runner_waker.wake(); + } + + self.ioctl_wait_complete().await } pub fn ioctl_done(&self, response: &[u8]) { - if let IoctlStateInner::Sent { buf } = self.state.get() { + let mut this = self.0.borrow_mut(); + if let IoctlState::Sent { buf } = this.ioctl { trace!("ioctl resp bytes: {:02x}", Bytes(response)); // TODO fix this (unsafe { &mut *buf }[..response.len()]).copy_from_slice(response); - self.state.set(IoctlStateInner::Done { + this.ioctl = IoctlState::Done { resp_len: response.len(), - }); - self.wake_control(); + }; + this.control_waker.wake(); } else { warn!("IOCTL Response but no pending Ioctl"); } diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index 084009966..700a5221c 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -7,7 +7,7 @@ use embassy_time::{Duration, Instant, Timer}; use embedded_hal::digital::{InputPin, OutputPin}; use embedded_hal_async::digital::Wait; use embedded_hal_async::spi::SpiDevice; -use ioctl::IoctlState; +use ioctl::Shared; use proto::CtrlMsg; use crate::ioctl::PendingIoctl; @@ -95,14 +95,14 @@ enum InterfaceType { const MAX_SPI_BUFFER_SIZE: usize = 1600; pub struct State { - ioctl_state: IoctlState, + shared: Shared, ch: ch::State, } impl State { pub fn new() -> Self { Self { - ioctl_state: IoctlState::new(), + shared: Shared::new(), ch: ch::State::new(), } } @@ -127,7 +127,7 @@ where let mut runner = Runner { ch: ch_runner, - ioctl_state: &state.ioctl_state, + shared: &state.shared, next_seq: 1, handshake, ready, @@ -136,12 +136,12 @@ where }; runner.init().await; - (device, Control::new(state_ch, &state.ioctl_state), runner) + (device, Control::new(state_ch, &state.shared), runner) } pub struct Runner<'a, SPI, IN, OUT> { ch: ch::Runner<'a, MTU>, - ioctl_state: &'a IoctlState, + shared: &'a Shared, next_seq: u16, @@ -172,7 +172,7 @@ where loop { self.handshake.wait_for_high().await.unwrap(); - let ioctl = self.ioctl_state.wait_pending(); + let ioctl = self.shared.ioctl_wait_pending(); let tx = self.ch.tx_buf(); let ev = async { self.ready.wait_for_high().await.unwrap() }; @@ -294,7 +294,7 @@ where if isEvent { self.handle_event(data); } else { - self.ioctl_state.ioctl_done(data); + self.shared.ioctl_done(data); } } _ => warn!("unknown iftype {}", if_type_and_num), From 764b43e82c7b61c21621c1fd9f5fd2f6a3dc419c Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Jun 2023 19:05:20 +0200 Subject: [PATCH 17/74] esp-hosted: wait for esp firmware init. --- embassy-net-esp-hosted/src/control.rs | 3 +++ embassy-net-esp-hosted/src/ioctl.rs | 23 ++++++++++++++++++++ embassy-net-esp-hosted/src/lib.rs | 11 ++++++++++ examples/nrf52840/src/bin/wifi_esp_hosted.rs | 3 --- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index c98d0ebf4..a2a65bc31 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -29,6 +29,9 @@ impl<'a> Control<'a> { } pub async fn init(&mut self) { + debug!("wait for init event..."); + self.shared.init_wait().await; + debug!("set wifi mode"); self.set_wifi_mode(WifiMode::Sta as _).await; let mac_addr = self.get_mac_addr().await; diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index 7cbe80b2a..607b7b627 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -23,6 +23,7 @@ pub struct Shared(RefCell); struct SharedInner { ioctl: IoctlState, + is_init: bool, control_waker: WakerRegistration, runner_waker: WakerRegistration, } @@ -31,6 +32,7 @@ impl Shared { pub fn new() -> Self { Self(RefCell::new(SharedInner { ioctl: IoctlState::Done { resp_len: 0 }, + is_init: false, control_waker: WakerRegistration::new(), runner_waker: WakerRegistration::new(), })) @@ -97,4 +99,25 @@ impl Shared { warn!("IOCTL Response but no pending Ioctl"); } } + + // // // // // // // // // // // // // // // // // // // // + + pub fn init_done(&self) { + let mut this = self.0.borrow_mut(); + this.is_init = true; + this.control_waker.wake(); + } + + pub async fn init_wait(&self) { + poll_fn(|cx| { + let mut this = self.0.borrow_mut(); + if this.is_init { + Poll::Ready(()) + } else { + this.control_waker.register(cx.waker()); + Poll::Pending + } + }) + .await + } } diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index 700a5221c..ff7bed2b7 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -11,6 +11,7 @@ use ioctl::Shared; use proto::CtrlMsg; use crate::ioctl::PendingIoctl; +use crate::proto::CtrlMsgPayload; mod proto; @@ -308,6 +309,16 @@ where }; debug!("event: {:?}", &event); + + let Some(payload) = &event.payload else { + warn!("event without payload?"); + return + }; + + match payload { + CtrlMsgPayload::EventEspInit(_) => self.shared.init_done(), + _ => {} + } } } diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index 401dbd33c..b75756f76 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -69,9 +69,6 @@ async fn main(spawner: Spawner) { unwrap!(spawner.spawn(wifi_task(runner))); - // TODO: wait for ESP_INIT event instead of hardcoding delay. - Timer::after(Duration::from_secs(3)).await; - control.init().await; control.join(env!("WIFI_NETWORK"), env!("WIFI_PASSWORD")).await; From 1ed909ea74bfff75bd91b35739a44c5128271571 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 21 Jun 2023 19:08:09 +0200 Subject: [PATCH 18/74] esp-hosted: fix warnings. --- embassy-net-esp-hosted/src/control.rs | 14 ++------------ embassy-net-esp-hosted/src/ioctl.rs | 4 ++-- embassy-net-esp-hosted/src/lib.rs | 5 +++-- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 1 - 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/embassy-net-esp-hosted/src/control.rs b/embassy-net-esp-hosted/src/control.rs index a2a65bc31..fce82ade7 100644 --- a/embassy-net-esp-hosted/src/control.rs +++ b/embassy-net-esp-hosted/src/control.rs @@ -16,6 +16,7 @@ pub struct Control<'a> { shared: &'a Shared, } +#[allow(unused)] enum WifiMode { None = 0, Sta = 1, @@ -34,6 +35,7 @@ impl<'a> Control<'a> { debug!("set wifi mode"); self.set_wifi_mode(WifiMode::Sta as _).await; + let mac_addr = self.get_mac_addr().await; debug!("mac addr: {:02x}", mac_addr); self.state_ch.set_ethernet_address(mac_addr); @@ -91,18 +93,6 @@ impl<'a> Control<'a> { res } - async fn get_wifi_mode(&mut self) -> u32 { - let req = proto::CtrlMsg { - msg_id: proto::CtrlMsgId::ReqGetWifiMode as _, - msg_type: proto::CtrlMsgType::Req as _, - payload: Some(proto::CtrlMsgPayload::ReqGetWifiMode(proto::CtrlMsgReqGetMode {})), - }; - let resp = self.ioctl(req).await; - let proto::CtrlMsgPayload::RespGetWifiMode(resp) = resp.payload.unwrap() else { panic!("unexpected resp") }; - assert_eq!(resp.resp, 0); - resp.mode - } - async fn set_wifi_mode(&mut self, mode: u32) { let req = proto::CtrlMsg { msg_id: proto::CtrlMsgId::ReqSetWifiMode as _, diff --git a/embassy-net-esp-hosted/src/ioctl.rs b/embassy-net-esp-hosted/src/ioctl.rs index 607b7b627..e2a6815aa 100644 --- a/embassy-net-esp-hosted/src/ioctl.rs +++ b/embassy-net-esp-hosted/src/ioctl.rs @@ -1,6 +1,6 @@ -use core::cell::{Cell, RefCell}; +use core::cell::RefCell; use core::future::poll_fn; -use core::task::{Poll, Waker}; +use core::task::Poll; use embassy_sync::waitqueue::WakerRegistration; diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index ff7bed2b7..2a4601ce4 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -83,6 +83,7 @@ struct PayloadHeader { } impl_bytes!(PayloadHeader); +#[allow(unused)] #[repr(u8)] enum InterfaceType { Sta = 0, @@ -276,7 +277,7 @@ where return; } - let isEvent = match &payload[..12] { + let is_event = match &payload[..12] { b"\x01\x08\x00ctrlResp\x02" => false, b"\x01\x08\x00ctrlEvnt\x02" => true, _ => { @@ -292,7 +293,7 @@ where } let data = &payload[14..][..len]; - if isEvent { + if is_event { self.handle_event(data); } else { self.shared.ioctl_done(data); diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index b75756f76..cea45c5c8 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -10,7 +10,6 @@ use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; use embassy_nrf::rng::Rng; use embassy_nrf::spim::{self, Spim}; use embassy_nrf::{bind_interrupts, peripherals}; -use embassy_time::{Duration, Timer}; use embedded_hal_async::spi::ExclusiveDevice; use embedded_io::asynch::Write; use static_cell::make_static; From 0d02298ea628b9d2154fd05db7975f62b8d12edb Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 22 Jun 2023 15:30:26 +0200 Subject: [PATCH 19/74] esp-hosted: fix build on stable. --- examples/nrf52840/Cargo.toml | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/examples/nrf52840/Cargo.toml b/examples/nrf52840/Cargo.toml index 7c9d48bad..8c4175966 100644 --- a/examples/nrf52840/Cargo.toml +++ b/examples/nrf52840/Cargo.toml @@ -6,8 +6,24 @@ license = "MIT OR Apache-2.0" [features] default = ["nightly"] -nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-net/nightly", "embassy-nrf/unstable-traits", "embassy-time/nightly", "embassy-time/unstable-traits", "static_cell/nightly", - "embassy-usb", "embedded-io/async", "embassy-net", "embassy-lora", "lora-phy", "lorawan-device", "lorawan"] +nightly = [ + "embedded-hal-async", + "embassy-executor/nightly", + "embassy-nrf/nightly", + "embassy-net/nightly", + "embassy-net-esp-hosted", + "embassy-nrf/unstable-traits", + "embassy-time/nightly", + "embassy-time/unstable-traits", + "static_cell/nightly", + "embassy-usb", + "embedded-io/async", + "embassy-net", + "embassy-lora", + "lora-phy", + "lorawan-device", + "lorawan", +] [dependencies] embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } @@ -22,7 +38,7 @@ embassy-lora = { version = "0.1.0", path = "../../embassy-lora", features = ["ti lora-phy = { version = "1", optional = true } lorawan-device = { version = "0.10.0", default-features = false, features = ["async", "external-lora-phy"], optional = true } lorawan = { version = "0.7.3", default-features = false, features = ["default-crypto"], optional = true } -embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } +embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"], optional = true } defmt = "0.3" defmt-rtt = "0.4" @@ -36,4 +52,4 @@ rand = { version = "0.8.4", default-features = false } embedded-storage = "0.3.0" usbd-hid = "0.6.0" serde = { version = "1.0.136", default-features = false } -embedded-hal-async = "0.2.0-alpha.1" +embedded-hal-async = { version = "0.2.0-alpha.1", optional = true } From 6e65282f185d94a8c449374e6d4ed4eefa5793a4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 22 Jun 2023 21:10:58 +0200 Subject: [PATCH 20/74] esp-hosted: smaller delay after transfer, makes slightly better perf. --- embassy-net-esp-hosted/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/embassy-net-esp-hosted/src/lib.rs b/embassy-net-esp-hosted/src/lib.rs index 2a4601ce4..44dfbe89c 100644 --- a/embassy-net-esp-hosted/src/lib.rs +++ b/embassy-net-esp-hosted/src/lib.rs @@ -227,7 +227,12 @@ where } self.spi.transfer(&mut rx_buf, &tx_buf).await.unwrap(); - let delay_until = Instant::now() + Duration::from_millis(1); + + // The esp-hosted firmware deasserts the HANSHAKE pin a few us AFTER ending the SPI transfer + // If we check it again too fast, we'll see it's high from the previous transfer, and if we send it + // data it will get lost. + // Make sure we check it after 100us at minimum. + let delay_until = Instant::now() + Duration::from_micros(100); self.handle_rx(&mut rx_buf); Timer::at(delay_until).await; } From 8bbfa6827cd68f67a50a89b13947542e632d5411 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 22 Jun 2023 21:11:53 +0200 Subject: [PATCH 21/74] esp-hosted: add perf hil test. --- ci.sh | 2 +- examples/nrf52840/src/bin/wifi_esp_hosted.rs | 8 +- tests/nrf/Cargo.toml | 4 + tests/nrf/src/bin/wifi_esp_hosted_perf.rs | 270 +++++++++++++++++++ tests/rp/src/bin/cyw43-perf.rs | 9 +- 5 files changed, 280 insertions(+), 13 deletions(-) create mode 100644 tests/nrf/src/bin/wifi_esp_hosted_perf.rs diff --git a/ci.sh b/ci.sh index 3fe1b1ce8..a03efb856 100755 --- a/ci.sh +++ b/ci.sh @@ -3,7 +3,7 @@ set -euo pipefail export RUSTFLAGS=-Dwarnings -export DEFMT_LOG=trace,cyw43=info,cyw43_pio=info,smoltcp=info +export DEFMT_LOG=trace,embassy_net_esp_hosted=debug,cyw43=info,cyw43_pio=info,smoltcp=info # needed by wifi examples export WIFI_NETWORK=x diff --git a/examples/nrf52840/src/bin/wifi_esp_hosted.rs b/examples/nrf52840/src/bin/wifi_esp_hosted.rs index cea45c5c8..4eb31b105 100644 --- a/examples/nrf52840/src/bin/wifi_esp_hosted.rs +++ b/examples/nrf52840/src/bin/wifi_esp_hosted.rs @@ -26,7 +26,7 @@ async fn wifi_task( 'static, ExclusiveDevice, Output<'static, peripherals::P0_31>>, Input<'static, AnyPin>, - Output<'static, peripherals::P1_03>, + Output<'static, peripherals::P1_05>, >, ) -> ! { runner.run().await @@ -48,11 +48,11 @@ async fn main(spawner: Spawner) { let mosi = p.P0_30; let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); let handshake = Input::new(p.P1_01.degrade(), Pull::Up); - let ready = Input::new(p.P1_02.degrade(), Pull::None); - let reset = Output::new(p.P1_03, Level::Low, OutputDrive::Standard); + let ready = Input::new(p.P1_04.degrade(), Pull::None); + let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); let mut config = spim::Config::default(); - config.frequency = spim::Frequency::M1; + config.frequency = spim::Frequency::M32; config.mode = spim::MODE_2; // !!! let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); let spi = ExclusiveDevice::new(spi, cs); diff --git a/tests/nrf/Cargo.toml b/tests/nrf/Cargo.toml index 9735c87d9..4f9ecc47a 100644 --- a/tests/nrf/Cargo.toml +++ b/tests/nrf/Cargo.toml @@ -13,6 +13,10 @@ embassy-executor = { version = "0.2.0", path = "../../embassy-executor", feature embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "nightly", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nightly", "unstable-traits", "nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] } embedded-io = { version = "0.4.0", features = ["async"] } +embassy-net = { version = "0.1.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "nightly"] } +embassy-net-esp-hosted = { version = "0.1.0", path = "../../embassy-net-esp-hosted", features = ["defmt"] } +embedded-hal-async = { version = "0.2.0-alpha.1" } +static_cell = { version = "1.1", features = [ "nightly" ] } defmt = "0.3" defmt-rtt = "0.4" diff --git a/tests/nrf/src/bin/wifi_esp_hosted_perf.rs b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs new file mode 100644 index 000000000..277b985c5 --- /dev/null +++ b/tests/nrf/src/bin/wifi_esp_hosted_perf.rs @@ -0,0 +1,270 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../common.rs"] +mod common; + +use defmt::{error, info, unwrap}; +use embassy_executor::Spawner; +use embassy_futures::join::join; +use embassy_net::tcp::TcpSocket; +use embassy_net::{Config, Ipv4Address, Stack, StackResources}; +use embassy_nrf::gpio::{AnyPin, Input, Level, Output, OutputDrive, Pin, Pull}; +use embassy_nrf::rng::Rng; +use embassy_nrf::spim::{self, Spim}; +use embassy_nrf::{bind_interrupts, peripherals}; +use embassy_time::{with_timeout, Duration, Timer}; +use embedded_hal_async::spi::ExclusiveDevice; +use static_cell::make_static; +use {defmt_rtt as _, embassy_net_esp_hosted as hosted, panic_probe as _}; + +teleprobe_meta::timeout!(120); + +bind_interrupts!(struct Irqs { + SPIM3 => spim::InterruptHandler; + RNG => embassy_nrf::rng::InterruptHandler; +}); + +#[embassy_executor::task] +async fn wifi_task( + runner: hosted::Runner< + 'static, + ExclusiveDevice, Output<'static, peripherals::P0_31>>, + Input<'static, AnyPin>, + Output<'static, peripherals::P1_05>, + >, +) -> ! { + runner.run().await +} + +type MyDriver = hosted::NetDriver<'static>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Hello World!"); + + let p = embassy_nrf::init(Default::default()); + + let miso = p.P0_28; + let sck = p.P0_29; + let mosi = p.P0_30; + let cs = Output::new(p.P0_31, Level::High, OutputDrive::HighDrive); + let handshake = Input::new(p.P1_01.degrade(), Pull::Up); + let ready = Input::new(p.P1_04.degrade(), Pull::None); + let reset = Output::new(p.P1_05, Level::Low, OutputDrive::Standard); + + let mut config = spim::Config::default(); + config.frequency = spim::Frequency::M32; + config.mode = spim::MODE_2; // !!! + let spi = spim::Spim::new(p.SPI3, Irqs, sck, miso, mosi, config); + let spi = ExclusiveDevice::new(spi, cs); + + let (device, mut control, runner) = embassy_net_esp_hosted::new( + make_static!(embassy_net_esp_hosted::State::new()), + spi, + handshake, + ready, + reset, + ) + .await; + + unwrap!(spawner.spawn(wifi_task(runner))); + + control.init().await; + control.join(WIFI_NETWORK, WIFI_PASSWORD).await; + + // Generate random seed + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.blocking_fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + // Init network stack + let stack = &*make_static!(Stack::new( + device, + Config::dhcpv4(Default::default()), + make_static!(StackResources::<2>::new()), + seed + )); + + unwrap!(spawner.spawn(net_task(stack))); + + info!("Waiting for DHCP up..."); + while stack.config_v4().is_none() { + Timer::after(Duration::from_millis(100)).await; + } + info!("IP addressing up!"); + + let down = test_download(stack).await; + let up = test_upload(stack).await; + let updown = test_upload_download(stack).await; + + assert!(down > TEST_EXPECTED_DOWNLOAD_KBPS); + assert!(up > TEST_EXPECTED_UPLOAD_KBPS); + assert!(updown > TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS); + + info!("Test OK"); + cortex_m::asm::bkpt(); +} + +// Test-only wifi network, no internet access! +const WIFI_NETWORK: &str = "EmbassyTest"; +const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; + +const TEST_DURATION: usize = 10; +const TEST_EXPECTED_DOWNLOAD_KBPS: usize = 150; +const TEST_EXPECTED_UPLOAD_KBPS: usize = 150; +const TEST_EXPECTED_UPLOAD_DOWNLOAD_KBPS: usize = 150; +const RX_BUFFER_SIZE: usize = 4096; +const TX_BUFFER_SIZE: usize = 4096; +const SERVER_ADDRESS: Ipv4Address = Ipv4Address::new(192, 168, 2, 2); +const DOWNLOAD_PORT: u16 = 4321; +const UPLOAD_PORT: u16 = 4322; +const UPLOAD_DOWNLOAD_PORT: u16 = 4323; + +async fn test_download(stack: &'static Stack) -> usize { + info!("Testing download..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, DOWNLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, DOWNLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let mut rx_buf = [0; 4096]; + let mut total: usize = 0; + with_timeout(Duration::from_secs(TEST_DURATION as _), async { + loop { + match socket.read(&mut rx_buf).await { + Ok(0) => { + error!("read EOF"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("read error: {:?}", e); + return 0; + } + } + } + }) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("download: {} kB/s", kbps); + kbps +} + +async fn test_upload(stack: &'static Stack) -> usize { + info!("Testing upload..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let buf = [0; 4096]; + let mut total: usize = 0; + with_timeout(Duration::from_secs(TEST_DURATION as _), async { + loop { + match socket.write(&buf).await { + Ok(0) => { + error!("write zero?!??!?!"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("write error: {:?}", e); + return 0; + } + } + } + }) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("upload: {} kB/s", kbps); + kbps +} + +async fn test_upload_download(stack: &'static Stack) -> usize { + info!("Testing upload+download..."); + + let mut rx_buffer = [0; RX_BUFFER_SIZE]; + let mut tx_buffer = [0; TX_BUFFER_SIZE]; + let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); + socket.set_timeout(Some(Duration::from_secs(10))); + + info!("connecting to {:?}:{}...", SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT); + if let Err(e) = socket.connect((SERVER_ADDRESS, UPLOAD_DOWNLOAD_PORT)).await { + error!("connect error: {:?}", e); + return 0; + } + info!("connected, testing..."); + + let (mut reader, mut writer) = socket.split(); + + let tx_buf = [0; 4096]; + let mut rx_buf = [0; 4096]; + let mut total: usize = 0; + let tx_fut = async { + loop { + match writer.write(&tx_buf).await { + Ok(0) => { + error!("write zero?!??!?!"); + return 0; + } + Ok(_) => {} + Err(e) => { + error!("write error: {:?}", e); + return 0; + } + } + } + }; + + let rx_fut = async { + loop { + match reader.read(&mut rx_buf).await { + Ok(0) => { + error!("read EOF"); + return 0; + } + Ok(n) => total += n, + Err(e) => { + error!("read error: {:?}", e); + return 0; + } + } + } + }; + + with_timeout(Duration::from_secs(TEST_DURATION as _), join(tx_fut, rx_fut)) + .await + .ok(); + + let kbps = (total + 512) / 1024 / TEST_DURATION; + info!("upload+download: {} kB/s", kbps); + kbps +} diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 7a94ea191..9fc537a4b 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -63,20 +63,13 @@ async fn main(spawner: Spawner) { .set_power_management(cyw43::PowerManagementMode::PowerSave) .await; - let config = Config::dhcpv4(Default::default()); - //let config = embassy_net::Config::Static(embassy_net::Config { - // address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 69, 2), 24), - // dns_servers: Vec::new(), - // gateway: Some(Ipv4Address::new(192, 168, 69, 1)), - //}); - // Generate random seed let seed = 0x0123_4567_89ab_cdef; // chosen by fair dice roll. guarenteed to be random. // Init network stack let stack = &*make_static!(Stack::new( net_device, - config, + Config::dhcpv4(Default::default()), make_static!(StackResources::<2>::new()), seed )); From 23c51a18741c4c500c46955b5cd028ec0eb7d53a Mon Sep 17 00:00:00 2001 From: Dietrich Beck Date: Thu, 22 Jun 2023 23:02:16 +0200 Subject: [PATCH 22/74] disable pull-up and down resistors for rp adc blocking_read --- embassy-rp/src/adc.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/embassy-rp/src/adc.rs b/embassy-rp/src/adc.rs index b96d5a4a8..699a0d61d 100644 --- a/embassy-rp/src/adc.rs +++ b/embassy-rp/src/adc.rs @@ -112,8 +112,14 @@ impl<'d> Adc<'d> { r.result().read().result().into() } - pub fn blocking_read, ID = u8>>(&mut self, _pin: &mut PIN) -> u16 { + pub fn blocking_read, ID = u8> + Pin>(&mut self, pin: &mut PIN) -> u16 { let r = Self::regs(); + pin.pad_ctrl().modify(|w| { + w.set_ie(true); + let (pu, pd) = (false, false); + w.set_pue(pu); + w.set_pde(pd); + }); r.cs().modify(|w| { w.set_ainsel(PIN::channel()); w.set_start_once(true) @@ -166,7 +172,7 @@ impl_pin!(PIN_29, 3); impl OneShot, WORD, PIN> for Adc<'static> where WORD: From, - PIN: Channel, ID = u8>, + PIN: Channel, ID = u8> + Pin, { type Error = (); fn read(&mut self, pin: &mut PIN) -> nb::Result { From 558247d8f60dbdebf5f3df3a632d9e32fe0f0277 Mon Sep 17 00:00:00 2001 From: GhaithOueslati Date: Thu, 22 Jun 2023 22:51:38 +0100 Subject: [PATCH 23/74] update hci crate name --- embassy-stm32-wpan/Cargo.toml | 4 ++-- embassy-stm32-wpan/src/ble.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 3659d7135..2977084ff 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -24,12 +24,12 @@ heapless = "0.7.16" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -bluetooth-hci-async = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true } +stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true } [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] -ble = ["dep:bluetooth-hci-async"] +ble = ["dep:stm32wb-hci"] mac = [] stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ] diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/ble.rs index 04acf0aff..619cd66a0 100644 --- a/embassy-stm32-wpan/src/ble.rs +++ b/embassy-stm32-wpan/src/ble.rs @@ -63,7 +63,7 @@ impl Ble { } } -pub extern crate bluetooth_hci_async as hci; +pub extern crate stm32wb_hci as hci; impl hci::Controller for Ble { async fn controller_write(&mut self, opcode: Opcode, payload: &[u8]) { From 64ff1a6b75aa13797cf64bb97e597f333a2ae9b6 Mon Sep 17 00:00:00 2001 From: GhaithOueslati Date: Thu, 22 Jun 2023 22:53:07 +0100 Subject: [PATCH 24/74] update hci crate git path --- embassy-stm32-wpan/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 2977084ff..ee60a22e5 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -24,7 +24,7 @@ heapless = "0.7.16" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/bluetooth-hci", features = ["version-5-0"], optional = true } +stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/stm32wb-hci", features = ["version-5-0"], optional = true } [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] From caf63b9e7336ed3ddb0dc997d431f15a26ae7693 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 22 Jun 2023 21:05:51 -0500 Subject: [PATCH 25/74] stm32/tests: update ble test --- embassy-stm32-wpan/Cargo.toml | 2 +- examples/stm32wb/Cargo.toml | 5 +- examples/stm32wb/src/bin/tl_mbox_mac.rs | 2 +- tests/stm32/Cargo.toml | 3 + tests/stm32/src/bin/tl_mbox.rs | 217 +++++++++++++++++++++--- 5 files changed, 205 insertions(+), 24 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index ee60a22e5..6d78ca577 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -24,7 +24,7 @@ heapless = "0.7.16" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } -stm32wb-hci = { version = "*", git = "https://github.com/OueslatiGhaith/stm32wb-hci", features = ["version-5-0"], optional = true } +stm32wb-hci = { version = "0.1.2", features = ["version-5-0"], optional = true } [features] defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-common/defmt"] diff --git a/examples/stm32wb/Cargo.toml b/examples/stm32wb/Cargo.toml index 726cd10d4..fbb2d918b 100644 --- a/examples/stm32wb/Cargo.toml +++ b/examples/stm32wb/Cargo.toml @@ -37,4 +37,7 @@ required-features = ["mac"] [[bin]] name = "eddystone_beacon" -required-features = ["ble"] \ No newline at end of file +required-features = ["ble"] + +[patch.crates-io] +stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"} \ No newline at end of file diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index 6c8653cf4..afd319a41 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -46,7 +46,7 @@ async fn main(_spawner: Spawner) { let config = Config::default(); let mbox = TlMbox::init(p.IPCC, Irqs, config); - let sys_event = mbox.sys_subsystem.tl_read().await; + let sys_event = mbox.sys_subsystem.read().await; info!("sys event: {}", sys_event.payload()); mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; diff --git a/tests/stm32/Cargo.toml b/tests/stm32/Cargo.toml index fe646927a..c2422f7bc 100644 --- a/tests/stm32/Cargo.toml +++ b/tests/stm32/Cargo.toml @@ -46,6 +46,9 @@ rand_chacha = { version = "0.3", default-features = false } chrono = { version = "^0.4", default-features = false, optional = true} +[patch.crates-io] +stm32wb-hci = { git = "https://github.com/OueslatiGhaith/stm32wb-hci", rev = "9f663be"} + # BEGIN TESTS # Generated by gen_test.py. DO NOT EDIT. [[bin]] diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs index f55c0292a..76c736a5b 100644 --- a/tests/stm32/src/bin/tl_mbox.rs +++ b/tests/stm32/src/bin/tl_mbox.rs @@ -6,43 +6,49 @@ #[path = "../common.rs"] mod common; -use core::mem; +use core::time::Duration; use common::*; use embassy_executor::Spawner; -use embassy_futures::poll_once; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; +use embassy_stm32_wpan::ble::hci::host::uart::UartHci; +use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; +use embassy_stm32_wpan::ble::hci::types::AdvertisingType; +use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{ + AdvertisingDataType, DiscoverableParameters, GapCommands, Role, +}; +use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands; +use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::ble::hci::BdAddr; +use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::{mm, TlMbox}; -use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ IPCC_C1_RX => ReceiveInterruptHandler; IPCC_C1_TX => TransmitInterruptHandler; }); +const BLE_GAP_DEVICE_NAME_LENGTH: u8 = 7; + #[embassy_executor::task] async fn run_mm_queue(memory_manager: mm::MemoryManager) { memory_manager.run_queue().await; } #[embassy_executor::main] -async fn main(spawner: Spawner) { +async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config()); info!("Hello World!"); let config = Config::default(); - let mbox = TlMbox::init(p.IPCC, Irqs, config); + let mut mbox = TlMbox::init(p.IPCC, Irqs, config); - spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap(); + // spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap(); - let ready_event = mbox.sys_subsystem.read().await; - let _ = poll_once(mbox.sys_subsystem.read()); // clear rx not - - info!("sys event {:x} : {:x}", ready_event.stub().kind, ready_event.payload()); - - // test memory manager - mem::drop(ready_event); + let sys_event = mbox.sys_subsystem.read().await; + info!("sys event: {}", sys_event.payload()); let fw_info = mbox.sys_subsystem.wireless_fw_info().unwrap(); let version_major = fw_info.version_major(); @@ -57,19 +63,188 @@ async fn main(spawner: Spawner) { version_major, version_minor, subversion, sram2a_size, sram2b_size ); - Timer::after(Duration::from_millis(50)).await; + mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; - let result = mbox.sys_subsystem.shci_c2_ble_init(Default::default()).await; - info!("subsystem initialization: {}", result); + info!("resetting BLE..."); + mbox.ble_subsystem.reset().await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); - info!("starting ble..."); - mbox.ble_subsystem.tl_write(0x0c, &[]).await; + info!("config public address..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::public_address(get_bd_addr()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); - info!("waiting for ble..."); - let ble_event = mbox.ble_subsystem.tl_read().await; + info!("config random address..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::random_address(get_random_addr()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); - info!("ble event {:x} : {:x}", ble_event.stub().kind, ble_event.payload()); + info!("config identity root..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::identity_root(&get_irk()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("config encryption root..."); + mbox.ble_subsystem + .write_config_data(&ConfigData::encryption_root(&get_erk()).build()) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("config tx power level..."); + mbox.ble_subsystem.set_tx_power_level(PowerLevel::ZerodBm).await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("GATT init..."); + mbox.ble_subsystem.init_gatt().await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("GAP init..."); + mbox.ble_subsystem + .init_gap(Role::PERIPHERAL, false, BLE_GAP_DEVICE_NAME_LENGTH) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + // info!("set scan response..."); + // mbox.ble_subsystem.le_set_scan_response_data(&[]).await.unwrap(); + // let response = mbox.ble_subsystem.read().await.unwrap(); + // info!("{}", response); + + info!("set discoverable..."); + mbox.ble_subsystem + .set_discoverable(&DiscoverableParameters { + advertising_type: AdvertisingType::NonConnectableUndirected, + advertising_interval: Some((Duration::from_millis(250), Duration::from_millis(250))), + address_type: OwnAddressType::Public, + filter_policy: AdvertisingFilterPolicy::AllowConnectionAndScan, + local_name: None, + advertising_data: &[], + conn_interval: (None, None), + }) + .await + .unwrap(); + + let response = mbox.ble_subsystem.read().await; + info!("{}", response); + + // remove some advertisement to decrease the packet size + info!("delete tx power ad type..."); + mbox.ble_subsystem + .delete_ad_type(AdvertisingDataType::TxPowerLevel) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("delete conn interval ad type..."); + mbox.ble_subsystem + .delete_ad_type(AdvertisingDataType::PeripheralConnectionInterval) + .await; + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("update advertising data..."); + mbox.ble_subsystem + .update_advertising_data(&eddystone_advertising_data()) + .await + .unwrap(); + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("update advertising data type..."); + mbox.ble_subsystem + .update_advertising_data(&[3, AdvertisingDataType::UuidCompleteList16 as u8, 0xaa, 0xfe]) + .await + .unwrap(); + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); + + info!("update advertising data flags..."); + mbox.ble_subsystem + .update_advertising_data(&[ + 2, + AdvertisingDataType::Flags as u8, + (0x02 | 0x04) as u8, // BLE general discoverable, without BR/EDR support + ]) + .await + .unwrap(); + let response = mbox.ble_subsystem.read().await.unwrap(); + info!("{}", response); info!("Test OK"); cortex_m::asm::bkpt(); } + +fn get_bd_addr() -> BdAddr { + let mut bytes = [0u8; 6]; + + let lhci_info = LhciC1DeviceInformationCcrp::new(); + bytes[0] = (lhci_info.uid64 & 0xff) as u8; + bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8; + bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8; + bytes[3] = lhci_info.device_type_id; + bytes[4] = (lhci_info.st_company_id & 0xff) as u8; + bytes[5] = (lhci_info.st_company_id >> 8 & 0xff) as u8; + + BdAddr(bytes) +} + +fn get_random_addr() -> BdAddr { + let mut bytes = [0u8; 6]; + + let lhci_info = LhciC1DeviceInformationCcrp::new(); + bytes[0] = (lhci_info.uid64 & 0xff) as u8; + bytes[1] = ((lhci_info.uid64 >> 8) & 0xff) as u8; + bytes[2] = ((lhci_info.uid64 >> 16) & 0xff) as u8; + bytes[3] = 0; + bytes[4] = 0x6E; + bytes[5] = 0xED; + + BdAddr(bytes) +} + +const BLE_CFG_IRK: [u8; 16] = [ + 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, +]; +const BLE_CFG_ERK: [u8; 16] = [ + 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, 0xfe, 0xdc, 0xba, 0x09, 0x87, 0x65, 0x43, 0x21, +]; + +fn get_irk() -> EncryptionKey { + EncryptionKey(BLE_CFG_IRK) +} + +fn get_erk() -> EncryptionKey { + EncryptionKey(BLE_CFG_ERK) +} + +fn eddystone_advertising_data() -> [u8; 24] { + const EDDYSTONE_URL: &[u8] = b"www.rust-lang.com"; + + let mut service_data = [0u8; 24]; + let url_len = EDDYSTONE_URL.len(); + + service_data[0] = 6 + url_len as u8; + service_data[1] = AdvertisingDataType::ServiceData as u8; + + // 16-bit eddystone uuid + service_data[2] = 0xaa; + service_data[3] = 0xFE; + + service_data[4] = 0x10; // URL frame type + service_data[5] = 22_i8 as u8; // calibrated TX power at 0m + service_data[6] = 0x03; // eddystone url prefix = https + + service_data[7..(7 + url_len)].copy_from_slice(EDDYSTONE_URL); + + service_data +} From ea04a0277bb19719188e904a86e28c34f9801c96 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:14:26 +0200 Subject: [PATCH 26/74] change dma complete transfer IR default to true --- embassy-stm32/src/dma/bdma.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/dma/bdma.rs b/embassy-stm32/src/dma/bdma.rs index 32b75bb68..5a87888b7 100644 --- a/embassy-stm32/src/dma/bdma.rs +++ b/embassy-stm32/src/dma/bdma.rs @@ -35,7 +35,7 @@ impl Default for TransferOptions { Self { circular: false, half_transfer_ir: false, - complete_transfer_ir: false, + complete_transfer_ir: true, } } } From 915f79c974ace037e914397b42eb9d2448bd5ca3 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Fri, 23 Jun 2023 12:14:40 +0200 Subject: [PATCH 27/74] allow independent use of ch1 and ch2 on dac --- embassy-stm32/src/dac/mod.rs | 152 +++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 51 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 42646d20d..5b39758bf 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -22,7 +22,7 @@ pub enum Channel { } impl Channel { - fn index(&self) -> usize { + const fn index(&self) -> usize { match self { Channel::Ch1 => 0, Channel::Ch2 => 1, @@ -109,72 +109,100 @@ pub enum ValueArray<'a> { } pub struct Dac<'d, T: Instance, Tx> { - channels: u8, + ch1: bool, + ch2: bool, txdma: PeripheralRef<'d, Tx>, _peri: PeripheralRef<'d, T>, } impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { - /// Create a new instance with one channel - pub fn new_1ch( + pub fn new_ch1( peri: impl Peripheral

+ 'd, txdma: impl Peripheral

+ 'd, _ch1: impl Peripheral

> + 'd, ) -> Self { into_ref!(peri); - Self::new_inner(peri, 1, txdma) + Self::new_inner(peri, true, false, txdma) } - /// Create a new instance with two channels - pub fn new_2ch( + pub fn new_ch2( + peri: impl Peripheral

+ 'd, + txdma: impl Peripheral

+ 'd, + _ch2: impl Peripheral

> + 'd, + ) -> Self { + into_ref!(peri); + Self::new_inner(peri, false, true, txdma) + } + + pub fn new_ch1_and_ch2( peri: impl Peripheral

+ 'd, txdma: impl Peripheral

+ 'd, _ch1: impl Peripheral

> + 'd, _ch2: impl Peripheral

> + 'd, ) -> Self { into_ref!(peri); - Self::new_inner(peri, 2, txdma) + Self::new_inner(peri, true, true, txdma) } /// Perform initialisation steps for the DAC - fn new_inner(peri: PeripheralRef<'d, T>, channels: u8, txdma: impl Peripheral

+ 'd) -> Self { + fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral

+ 'd) -> Self { into_ref!(txdma); T::enable(); T::reset(); - T::regs().mcr().modify(|reg| { - for ch in 0..channels { - reg.set_mode(ch as usize, 0); - reg.set_mode(ch as usize, 0); - } - }); - - T::regs().cr().modify(|reg| { - for ch in 0..channels { - reg.set_en(ch as usize, true); - reg.set_ten(ch as usize, true); - } - }); - - Self { - channels, + let mut dac = Self { + ch1, + ch2, txdma, _peri: peri, + }; + + // Configure each activated channel. All results can be `unwrap`ed since they + // will only error if the channel is not configured (i.e. ch1, ch2 are false) + if ch1 { + dac.set_channel_mode(Channel::Ch1, 0).unwrap(); + dac.enable_channel(Channel::Ch1).unwrap(); + dac.set_trigger_enable(Channel::Ch1, true).unwrap(); } + if ch2 { + dac.set_channel_mode(Channel::Ch2, 0).unwrap(); + dac.enable_channel(Channel::Ch2).unwrap(); + dac.set_trigger_enable(Channel::Ch2, true).unwrap(); + } + + dac } /// Check the channel is configured - fn check_channel_exists(&self, ch: Channel) -> Result<(), Error> { - if ch == Channel::Ch2 && self.channels < 2 { + fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> { + if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) { Err(Error::UnconfiguredChannel) } else { Ok(()) } } - /// Set the enable register of the given channel + /// Enable trigger of the given channel + fn set_trigger_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { + self.check_channel_configured(ch)?; + T::regs().cr().modify(|reg| { + reg.set_ten(ch.index(), on); + }); + Ok(()) + } + + /// Set mode register of the given channel + fn set_channel_mode(&mut self, ch: Channel, val: u8) -> Result<(), Error> { + self.check_channel_configured(ch)?; + T::regs().mcr().modify(|reg| { + reg.set_mode(ch.index(), val); + }); + Ok(()) + } + + /// Set enable register of the given channel fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { - self.check_channel_exists(ch)?; + self.check_channel_configured(ch)?; T::regs().cr().modify(|reg| { reg.set_en(ch.index(), on); }); @@ -193,7 +221,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// Select a new trigger for CH1 (disables the channel) pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { - self.check_channel_exists(Channel::Ch1)?; + self.check_channel_configured(Channel::Ch1)?; unwrap!(self.disable_channel(Channel::Ch1)); T::regs().cr().modify(|reg| { reg.set_tsel1(trigger.tsel()); @@ -203,7 +231,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// Select a new trigger for CH2 (disables the channel) pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { - self.check_channel_exists(Channel::Ch2)?; + self.check_channel_configured(Channel::Ch2)?; unwrap!(self.disable_channel(Channel::Ch2)); T::regs().cr().modify(|reg| { reg.set_tsel2(trigger.tsel()); @@ -213,7 +241,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// Perform a software trigger on `ch` pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { - self.check_channel_exists(ch)?; + self.check_channel_configured(ch)?; T::regs().swtrigr().write(|reg| { reg.set_swtrig(ch.index(), true); }); @@ -232,7 +260,7 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// /// The `value` is written to the corresponding "data holding register" pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { - self.check_channel_exists(ch)?; + self.check_channel_configured(ch)?; match value { Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), @@ -241,39 +269,61 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { Ok(()) } - /// Write `data` to the DAC via DMA. + /// Write `data` to the DAC CH1 via DMA. /// /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. /// This will configure a circular DMA transfer that periodically outputs the `data`. /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// - /// ## Current limitations - /// - Only CH1 Supported - /// - pub async fn write(&mut self, data_ch1: ValueArray<'_>, circular: bool) -> Result<(), Error> + /// **Important:** Channel 1 has to be configured for the DAC instance! + pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: Dma, { - // TODO: Make this a parameter or get it from the struct or so... - const CHANNEL: usize = 0; + self.check_channel_configured(Channel::Ch1)?; + self.write_inner(data, circular, Channel::Ch1).await + } + + /// Write `data` to the DAC CH2 via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. + /// + /// **Important:** Channel 2 has to be configured for the DAC instance! + pub async fn write_ch2(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + self.check_channel_configured(Channel::Ch2)?; + self.write_inner(data, circular, Channel::Ch2).await + } + + /// Performs the dma write for the given channel. + /// TODO: Should self be &mut? + async fn write_inner(&self, data_ch1: ValueArray<'_>, circular: bool, channel: Channel) -> Result<(), Error> + where + Tx: Dma, + { + let channel = channel.index(); // Enable DAC and DMA T::regs().cr().modify(|w| { - w.set_en(CHANNEL, true); - w.set_dmaen(CHANNEL, true); + w.set_en(channel, true); + w.set_dmaen(channel, true); }); let tx_request = self.txdma.request(); - let channel = &self.txdma; + let dma_channel = &self.txdma; // Initiate the correct type of DMA transfer depending on what data is passed let tx_f = match data_ch1 { ValueArray::Bit8(buf) => unsafe { Transfer::new_write( - channel, + dma_channel, tx_request, buf, - T::regs().dhr8r(CHANNEL).as_ptr() as *mut u8, + T::regs().dhr8r(channel).as_ptr() as *mut u8, TransferOptions { circular, half_transfer_ir: false, @@ -283,10 +333,10 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { }, ValueArray::Bit12Left(buf) => unsafe { Transfer::new_write( - channel, + dma_channel, tx_request, buf, - T::regs().dhr12l(CHANNEL).as_ptr() as *mut u16, + T::regs().dhr12l(channel).as_ptr() as *mut u16, TransferOptions { circular, half_transfer_ir: false, @@ -296,10 +346,10 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { }, ValueArray::Bit12Right(buf) => unsafe { Transfer::new_write( - channel, + dma_channel, tx_request, buf, - T::regs().dhr12r(CHANNEL).as_ptr() as *mut u16, + T::regs().dhr12r(channel).as_ptr() as *mut u16, TransferOptions { circular, half_transfer_ir: false, @@ -315,9 +365,9 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { // TODO: Do we need to check any status registers here? T::regs().cr().modify(|w| { // Disable the DAC peripheral - w.set_en(CHANNEL, false); + w.set_en(channel, false); // Disable the DMA. TODO: Is this necessary? - w.set_dmaen(CHANNEL, false); + w.set_dmaen(channel, false); }); Ok(()) From 29f32ce00ec0f50ef5e3b29c7e50f7f5479b4967 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 23 Jun 2023 17:54:06 -0500 Subject: [PATCH 28/74] stm32/wpan: reorg subsystems --- embassy-stm32-wpan/src/evt.rs | 4 +-- embassy-stm32-wpan/src/lhci.rs | 8 +++--- embassy-stm32-wpan/src/lib.rs | 26 +++++++++----------- embassy-stm32-wpan/src/{ => sub}/ble.rs | 0 embassy-stm32-wpan/src/{ => sub}/mac.rs | 0 embassy-stm32-wpan/src/{ => sub}/mm.rs | 0 embassy-stm32-wpan/src/sub/mod.rs | 6 +++++ embassy-stm32-wpan/src/{ => sub}/sys.rs | 0 examples/stm32wb/src/bin/eddystone_beacon.rs | 14 +++++------ tests/stm32/src/bin/tl_mbox.rs | 17 +++++++------ 10 files changed, 41 insertions(+), 34 deletions(-) rename embassy-stm32-wpan/src/{ => sub}/ble.rs (100%) rename embassy-stm32-wpan/src/{ => sub}/mac.rs (100%) rename embassy-stm32-wpan/src/{ => sub}/mm.rs (100%) create mode 100644 embassy-stm32-wpan/src/sub/mod.rs rename embassy-stm32-wpan/src/{ => sub}/sys.rs (100%) diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs index 25249a13a..22f089037 100644 --- a/embassy-stm32-wpan/src/evt.rs +++ b/embassy-stm32-wpan/src/evt.rs @@ -145,14 +145,14 @@ impl Drop for EvtBox { fn drop(&mut self) { #[cfg(feature = "ble")] unsafe { - use crate::mm; + use crate::sub::mm; mm::MemoryManager::drop_event_packet(self.ptr) }; #[cfg(feature = "mac")] unsafe { - use crate::mac; + use crate::sub::mac; mac::Mac::drop_event_packet(self.ptr) } diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs index 62116a695..284103705 100644 --- a/embassy-stm32-wpan/src/lhci.rs +++ b/embassy-stm32-wpan/src/lhci.rs @@ -1,7 +1,9 @@ +use core::ptr; + use crate::cmd::CmdPacket; use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE}; use crate::evt::{CcEvt, EvtPacket, EvtSerial}; -use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable}; +use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE}; use crate::TL_REF_TABLE; const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; @@ -38,7 +40,7 @@ impl Default for LhciC1DeviceInformationCcrp { safe_boot_info_table, rss_info_table, wireless_fw_info_table, - } = unsafe { &*(*TL_REF_TABLE.as_ptr()).device_info_table }.clone(); + } = unsafe { ptr::read_volatile(TL_DEVICE_INFO_TABLE.as_ptr()) }; let device_id = stm32_device_signature::device_id(); let uid96_0 = (device_id[3] as u32) << 24 @@ -105,7 +107,7 @@ impl LhciC1DeviceInformationCcrp { let self_ptr: *const LhciC1DeviceInformationCcrp = self; let self_buf = self_ptr.cast(); - core::ptr::copy(self_buf, evt_cc_payload_buf, self_size); + ptr::copy(self_buf, evt_cc_payload_buf, self_size); } } } diff --git a/embassy-stm32-wpan/src/lib.rs b/embassy-stm32-wpan/src/lib.rs index bf0f0466e..99c610583 100644 --- a/embassy-stm32-wpan/src/lib.rs +++ b/embassy-stm32-wpan/src/lib.rs @@ -11,26 +11,24 @@ use embassy_hal_common::{into_ref, Peripheral, PeripheralRef}; use embassy_stm32::interrupt; use embassy_stm32::ipcc::{Config, Ipcc, ReceiveInterruptHandler, TransmitInterruptHandler}; use embassy_stm32::peripherals::IPCC; -use mm::MemoryManager; -use sys::Sys; +use sub::mm::MemoryManager; +use sub::sys::Sys; use tables::*; use unsafe_linked_list::LinkedListNode; -#[cfg(feature = "ble")] -pub mod ble; pub mod channels; pub mod cmd; pub mod consts; pub mod evt; pub mod lhci; -#[cfg(feature = "mac")] -pub mod mac; -pub mod mm; pub mod shci; -pub mod sys; +pub mod sub; pub mod tables; pub mod unsafe_linked_list; +#[cfg(feature = "ble")] +pub use crate::sub::ble::hci; + type PacketHeader = LinkedListNode; pub struct TlMbox<'d> { @@ -39,9 +37,9 @@ pub struct TlMbox<'d> { pub sys_subsystem: Sys, pub mm_subsystem: MemoryManager, #[cfg(feature = "ble")] - pub ble_subsystem: ble::Ble, + pub ble_subsystem: sub::ble::Ble, #[cfg(feature = "mac")] - pub mac_subsystem: mac::Mac, + pub mac_subsystem: sub::mac::Mac, } impl<'d> TlMbox<'d> { @@ -128,12 +126,12 @@ impl<'d> TlMbox<'d> { Self { _ipcc: ipcc, - sys_subsystem: sys::Sys::new(), + sys_subsystem: sub::sys::Sys::new(), #[cfg(feature = "ble")] - ble_subsystem: ble::Ble::new(), + ble_subsystem: sub::ble::Ble::new(), #[cfg(feature = "mac")] - mac_subsystem: mac::Mac::new(), - mm_subsystem: mm::MemoryManager::new(), + mac_subsystem: sub::mac::Mac::new(), + mm_subsystem: sub::mm::MemoryManager::new(), } } } diff --git a/embassy-stm32-wpan/src/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs similarity index 100% rename from embassy-stm32-wpan/src/ble.rs rename to embassy-stm32-wpan/src/sub/ble.rs diff --git a/embassy-stm32-wpan/src/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs similarity index 100% rename from embassy-stm32-wpan/src/mac.rs rename to embassy-stm32-wpan/src/sub/mac.rs diff --git a/embassy-stm32-wpan/src/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs similarity index 100% rename from embassy-stm32-wpan/src/mm.rs rename to embassy-stm32-wpan/src/sub/mm.rs diff --git a/embassy-stm32-wpan/src/sub/mod.rs b/embassy-stm32-wpan/src/sub/mod.rs new file mode 100644 index 000000000..bee3dbdf1 --- /dev/null +++ b/embassy-stm32-wpan/src/sub/mod.rs @@ -0,0 +1,6 @@ +#[cfg(feature = "ble")] +pub mod ble; +#[cfg(feature = "mac")] +pub mod mac; +pub mod mm; +pub mod sys; diff --git a/embassy-stm32-wpan/src/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs similarity index 100% rename from embassy-stm32-wpan/src/sys.rs rename to embassy-stm32-wpan/src/sub/sys.rs diff --git a/examples/stm32wb/src/bin/eddystone_beacon.rs b/examples/stm32wb/src/bin/eddystone_beacon.rs index fdd5be4a2..b99f8cb2e 100644 --- a/examples/stm32wb/src/bin/eddystone_beacon.rs +++ b/examples/stm32wb/src/bin/eddystone_beacon.rs @@ -8,15 +8,15 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; -use embassy_stm32_wpan::ble::hci::host::uart::UartHci; -use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; -use embassy_stm32_wpan::ble::hci::types::AdvertisingType; -use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{ +use embassy_stm32_wpan::hci::host::uart::UartHci; +use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; +use embassy_stm32_wpan::hci::types::AdvertisingType; +use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{ AdvertisingDataType, DiscoverableParameters, GapCommands, Role, }; -use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands; -use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::ble::hci::BdAddr; +use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands; +use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs index 76c736a5b..8880554de 100644 --- a/tests/stm32/src/bin/tl_mbox.rs +++ b/tests/stm32/src/bin/tl_mbox.rs @@ -12,17 +12,18 @@ use common::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::ipcc::{Config, ReceiveInterruptHandler, TransmitInterruptHandler}; -use embassy_stm32_wpan::ble::hci::host::uart::UartHci; -use embassy_stm32_wpan::ble::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; -use embassy_stm32_wpan::ble::hci::types::AdvertisingType; -use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gap::{ +use embassy_stm32_wpan::hci::host::uart::UartHci; +use embassy_stm32_wpan::hci::host::{AdvertisingFilterPolicy, EncryptionKey, HostHci, OwnAddressType}; +use embassy_stm32_wpan::hci::types::AdvertisingType; +use embassy_stm32_wpan::hci::vendor::stm32wb::command::gap::{ AdvertisingDataType, DiscoverableParameters, GapCommands, Role, }; -use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::gatt::GattCommands; -use embassy_stm32_wpan::ble::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; -use embassy_stm32_wpan::ble::hci::BdAddr; +use embassy_stm32_wpan::hci::vendor::stm32wb::command::gatt::GattCommands; +use embassy_stm32_wpan::hci::vendor::stm32wb::command::hal::{ConfigData, HalCommands, PowerLevel}; +use embassy_stm32_wpan::hci::BdAddr; use embassy_stm32_wpan::lhci::LhciC1DeviceInformationCcrp; -use embassy_stm32_wpan::{mm, TlMbox}; +use embassy_stm32_wpan::sub::mm; +use embassy_stm32_wpan::TlMbox; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs{ From f23b34951a20f569997bbe028048f3943d7e4c56 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 23 Jun 2023 17:55:47 -0500 Subject: [PATCH 29/74] rustfmt --- embassy-stm32-wpan/src/lhci.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/embassy-stm32-wpan/src/lhci.rs b/embassy-stm32-wpan/src/lhci.rs index 284103705..89f204f99 100644 --- a/embassy-stm32-wpan/src/lhci.rs +++ b/embassy-stm32-wpan/src/lhci.rs @@ -4,7 +4,6 @@ use crate::cmd::CmdPacket; use crate::consts::{TlPacketType, TL_EVT_HEADER_SIZE}; use crate::evt::{CcEvt, EvtPacket, EvtSerial}; use crate::tables::{DeviceInfoTable, RssInfoTable, SafeBootInfoTable, WirelessFwInfoTable, TL_DEVICE_INFO_TABLE}; -use crate::TL_REF_TABLE; const TL_BLEEVT_CC_OPCODE: u8 = 0x0e; const LHCI_OPCODE_C1_DEVICE_INF: u16 = 0xfd62; From 91fdd76053c747c569b0eefe0715522465fe0194 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 23 Jun 2023 18:08:42 -0500 Subject: [PATCH 30/74] stm32/wpan: use align to align data --- embassy-stm32-wpan/Cargo.toml | 1 + embassy-stm32-wpan/src/tables.rs | 34 ++++++++++++-------------------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml index 6d78ca577..4b830cab3 100644 --- a/embassy-stm32-wpan/Cargo.toml +++ b/embassy-stm32-wpan/Cargo.toml @@ -21,6 +21,7 @@ embassy-embedded-hal = { version = "0.1.0", path = "../embassy-embedded-hal" } defmt = { version = "0.3", optional = true } cortex-m = "0.7.6" heapless = "0.7.16" +aligned = "0.4.1" bit_field = "0.10.2" stm32-device-signature = { version = "0.3.3", features = ["stm32wb5x"] } diff --git a/embassy-stm32-wpan/src/tables.rs b/embassy-stm32-wpan/src/tables.rs index 3f26282c6..1b5dcdf2e 100644 --- a/embassy-stm32-wpan/src/tables.rs +++ b/embassy-stm32-wpan/src/tables.rs @@ -1,5 +1,6 @@ use core::mem::MaybeUninit; +use aligned::{Aligned, A4}; use bit_field::BitField; use crate::cmd::{AclDataPacket, CmdPacket}; @@ -164,9 +165,6 @@ pub struct Mac802_15_4Table { pub evt_queue: *const u8, } -#[repr(C, align(4))] -pub struct AlignedData([u8; L]); - /// Reference table. Contains pointers to all other tables. #[derive(Debug, Copy, Clone)] #[repr(C)] @@ -222,10 +220,9 @@ pub static mut FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit #[link_section = "MB_MEM1"] pub static mut TRACES_EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); -const CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; - #[link_section = "MB_MEM2"] -pub static mut CS_BUFFER: MaybeUninit> = MaybeUninit::uninit(); +pub static mut CS_BUFFER: MaybeUninit> = + MaybeUninit::uninit(); #[link_section = "MB_MEM2"] pub static mut EVT_QUEUE: MaybeUninit = MaybeUninit::uninit(); @@ -238,35 +235,30 @@ pub static mut SYSTEM_EVT_QUEUE: MaybeUninit = MaybeUninit::unin #[link_section = "MB_MEM2"] pub static mut MAC_802_15_4_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); -#[cfg(feature = "mac")] -const MAC_802_15_4_NOTIF_RSP_EVT_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255; - #[cfg(feature = "mac")] #[link_section = "MB_MEM2"] -pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit> = - MaybeUninit::uninit(); +pub static mut MAC_802_15_4_NOTIF_RSP_EVT_BUFFER: MaybeUninit< + Aligned, +> = MaybeUninit::uninit(); #[link_section = "MB_MEM2"] -pub static mut EVT_POOL: MaybeUninit<[u8; POOL_SIZE]> = MaybeUninit::uninit(); +pub static mut EVT_POOL: MaybeUninit> = MaybeUninit::uninit(); #[link_section = "MB_MEM2"] pub static mut SYS_CMD_BUF: MaybeUninit = MaybeUninit::uninit(); -const SYS_SPARE_EVT_BUF_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255; - #[link_section = "MB_MEM2"] -pub static mut SYS_SPARE_EVT_BUF: MaybeUninit> = MaybeUninit::uninit(); +pub static mut SYS_SPARE_EVT_BUF: MaybeUninit> = + MaybeUninit::uninit(); #[link_section = "MB_MEM1"] pub static mut BLE_CMD_BUFFER: MaybeUninit = MaybeUninit::uninit(); -const BLE_SPARE_EVT_BUF_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_EVT_HEADER_SIZE + 255; - #[link_section = "MB_MEM2"] -pub static mut BLE_SPARE_EVT_BUF: MaybeUninit> = MaybeUninit::uninit(); - -const HCI_ACL_DATA_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + 5 + 251; +pub static mut BLE_SPARE_EVT_BUF: MaybeUninit> = + MaybeUninit::uninit(); #[link_section = "MB_MEM2"] // fuck these "magic" numbers from ST ---v---v -pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit<[u8; HCI_ACL_DATA_BUFFER_SIZE]> = MaybeUninit::uninit(); +pub static mut HCI_ACL_DATA_BUFFER: MaybeUninit> = + MaybeUninit::uninit(); From d43417e97c4de487b4ebf018830825e034c5394e Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 23 Jun 2023 19:59:48 -0500 Subject: [PATCH 31/74] stm32/wpan: implement mm pattern --- embassy-stm32-wpan/src/consts.rs | 4 +++ embassy-stm32-wpan/src/evt.rs | 33 ++++++++------------- embassy-stm32-wpan/src/sub/ble.rs | 25 +++++++++++++--- embassy-stm32-wpan/src/sub/mac.rs | 48 ++++++++++++++++--------------- embassy-stm32-wpan/src/sub/mm.rs | 23 ++++++++------- embassy-stm32-wpan/src/sub/sys.rs | 3 +- tests/stm32/src/bin/tl_mbox.rs | 4 +-- 7 files changed, 78 insertions(+), 62 deletions(-) diff --git a/embassy-stm32-wpan/src/consts.rs b/embassy-stm32-wpan/src/consts.rs index 9a107306c..f234151d7 100644 --- a/embassy-stm32-wpan/src/consts.rs +++ b/embassy-stm32-wpan/src/consts.rs @@ -87,3 +87,7 @@ pub const fn divc(x: usize, y: usize) -> usize { pub const TL_BLE_EVT_CS_PACKET_SIZE: usize = TL_EVT_HEADER_SIZE + TL_CS_EVT_SIZE; #[allow(dead_code)] pub const TL_BLE_EVT_CS_BUFFER_SIZE: usize = TL_PACKET_HEADER_SIZE + TL_BLE_EVT_CS_PACKET_SIZE; + +pub const TL_BLEEVT_CC_OPCODE: u8 = 0x0E; +pub const TL_BLEEVT_CS_OPCODE: u8 = 0x0F; +pub const TL_BLEEVT_VS_OPCODE: u8 = 0xFF; diff --git a/embassy-stm32-wpan/src/evt.rs b/embassy-stm32-wpan/src/evt.rs index 22f089037..c6528413d 100644 --- a/embassy-stm32-wpan/src/evt.rs +++ b/embassy-stm32-wpan/src/evt.rs @@ -1,3 +1,4 @@ +use core::marker::PhantomData; use core::{ptr, slice}; use super::PacketHeader; @@ -93,17 +94,22 @@ impl EvtPacket { } } +pub trait MemoryManager { + unsafe fn drop_event_packet(evt: *mut EvtPacket); +} + /// smart pointer to the [`EvtPacket`] that will dispose of [`EvtPacket`] buffer automatically /// on [`Drop`] #[derive(Debug)] -pub struct EvtBox { +pub struct EvtBox { ptr: *mut EvtPacket, + mm: PhantomData, } -unsafe impl Send for EvtBox {} -impl EvtBox { +unsafe impl Send for EvtBox {} +impl EvtBox { pub(super) fn new(ptr: *mut EvtPacket) -> Self { - Self { ptr } + Self { ptr, mm: PhantomData } } /// Returns information about the event @@ -126,9 +132,6 @@ impl EvtBox { } } - /// writes an underlying [`EvtPacket`] into the provided buffer. - /// Returns the number of bytes that were written. - /// Returns an error if event kind is unknown or if provided buffer size is not enough. pub fn serial<'a>(&'a self) -> &'a [u8] { unsafe { let evt_serial: *const EvtSerial = &(*self.ptr).evt_serial; @@ -141,20 +144,8 @@ impl EvtBox { } } -impl Drop for EvtBox { +impl Drop for EvtBox { fn drop(&mut self) { - #[cfg(feature = "ble")] - unsafe { - use crate::sub::mm; - - mm::MemoryManager::drop_event_packet(self.ptr) - }; - - #[cfg(feature = "mac")] - unsafe { - use crate::sub::mac; - - mac::Mac::drop_event_packet(self.ptr) - } + unsafe { T::drop_event_packet(self.ptr) }; } } diff --git a/embassy-stm32-wpan/src/sub/ble.rs b/embassy-stm32-wpan/src/sub/ble.rs index 619cd66a0..cd32692e1 100644 --- a/embassy-stm32-wpan/src/sub/ble.rs +++ b/embassy-stm32-wpan/src/sub/ble.rs @@ -1,14 +1,16 @@ use core::marker::PhantomData; +use core::ptr; use embassy_stm32::ipcc::Ipcc; use hci::Opcode; -use crate::channels; use crate::cmd::CmdPacket; -use crate::consts::TlPacketType; -use crate::evt::EvtBox; +use crate::consts::{TlPacketType, TL_BLEEVT_CC_OPCODE, TL_BLEEVT_CS_OPCODE}; +use crate::evt::{EvtBox, EvtPacket, EvtStub}; +use crate::sub::mm; use crate::tables::{BleTable, BLE_CMD_BUFFER, CS_BUFFER, EVT_QUEUE, HCI_ACL_DATA_BUFFER, TL_BLE_TABLE}; use crate::unsafe_linked_list::LinkedListNode; +use crate::{channels, evt}; pub struct Ble { phantom: PhantomData, @@ -30,7 +32,7 @@ impl Ble { Self { phantom: PhantomData } } /// `HW_IPCC_BLE_EvtNot` - pub async fn tl_read(&self) -> EvtBox { + pub async fn tl_read(&self) -> EvtBox { Ipcc::receive(channels::cpu2::IPCC_BLE_EVENT_CHANNEL, || unsafe { if let Some(node_ptr) = LinkedListNode::remove_head(EVT_QUEUE.as_mut_ptr()) { Some(EvtBox::new(node_ptr.cast())) @@ -63,6 +65,21 @@ impl Ble { } } +impl evt::MemoryManager for Ble { + /// SAFETY: passing a pointer to something other than a managed event packet is UB + unsafe fn drop_event_packet(evt: *mut EvtPacket) { + let stub = unsafe { + let p_evt_stub = &(*evt).evt_serial as *const _ as *const EvtStub; + + ptr::read_volatile(p_evt_stub) + }; + + if !(stub.evt_code == TL_BLEEVT_CS_OPCODE || stub.evt_code == TL_BLEEVT_CC_OPCODE) { + mm::MemoryManager::drop_event_packet(evt); + } + } +} + pub extern crate stm32wb_hci as hci; impl hci::Controller for Ble { diff --git a/embassy-stm32-wpan/src/sub/mac.rs b/embassy-stm32-wpan/src/sub/mac.rs index d2be1b85c..fd8af8609 100644 --- a/embassy-stm32-wpan/src/sub/mac.rs +++ b/embassy-stm32-wpan/src/sub/mac.rs @@ -8,13 +8,13 @@ use embassy_futures::poll_once; use embassy_stm32::ipcc::Ipcc; use embassy_sync::waitqueue::AtomicWaker; -use crate::channels; use crate::cmd::CmdPacket; use crate::consts::TlPacketType; use crate::evt::{EvtBox, EvtPacket}; use crate::tables::{ Mac802_15_4Table, MAC_802_15_4_CMD_BUFFER, MAC_802_15_4_NOTIF_RSP_EVT_BUFFER, TL_MAC_802_15_4_TABLE, }; +use crate::{channels, evt}; static MAC_WAKER: AtomicWaker = AtomicWaker::new(); static MAC_EVT_OUT: AtomicBool = AtomicBool::new(false); @@ -36,31 +36,10 @@ impl Mac { Self { phantom: PhantomData } } - /// SAFETY: passing a pointer to something other than a managed event packet is UB - pub(crate) unsafe fn drop_event_packet(_: *mut EvtPacket) { - // Write the ack - CmdPacket::write_into( - MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, - TlPacketType::OtAck, - 0, - &[], - ); - - // Clear the rx flag - let _ = poll_once(Ipcc::receive::( - channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, - || None, - )); - - // Allow a new read call - MAC_EVT_OUT.store(false, Ordering::SeqCst); - MAC_WAKER.wake(); - } - /// `HW_IPCC_MAC_802_15_4_EvtNot` /// /// This function will stall if the previous `EvtBox` has not been dropped - pub async fn read(&self) -> EvtBox { + pub async fn read(&self) -> EvtBox { // Wait for the last event box to be dropped poll_fn(|cx| { MAC_WAKER.register(cx.waker()); @@ -109,3 +88,26 @@ impl Mac { .await; } } + +impl evt::MemoryManager for Mac { + /// SAFETY: passing a pointer to something other than a managed event packet is UB + unsafe fn drop_event_packet(_: *mut EvtPacket) { + // Write the ack + CmdPacket::write_into( + MAC_802_15_4_NOTIF_RSP_EVT_BUFFER.as_mut_ptr() as *mut _, + TlPacketType::OtAck, + 0, + &[], + ); + + // Clear the rx flag + let _ = poll_once(Ipcc::receive::( + channels::cpu2::IPCC_MAC_802_15_4_NOTIFICATION_ACK_CHANNEL, + || None, + )); + + // Allow a new read call + MAC_EVT_OUT.store(false, Ordering::SeqCst); + MAC_WAKER.wake(); + } +} diff --git a/embassy-stm32-wpan/src/sub/mm.rs b/embassy-stm32-wpan/src/sub/mm.rs index 047fddcd4..1f2ecac2e 100644 --- a/embassy-stm32-wpan/src/sub/mm.rs +++ b/embassy-stm32-wpan/src/sub/mm.rs @@ -8,13 +8,13 @@ use cortex_m::interrupt; use embassy_stm32::ipcc::Ipcc; use embassy_sync::waitqueue::AtomicWaker; -use crate::channels; use crate::consts::POOL_SIZE; use crate::evt::EvtPacket; use crate::tables::{ MemManagerTable, BLE_SPARE_EVT_BUF, EVT_POOL, FREE_BUF_QUEUE, SYS_SPARE_EVT_BUF, TL_MEM_MANAGER_TABLE, }; use crate::unsafe_linked_list::LinkedListNode; +use crate::{channels, evt}; static MM_WAKER: AtomicWaker = AtomicWaker::new(); static mut LOCAL_FREE_BUF_QUEUE: MaybeUninit = MaybeUninit::uninit(); @@ -43,16 +43,6 @@ impl MemoryManager { Self { phantom: PhantomData } } - #[allow(dead_code)] - /// SAFETY: passing a pointer to something other than a managed event packet is UB - pub(crate) unsafe fn drop_event_packet(evt: *mut EvtPacket) { - interrupt::free(|_| unsafe { - LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); - }); - - MM_WAKER.wake(); - } - pub async fn run_queue(&self) { loop { poll_fn(|cx| unsafe { @@ -77,3 +67,14 @@ impl MemoryManager { } } } + +impl evt::MemoryManager for MemoryManager { + /// SAFETY: passing a pointer to something other than a managed event packet is UB + unsafe fn drop_event_packet(evt: *mut EvtPacket) { + interrupt::free(|_| unsafe { + LinkedListNode::insert_head(LOCAL_FREE_BUF_QUEUE.as_mut_ptr(), evt as *mut _); + }); + + MM_WAKER.wake(); + } +} diff --git a/embassy-stm32-wpan/src/sub/sys.rs b/embassy-stm32-wpan/src/sub/sys.rs index 2b699b725..af652860d 100644 --- a/embassy-stm32-wpan/src/sub/sys.rs +++ b/embassy-stm32-wpan/src/sub/sys.rs @@ -6,6 +6,7 @@ use crate::consts::TlPacketType; use crate::evt::{CcEvt, EvtBox, EvtPacket}; #[allow(unused_imports)] use crate::shci::{SchiCommandStatus, ShciBleInitCmdParam, ShciOpcode}; +use crate::sub::mm; use crate::tables::{SysTable, WirelessFwInfoTable}; use crate::unsafe_linked_list::LinkedListNode; use crate::{channels, Ipcc, SYSTEM_EVT_QUEUE, SYS_CMD_BUF, TL_DEVICE_INFO_TABLE, TL_SYS_TABLE}; @@ -73,7 +74,7 @@ impl Sys { } /// `HW_IPCC_SYS_EvtNot` - pub async fn read(&self) -> EvtBox { + pub async fn read(&self) -> EvtBox { Ipcc::receive(channels::cpu2::IPCC_SYSTEM_EVENT_CHANNEL, || unsafe { if let Some(node_ptr) = LinkedListNode::remove_head(SYSTEM_EVT_QUEUE.as_mut_ptr()) { Some(EvtBox::new(node_ptr.cast())) diff --git a/tests/stm32/src/bin/tl_mbox.rs b/tests/stm32/src/bin/tl_mbox.rs index 8880554de..af3832709 100644 --- a/tests/stm32/src/bin/tl_mbox.rs +++ b/tests/stm32/src/bin/tl_mbox.rs @@ -39,14 +39,14 @@ async fn run_mm_queue(memory_manager: mm::MemoryManager) { } #[embassy_executor::main] -async fn main(_spawner: Spawner) { +async fn main(spawner: Spawner) { let p = embassy_stm32::init(config()); info!("Hello World!"); let config = Config::default(); let mut mbox = TlMbox::init(p.IPCC, Irqs, config); - // spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap(); + spawner.spawn(run_mm_queue(mbox.mm_subsystem)).unwrap(); let sys_event = mbox.sys_subsystem.read().await; info!("sys event: {}", sys_event.payload()); From 49333ce6adf28ff6c3eb1a632c0d4860379ef3ef Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 23 Jun 2023 20:09:13 -0500 Subject: [PATCH 32/74] stm32/wpan: move linker file into pkg --- embassy-stm32-wpan/build.rs | 13 ++++++++++++- {embassy-stm32 => embassy-stm32-wpan}/tl_mbox.x.in | 0 embassy-stm32/build.rs | 10 ---------- 3 files changed, 12 insertions(+), 11 deletions(-) rename {embassy-stm32 => embassy-stm32-wpan}/tl_mbox.x.in (100%) diff --git a/embassy-stm32-wpan/build.rs b/embassy-stm32-wpan/build.rs index 4edf73d59..94aac070d 100644 --- a/embassy-stm32-wpan/build.rs +++ b/embassy-stm32-wpan/build.rs @@ -1,4 +1,5 @@ -use std::env; +use std::path::PathBuf; +use std::{env, fs}; fn main() { match env::vars() @@ -10,6 +11,16 @@ fn main() { Err(GetOneError::None) => panic!("No stm32xx Cargo feature enabled"), Err(GetOneError::Multiple) => panic!("Multiple stm32xx Cargo features enabled"), } + + let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + + // ======== + // stm32wb tl_mbox link sections + + let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string(); + fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap(); + println!("cargo:rustc-link-search={}", out_dir.display()); + println!("cargo:rerun-if-changed=tl_mbox.x.in"); } enum GetOneError { diff --git a/embassy-stm32/tl_mbox.x.in b/embassy-stm32-wpan/tl_mbox.x.in similarity index 100% rename from embassy-stm32/tl_mbox.x.in rename to embassy-stm32-wpan/tl_mbox.x.in diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f71074bcf..40103d322 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -911,16 +911,6 @@ fn main() { println!("cargo:rustc-cfg={}x{}", &chip_name[..9], &chip_name[10..11]); } - // ======== - // stm32wb tl_mbox link sections - - if chip_name.starts_with("stm32wb") { - let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string(); - fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap(); - println!("cargo:rustc-link-search={}", out_dir.display()); - println!("cargo:rerun-if-changed=tl_mbox.x.in"); - } - // ======= // Features for targeting groups of chips From 388d3e273d3d003e6a058b4bad9e2517dd33d626 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sat, 24 Jun 2023 13:10:59 +0200 Subject: [PATCH 33/74] first attempt at fixing the 2nd channel problem --- embassy-stm32/src/dac/mod.rs | 386 +++++++++++++++++++++-------------- 1 file changed, 234 insertions(+), 152 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 5b39758bf..e87292b86 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -1,5 +1,7 @@ #![macro_use] +use core::marker::PhantomData; + use embassy_hal_common::{into_ref, PeripheralRef}; use crate::dma::{Transfer, TransferOptions}; @@ -108,166 +110,108 @@ pub enum ValueArray<'a> { Bit12Right(&'a [u16]), } -pub struct Dac<'d, T: Instance, Tx> { - ch1: bool, - ch2: bool, - txdma: PeripheralRef<'d, Tx>, - _peri: PeripheralRef<'d, T>, -} - -impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { - pub fn new_ch1( - peri: impl Peripheral

+ 'd, - txdma: impl Peripheral

+ 'd, - _ch1: impl Peripheral

> + 'd, - ) -> Self { - into_ref!(peri); - Self::new_inner(peri, true, false, txdma) - } - - pub fn new_ch2( - peri: impl Peripheral

+ 'd, - txdma: impl Peripheral

+ 'd, - _ch2: impl Peripheral

> + 'd, - ) -> Self { - into_ref!(peri); - Self::new_inner(peri, false, true, txdma) - } - - pub fn new_ch1_and_ch2( - peri: impl Peripheral

+ 'd, - txdma: impl Peripheral

+ 'd, - _ch1: impl Peripheral

> + 'd, - _ch2: impl Peripheral

> + 'd, - ) -> Self { - into_ref!(peri); - Self::new_inner(peri, true, true, txdma) - } - - /// Perform initialisation steps for the DAC - fn new_inner(peri: PeripheralRef<'d, T>, ch1: bool, ch2: bool, txdma: impl Peripheral

+ 'd) -> Self { - into_ref!(txdma); - T::enable(); - T::reset(); - - let mut dac = Self { - ch1, - ch2, - txdma, - _peri: peri, - }; - - // Configure each activated channel. All results can be `unwrap`ed since they - // will only error if the channel is not configured (i.e. ch1, ch2 are false) - if ch1 { - dac.set_channel_mode(Channel::Ch1, 0).unwrap(); - dac.enable_channel(Channel::Ch1).unwrap(); - dac.set_trigger_enable(Channel::Ch1, true).unwrap(); - } - if ch2 { - dac.set_channel_mode(Channel::Ch2, 0).unwrap(); - dac.enable_channel(Channel::Ch2).unwrap(); - dac.set_trigger_enable(Channel::Ch2, true).unwrap(); - } - - dac - } - - /// Check the channel is configured - fn check_channel_configured(&self, ch: Channel) -> Result<(), Error> { - if (ch == Channel::Ch1 && !self.ch1) || (ch == Channel::Ch2 && !self.ch2) { - Err(Error::UnconfiguredChannel) - } else { - Ok(()) - } - } +pub trait DacChannel { + const CHANNEL: Channel; /// Enable trigger of the given channel - fn set_trigger_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { - self.check_channel_configured(ch)?; + fn set_trigger_enable(&mut self, on: bool) -> Result<(), Error> { T::regs().cr().modify(|reg| { - reg.set_ten(ch.index(), on); + reg.set_ten(Self::CHANNEL.index(), on); }); Ok(()) } /// Set mode register of the given channel - fn set_channel_mode(&mut self, ch: Channel, val: u8) -> Result<(), Error> { - self.check_channel_configured(ch)?; + fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> { T::regs().mcr().modify(|reg| { - reg.set_mode(ch.index(), val); + reg.set_mode(Self::CHANNEL.index(), val); }); Ok(()) } /// Set enable register of the given channel - fn set_channel_enable(&mut self, ch: Channel, on: bool) -> Result<(), Error> { - self.check_channel_configured(ch)?; + fn set_channel_enable(&mut self, on: bool) -> Result<(), Error> { T::regs().cr().modify(|reg| { - reg.set_en(ch.index(), on); + reg.set_en(Self::CHANNEL.index(), on); }); Ok(()) } /// Enable the DAC channel `ch` - pub fn enable_channel(&mut self, ch: Channel) -> Result<(), Error> { - self.set_channel_enable(ch, true) + fn enable_channel(&mut self) -> Result<(), Error> { + self.set_channel_enable(true) } /// Disable the DAC channel `ch` - pub fn disable_channel(&mut self, ch: Channel) -> Result<(), Error> { - self.set_channel_enable(ch, false) - } - - /// Select a new trigger for CH1 (disables the channel) - pub fn select_trigger_ch1(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { - self.check_channel_configured(Channel::Ch1)?; - unwrap!(self.disable_channel(Channel::Ch1)); - T::regs().cr().modify(|reg| { - reg.set_tsel1(trigger.tsel()); - }); - Ok(()) - } - - /// Select a new trigger for CH2 (disables the channel) - pub fn select_trigger_ch2(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { - self.check_channel_configured(Channel::Ch2)?; - unwrap!(self.disable_channel(Channel::Ch2)); - T::regs().cr().modify(|reg| { - reg.set_tsel2(trigger.tsel()); - }); - Ok(()) + fn disable_channel(&mut self) -> Result<(), Error> { + self.set_channel_enable(false) } /// Perform a software trigger on `ch` - pub fn trigger(&mut self, ch: Channel) -> Result<(), Error> { - self.check_channel_configured(ch)?; + fn trigger(&mut self) -> Result<(), Error> { T::regs().swtrigr().write(|reg| { - reg.set_swtrig(ch.index(), true); + reg.set_swtrig(Self::CHANNEL.index(), true); }); Ok(()) } - /// Perform a software trigger on all channels - pub fn trigger_all(&mut self) { - T::regs().swtrigr().write(|reg| { - reg.set_swtrig(Channel::Ch1.index(), true); - reg.set_swtrig(Channel::Ch2.index(), true); - }); - } - /// Set a value to be output by the DAC on trigger. /// /// The `value` is written to the corresponding "data holding register" - pub fn set(&mut self, ch: Channel, value: Value) -> Result<(), Error> { - self.check_channel_configured(ch)?; + fn set(&mut self, value: Value) -> Result<(), Error> { match value { - Value::Bit8(v) => T::regs().dhr8r(ch.index()).write(|reg| reg.set_dhr(v)), - Value::Bit12Left(v) => T::regs().dhr12l(ch.index()).write(|reg| reg.set_dhr(v)), - Value::Bit12Right(v) => T::regs().dhr12r(ch.index()).write(|reg| reg.set_dhr(v)), + Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)), + Value::Bit12Left(v) => T::regs().dhr12l(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)), + Value::Bit12Right(v) => T::regs().dhr12r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)), } Ok(()) } +} + +pub struct Dac<'d, T: Instance, Tx> { + ch1: DacCh1<'d, T, Tx>, + ch2: DacCh2<'d, T, Tx>, +} + +pub struct DacCh1<'d, T: Instance, Tx> { + _peri: PeripheralRef<'d, T>, + dma: PeripheralRef<'d, Tx>, +} + +pub struct DacCh2<'d, T: Instance, Tx> { + phantom: PhantomData<&'d mut T>, + dma: PeripheralRef<'d, Tx>, +} + +impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { + /// Perform initialisation steps for the DAC + pub fn new( + peri: impl Peripheral

+ 'd, + dma: impl Peripheral

+ 'd, + _pin: impl Peripheral

> + 'd, + ) -> Self { + into_ref!(peri, dma); + T::enable(); + T::reset(); + + let mut dac = Self { _peri: peri, dma }; + + // Configure each activated channel. All results can be `unwrap`ed since they + // will only error if the channel is not configured (i.e. ch1, ch2 are false) + dac.set_channel_mode(0).unwrap(); + dac.enable_channel().unwrap(); + dac.set_trigger_enable(true).unwrap(); + + dac + } + /// Select a new trigger for CH1 (disables the channel) + pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { + unwrap!(self.disable_channel()); + T::regs().cr().modify(|reg| { + reg.set_tsel1(trigger.tsel()); + }); + Ok(()) + } /// Write `data` to the DAC CH1 via DMA. /// @@ -276,36 +220,12 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// /// **Important:** Channel 1 has to be configured for the DAC instance! - pub async fn write_ch1(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: Dma, { - self.check_channel_configured(Channel::Ch1)?; - self.write_inner(data, circular, Channel::Ch1).await - } - - /// Write `data` to the DAC CH2 via DMA. - /// - /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. - /// This will configure a circular DMA transfer that periodically outputs the `data`. - /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. - /// - /// **Important:** Channel 2 has to be configured for the DAC instance! - pub async fn write_ch2(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - self.check_channel_configured(Channel::Ch2)?; - self.write_inner(data, circular, Channel::Ch2).await - } - - /// Performs the dma write for the given channel. - /// TODO: Should self be &mut? - async fn write_inner(&self, data_ch1: ValueArray<'_>, circular: bool, channel: Channel) -> Result<(), Error> - where - Tx: Dma, - { - let channel = channel.index(); + let channel = Channel::Ch1.index(); + debug!("Writing to channel {}", channel); // Enable DAC and DMA T::regs().cr().modify(|w| { @@ -313,11 +233,11 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { w.set_dmaen(channel, true); }); - let tx_request = self.txdma.request(); - let dma_channel = &self.txdma; + let tx_request = self.dma.request(); + let dma_channel = &self.dma; // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data_ch1 { + let tx_f = match data { ValueArray::Bit8(buf) => unsafe { Transfer::new_write( dma_channel, @@ -374,6 +294,168 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { } } +impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { + /// Perform initialisation steps for the DAC + pub fn new_ch2( + peri: impl Peripheral

+ 'd, + dma: impl Peripheral

+ 'd, + _pin: impl Peripheral

> + 'd, + ) -> Self { + into_ref!(peri, dma); + T::enable(); + T::reset(); + + let mut dac = Self { + phantom: PhantomData, + dma, + }; + + // Configure each activated channel. All results can be `unwrap`ed since they + // will only error if the channel is not configured (i.e. ch1, ch2 are false) + dac.set_channel_mode(0).unwrap(); + dac.enable_channel().unwrap(); + dac.set_trigger_enable(true).unwrap(); + + dac + } + + /// Select a new trigger for CH1 (disables the channel) + pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { + unwrap!(self.disable_channel()); + T::regs().cr().modify(|reg| { + reg.set_tsel2(trigger.tsel()); + }); + Ok(()) + } + + /// Write `data` to the DAC CH1 via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. + /// + /// **Important:** Channel 1 has to be configured for the DAC instance! + async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + let channel = Channel::Ch2.index(); + debug!("Writing to channel {}", channel); + + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(channel, true); + w.set_dmaen(channel, true); + }); + + let tx_request = self.dma.request(); + let dma_channel = &self.dma; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr8r(channel).as_ptr() as *mut u8, + TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + }, + ) + }, + ValueArray::Bit12Left(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12l(channel).as_ptr() as *mut u16, + TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + }, + ) + }, + ValueArray::Bit12Right(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12r(channel).as_ptr() as *mut u16, + TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + }, + ) + }, + }; + + tx_f.await; + + // finish dma + // TODO: Do we need to check any status registers here? + T::regs().cr().modify(|w| { + // Disable the DAC peripheral + w.set_en(channel, false); + // Disable the DMA. TODO: Is this necessary? + w.set_dmaen(channel, false); + }); + + Ok(()) + } +} + +impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { + pub fn new( + peri: impl Peripheral

+ 'd, + dma_ch1: impl Peripheral

+ 'd, + dma_ch2: impl Peripheral

+ 'd, + _pin_ch1: impl Peripheral

> + 'd, + _pin_ch2: impl Peripheral

> + 'd, + ) -> Self { + into_ref!(peri, dma_ch1, dma_ch2); + T::enable(); + T::reset(); + + let mut dac_ch1 = DacCh1 { + _peri: peri, + dma: dma_ch1, + }; + + let mut dac_ch2 = DacCh2 { + phantom: PhantomData, + dma: dma_ch2, + }; + + // Configure each activated channel. All results can be `unwrap`ed since they + // will only error if the channel is not configured (i.e. ch1, ch2 are false) + dac_ch1.set_channel_mode(0).unwrap(); + dac_ch1.enable_channel().unwrap(); + dac_ch1.set_trigger_enable(true).unwrap(); + + dac_ch1.set_channel_mode(0).unwrap(); + dac_ch1.enable_channel().unwrap(); + dac_ch1.set_trigger_enable(true).unwrap(); + + Self { + ch1: dac_ch1, + ch2: dac_ch2, + } + } +} + +impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> { + const CHANNEL: Channel = Channel::Ch1; +} + +impl<'d, T: Instance, Tx> DacChannel for DacCh2<'d, T, Tx> { + const CHANNEL: Channel = Channel::Ch2; +} + pub(crate) mod sealed { pub trait Instance { fn regs() -> &'static crate::pac::dac::Dac; From df944edeef738590f481d35ee9e2a1afb09601fa Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sun, 25 Jun 2023 10:53:35 +0200 Subject: [PATCH 34/74] fix minor issues with splitting channels etc --- embassy-stm32/src/dac/mod.rs | 46 ++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index e87292b86..3dcd6b771 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -168,9 +168,9 @@ pub trait DacChannel { } } -pub struct Dac<'d, T: Instance, Tx> { - ch1: DacCh1<'d, T, Tx>, - ch2: DacCh2<'d, T, Tx>, +pub struct Dac<'d, T: Instance, TxCh1, TxCh2> { + ch1: DacCh1<'d, T, TxCh1>, + ch2: DacCh2<'d, T, TxCh2>, } pub struct DacCh1<'d, T: Instance, Tx> { @@ -220,7 +220,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// /// **Important:** Channel 1 has to be configured for the DAC instance! - async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: Dma, { @@ -297,11 +297,11 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { /// Perform initialisation steps for the DAC pub fn new_ch2( - peri: impl Peripheral

+ 'd, + _peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, _pin: impl Peripheral

> + 'd, ) -> Self { - into_ref!(peri, dma); + into_ref!(_peri, dma); T::enable(); T::reset(); @@ -335,7 +335,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// /// **Important:** Channel 1 has to be configured for the DAC instance! - async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: Dma, { @@ -409,11 +409,11 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { } } -impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { +impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { pub fn new( peri: impl Peripheral

+ 'd, - dma_ch1: impl Peripheral

+ 'd, - dma_ch2: impl Peripheral

+ 'd, + dma_ch1: impl Peripheral

+ 'd, + dma_ch2: impl Peripheral

+ 'd, _pin_ch1: impl Peripheral

> + 'd, _pin_ch2: impl Peripheral

> + 'd, ) -> Self { @@ -437,15 +437,35 @@ impl<'d, T: Instance, Tx> Dac<'d, T, Tx> { dac_ch1.enable_channel().unwrap(); dac_ch1.set_trigger_enable(true).unwrap(); - dac_ch1.set_channel_mode(0).unwrap(); - dac_ch1.enable_channel().unwrap(); - dac_ch1.set_trigger_enable(true).unwrap(); + dac_ch2.set_channel_mode(0).unwrap(); + dac_ch2.enable_channel().unwrap(); + dac_ch2.set_trigger_enable(true).unwrap(); Self { ch1: dac_ch1, ch2: dac_ch2, } } + + pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) { + (self.ch1, self.ch2) + } + + pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> { + &mut self.ch1 + } + + pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> { + &mut self.ch2 + } + + pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> { + &self.ch1 + } + + pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> { + &self.ch2 + } } impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> { From 8cafaa1f3c9b75e8dba30a7f37f60d9fee6e65e2 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Sun, 25 Jun 2023 11:54:25 +0200 Subject: [PATCH 35/74] add docs, cleanup --- embassy-stm32/src/dac/mod.rs | 322 +++++++++++++++++------------------ 1 file changed, 155 insertions(+), 167 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 3dcd6b771..d95674ff0 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -1,5 +1,6 @@ #![macro_use] +//! Provide access to the STM32 digital-to-analog converter (DAC). use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -11,6 +12,7 @@ use crate::{peripherals, Peripheral}; #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Curstom Errors pub enum Error { UnconfiguredChannel, InvalidValue, @@ -18,6 +20,7 @@ pub enum Error { #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// DAC Channels pub enum Channel { Ch1, Ch2, @@ -34,6 +37,7 @@ impl Channel { #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Trigger sources for CH1 pub enum Ch1Trigger { Tim6, Tim3, @@ -60,6 +64,7 @@ impl Ch1Trigger { #[derive(Debug, Copy, Clone, Eq, PartialEq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +/// Trigger sources for CH2 pub enum Ch2Trigger { Tim6, Tim8, @@ -109,7 +114,7 @@ pub enum ValueArray<'a> { // 12 bit values stored in a u16, right-aligned Bit12Right(&'a [u16]), } - +/// Provide common functions for DAC channels pub trait DacChannel { const CHANNEL: Channel; @@ -157,7 +162,7 @@ pub trait DacChannel { /// Set a value to be output by the DAC on trigger. /// - /// The `value` is written to the corresponding "data holding register" + /// The `value` is written to the corresponding "data holding register". fn set(&mut self, value: Value) -> Result<(), Error> { match value { Value::Bit8(v) => T::regs().dhr8r(Self::CHANNEL.index()).write(|reg| reg.set_dhr(v)), @@ -166,25 +171,51 @@ pub trait DacChannel { } Ok(()) } + + /// Write `data` to the DAC channel via DMA. + /// + /// `circular` sets the DMA to circular mode. + async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: Dma; } +/// Hold two DAC channels +/// +/// Note: This consumes the DAC `Instance` only once, allowing to get both channels simultaneously. +/// +/// # Example for obtaining both DAC channels +/// +/// ```no_run +/// // DMA channels and pins may need to be changed for your controller +/// let (dac_ch1, dac_ch2) = +/// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); +/// ``` pub struct Dac<'d, T: Instance, TxCh1, TxCh2> { ch1: DacCh1<'d, T, TxCh1>, ch2: DacCh2<'d, T, TxCh2>, } +/// DAC CH1 +/// +/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously. pub struct DacCh1<'d, T: Instance, Tx> { + /// To consume T _peri: PeripheralRef<'d, T>, dma: PeripheralRef<'d, Tx>, } +/// DAC CH2 +/// +/// Note: This consumes the DAC `Instance`. Use [`Dac::new`] to get both channels simultaneously. pub struct DacCh2<'d, T: Instance, Tx> { + /// Instead of PeripheralRef to consume T phantom: PhantomData<&'d mut T>, dma: PeripheralRef<'d, Tx>, } impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { - /// Perform initialisation steps for the DAC + /// Obtain DAC CH1 pub fn new( peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, @@ -204,7 +235,8 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { dac } - /// Select a new trigger for CH1 (disables the channel) + + /// Select a new trigger for this channel pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { unwrap!(self.disable_channel()); T::regs().cr().modify(|reg| { @@ -212,91 +244,11 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { }); Ok(()) } - - /// Write `data` to the DAC CH1 via DMA. - /// - /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. - /// This will configure a circular DMA transfer that periodically outputs the `data`. - /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. - /// - /// **Important:** Channel 1 has to be configured for the DAC instance! - pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - let channel = Channel::Ch1.index(); - debug!("Writing to channel {}", channel); - - // Enable DAC and DMA - T::regs().cr().modify(|w| { - w.set_en(channel, true); - w.set_dmaen(channel, true); - }); - - let tx_request = self.dma.request(); - let dma_channel = &self.dma; - - // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data { - ValueArray::Bit8(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr8r(channel).as_ptr() as *mut u8, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - ValueArray::Bit12Left(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12l(channel).as_ptr() as *mut u16, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - ValueArray::Bit12Right(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12r(channel).as_ptr() as *mut u16, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - }; - - tx_f.await; - - // finish dma - // TODO: Do we need to check any status registers here? - T::regs().cr().modify(|w| { - // Disable the DAC peripheral - w.set_en(channel, false); - // Disable the DMA. TODO: Is this necessary? - w.set_dmaen(channel, false); - }); - - Ok(()) - } } impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { - /// Perform initialisation steps for the DAC - pub fn new_ch2( + /// Obtain DAC CH2 + pub fn new( _peri: impl Peripheral

+ 'd, dma: impl Peripheral

+ 'd, _pin: impl Peripheral

> + 'd, @@ -319,7 +271,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { dac } - /// Select a new trigger for CH1 (disables the channel) + /// Select a new trigger for this channel pub fn select_trigger(&mut self, trigger: Ch2Trigger) -> Result<(), Error> { unwrap!(self.disable_channel()); T::regs().cr().modify(|reg| { @@ -327,89 +279,12 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { }); Ok(()) } - - /// Write `data` to the DAC CH1 via DMA. - /// - /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. - /// This will configure a circular DMA transfer that periodically outputs the `data`. - /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. - /// - /// **Important:** Channel 1 has to be configured for the DAC instance! - pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - let channel = Channel::Ch2.index(); - debug!("Writing to channel {}", channel); - - // Enable DAC and DMA - T::regs().cr().modify(|w| { - w.set_en(channel, true); - w.set_dmaen(channel, true); - }); - - let tx_request = self.dma.request(); - let dma_channel = &self.dma; - - // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data { - ValueArray::Bit8(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr8r(channel).as_ptr() as *mut u8, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - ValueArray::Bit12Left(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12l(channel).as_ptr() as *mut u16, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - ValueArray::Bit12Right(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12r(channel).as_ptr() as *mut u16, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - }; - - tx_f.await; - - // finish dma - // TODO: Do we need to check any status registers here? - T::regs().cr().modify(|w| { - // Disable the DAC peripheral - w.set_en(channel, false); - // Disable the DMA. TODO: Is this necessary? - w.set_dmaen(channel, false); - }); - - Ok(()) - } } impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { + /// Create a new DAC instance with both channels. + /// + /// This is used to obtain two independent channels via `split()` for use e.g. with DMA. pub fn new( peri: impl Peripheral

+ 'd, dma_ch1: impl Peripheral

+ 'd, @@ -447,22 +322,27 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { } } + /// Split the DAC into CH1 and CH2 for independent use. pub fn split(self) -> (DacCh1<'d, T, TxCh1>, DacCh2<'d, T, TxCh2>) { (self.ch1, self.ch2) } + /// Get mutable reference to CH1 pub fn ch1_mut(&mut self) -> &mut DacCh1<'d, T, TxCh1> { &mut self.ch1 } + /// Get mutable reference to CH2 pub fn ch2_mut(&mut self) -> &mut DacCh2<'d, T, TxCh2> { &mut self.ch2 } + /// Get reference to CH1 pub fn ch1(&mut self) -> &DacCh1<'d, T, TxCh1> { &self.ch1 } + /// Get reference to CH2 pub fn ch2(&mut self) -> &DacCh2<'d, T, TxCh2> { &self.ch2 } @@ -470,10 +350,117 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> { const CHANNEL: Channel = Channel::Ch1; + + /// Write `data` to the DAC CH1 via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. + /// + /// **Important:** Channel 1 has to be configured for the DAC instance! + async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + write_inner(Self::CHANNEL, &self.dma, data, circular).await + } } impl<'d, T: Instance, Tx> DacChannel for DacCh2<'d, T, Tx> { const CHANNEL: Channel = Channel::Ch2; + + /// Write `data` to the DAC CH2 via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. + /// + /// **Important:** Channel 2 has to be configured for the DAC instance! + async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: Dma, + { + write_inner(Self::CHANNEL, &self.dma, data, circular).await + } +} + +/// Shared utility function to perform the actual DMA config and write. +async fn write_inner( + ch: Channel, + dma: &PeripheralRef<'_, Tx>, + data: ValueArray<'_>, + circular: bool, +) -> Result<(), Error> +where + Tx: Dma, +{ + let channel = ch.index(); + debug!("Writing to channel {}", channel); + + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(channel, true); + w.set_dmaen(channel, true); + }); + + let tx_request = dma.request(); + let dma_channel = dma; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr8r(channel).as_ptr() as *mut u8, + TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + }, + ) + }, + ValueArray::Bit12Left(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12l(channel).as_ptr() as *mut u16, + TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + }, + ) + }, + ValueArray::Bit12Right(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12r(channel).as_ptr() as *mut u16, + TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + }, + ) + }, + }; + + tx_f.await; + + // finish dma + // TODO: Do we need to check any status registers here? + T::regs().cr().modify(|w| { + // Disable the DAC peripheral + w.set_en(channel, false); + // Disable the DMA. TODO: Is this necessary? + w.set_dmaen(channel, false); + }); + + Ok(()) } pub(crate) mod sealed { @@ -485,6 +472,7 @@ pub(crate) mod sealed { pub trait Instance: sealed::Instance + RccPeripheral + 'static {} dma_trait!(Dma, Instance); +/// Marks a pin that can be used with the DAC pub trait DacPin: crate::gpio::Pin + 'static {} foreach_peripheral!( From 018622f607a17037903ef7c5592dda762002f89b Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 25 Jun 2023 11:38:48 -0500 Subject: [PATCH 36/74] stm32/wpan: update example --- examples/stm32wb/src/bin/tl_mbox_mac.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/stm32wb/src/bin/tl_mbox_mac.rs b/examples/stm32wb/src/bin/tl_mbox_mac.rs index afd319a41..f67be4682 100644 --- a/examples/stm32wb/src/bin/tl_mbox_mac.rs +++ b/examples/stm32wb/src/bin/tl_mbox_mac.rs @@ -49,7 +49,9 @@ async fn main(_spawner: Spawner) { let sys_event = mbox.sys_subsystem.read().await; info!("sys event: {}", sys_event.payload()); - mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; + let result = mbox.sys_subsystem.shci_c2_mac_802_15_4_init().await; + info!("initialized mac: {}", result); + // // info!("starting ble..."); // mbox.ble_subsystem.t_write(0x0c, &[]).await; From aa0ab06645446bcb4b99a9407dc9c6c58030d8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 25 Jun 2023 22:24:48 +0200 Subject: [PATCH 37/74] Update darling --- embassy-macros/Cargo.toml | 4 ++-- embassy-macros/src/lib.rs | 37 ++++++++++++++++++++++--------- embassy-macros/src/macros/main.rs | 9 ++++---- embassy-macros/src/macros/task.rs | 5 +++-- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/embassy-macros/Cargo.toml b/embassy-macros/Cargo.toml index 781026b99..3b8fe8b44 100644 --- a/embassy-macros/Cargo.toml +++ b/embassy-macros/Cargo.toml @@ -12,9 +12,9 @@ categories = [ ] [dependencies] -syn = { version = "1.0.76", features = ["full", "extra-traits"] } +syn = { version = "2.0.15", features = ["full", "extra-traits"] } quote = "1.0.9" -darling = "0.13.0" +darling = "0.20.1" proc-macro2 = "1.0.29" [lib] diff --git a/embassy-macros/src/lib.rs b/embassy-macros/src/lib.rs index ba4f13b77..c9d58746a 100644 --- a/embassy-macros/src/lib.rs +++ b/embassy-macros/src/lib.rs @@ -1,11 +1,28 @@ #![doc = include_str!("../README.md")] extern crate proc_macro; +use darling::ast::NestedMeta; use proc_macro::TokenStream; mod macros; mod util; use macros::*; +use syn::parse::{Parse, ParseBuffer}; +use syn::punctuated::Punctuated; +use syn::Token; + +struct Args { + meta: Vec, +} + +impl Parse for Args { + fn parse(input: &ParseBuffer) -> syn::Result { + let meta = Punctuated::::parse_terminated(input)?; + Ok(Args { + meta: meta.into_iter().collect(), + }) + } +} /// Declares an async task that can be run by `embassy-executor`. The optional `pool_size` parameter can be used to specify how /// many concurrent tasks can be spawned (default is 1) for the function. @@ -39,10 +56,10 @@ use macros::*; /// ``` #[proc_macro_attribute] pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as syn::AttributeArgs); + let args = syn::parse_macro_input!(args as Args); let f = syn::parse_macro_input!(item as syn::ItemFn); - task::run(args, f).unwrap_or_else(|x| x).into() + task::run(&args.meta, f).unwrap_or_else(|x| x).into() } /// Creates a new `executor` instance and declares an application entry point for Cortex-M spawning the corresponding function body as an async task. @@ -65,9 +82,9 @@ pub fn task(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as syn::AttributeArgs); + let args = syn::parse_macro_input!(args as Args); let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(args, f, main::cortex_m()).unwrap_or_else(|x| x).into() + main::run(&args.meta, f, main::cortex_m()).unwrap_or_else(|x| x).into() } /// Creates a new `executor` instance and declares an application entry point for RISC-V spawning the corresponding function body as an async task. @@ -100,9 +117,9 @@ pub fn main_cortex_m(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as syn::AttributeArgs); + let args = syn::parse_macro_input!(args as Args); let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(args.clone(), f, main::riscv(args)) + main::run(&args.meta, f, main::riscv(&args.meta)) .unwrap_or_else(|x| x) .into() } @@ -127,9 +144,9 @@ pub fn main_riscv(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as syn::AttributeArgs); + let args = syn::parse_macro_input!(args as Args); let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(args, f, main::std()).unwrap_or_else(|x| x).into() + main::run(&args.meta, f, main::std()).unwrap_or_else(|x| x).into() } /// Creates a new `executor` instance and declares an application entry point for WASM spawning the corresponding function body as an async task. @@ -152,7 +169,7 @@ pub fn main_std(args: TokenStream, item: TokenStream) -> TokenStream { /// ``` #[proc_macro_attribute] pub fn main_wasm(args: TokenStream, item: TokenStream) -> TokenStream { - let args = syn::parse_macro_input!(args as syn::AttributeArgs); + let args = syn::parse_macro_input!(args as Args); let f = syn::parse_macro_input!(item as syn::ItemFn); - main::run(args, f, main::wasm()).unwrap_or_else(|x| x).into() + main::run(&args.meta, f, main::wasm()).unwrap_or_else(|x| x).into() } diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs index 5c099f68a..7c4d55163 100644 --- a/embassy-macros/src/macros/main.rs +++ b/embassy-macros/src/macros/main.rs @@ -1,3 +1,4 @@ +use darling::export::NestedMeta; use darling::FromMeta; use proc_macro2::TokenStream; use quote::quote; @@ -11,8 +12,8 @@ struct Args { entry: Option, } -pub fn riscv(args: syn::AttributeArgs) -> TokenStream { - let maybe_entry = match Args::from_list(&args) { +pub fn riscv(args: &[NestedMeta]) -> TokenStream { + let maybe_entry = match Args::from_list(args) { Ok(args) => args.entry, Err(e) => return e.write_errors(), }; @@ -77,9 +78,9 @@ pub fn std() -> TokenStream { } } -pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Result { +pub fn run(args: &[NestedMeta], f: syn::ItemFn, main: TokenStream) -> Result { #[allow(unused_variables)] - let args = Args::from_list(&args).map_err(|e| e.write_errors())?; + let args = Args::from_list(args).map_err(|e| e.write_errors())?; let fargs = f.sig.inputs.clone(); diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs index 9f30cf43e..8c4bf7265 100644 --- a/embassy-macros/src/macros/task.rs +++ b/embassy-macros/src/macros/task.rs @@ -1,3 +1,4 @@ +use darling::export::NestedMeta; use darling::FromMeta; use proc_macro2::TokenStream; use quote::{format_ident, quote}; @@ -11,8 +12,8 @@ struct Args { pool_size: Option, } -pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result { - let args = Args::from_list(&args).map_err(|e| e.write_errors())?; +pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result { + let args = Args::from_list(args).map_err(|e| e.write_errors())?; let pool_size: usize = args.pool_size.unwrap_or(1); From 2809e926cf8a3a1556c674a7b17c8db4b926f243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 25 Jun 2023 22:32:24 +0200 Subject: [PATCH 38/74] Allow arbitrary expressions as pool_size --- embassy-macros/src/macros/task.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs index 8c4bf7265..1d30434e9 100644 --- a/embassy-macros/src/macros/task.rs +++ b/embassy-macros/src/macros/task.rs @@ -1,21 +1,24 @@ use darling::export::NestedMeta; use darling::FromMeta; -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; -use syn::{parse_quote, ItemFn, ReturnType, Type}; +use syn::{parse_quote, Expr, ExprLit, ItemFn, Lit, LitInt, ReturnType, Type}; use crate::util::ctxt::Ctxt; #[derive(Debug, FromMeta)] struct Args { #[darling(default)] - pool_size: Option, + pool_size: Option, } pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result { let args = Args::from_list(args).map_err(|e| e.write_errors())?; - let pool_size: usize = args.pool_size.unwrap_or(1); + let pool_size = args.pool_size.unwrap_or(Expr::Lit(ExprLit { + attrs: vec![], + lit: Lit::Int(LitInt::new("1", Span::call_site())), + })); let ctxt = Ctxt::new(); @@ -46,10 +49,6 @@ pub fn run(args: &[NestedMeta], f: syn::ItemFn) -> Result Result ::embassy_executor::SpawnToken { type Fut = impl ::core::future::Future + 'static; - static POOL: ::embassy_executor::raw::TaskPool = ::embassy_executor::raw::TaskPool::new(); + const POOL_SIZE: usize = #pool_size; + static POOL: ::embassy_executor::raw::TaskPool = ::embassy_executor::raw::TaskPool::new(); unsafe { POOL._spawn_async_fn(move || #task_inner_ident(#(#arg_names,)*)) } } }; From 12872ce49b3945c1a28ae362f78bcfb334a9eeb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sun, 25 Jun 2023 23:03:14 +0200 Subject: [PATCH 39/74] Modify an example --- examples/nrf52840/src/bin/self_spawn.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/nrf52840/src/bin/self_spawn.rs b/examples/nrf52840/src/bin/self_spawn.rs index 196255a52..31ea6c81e 100644 --- a/examples/nrf52840/src/bin/self_spawn.rs +++ b/examples/nrf52840/src/bin/self_spawn.rs @@ -7,7 +7,11 @@ use embassy_executor::Spawner; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; -#[embassy_executor::task(pool_size = 2)] +mod config { + pub const MY_TASK_POOL_SIZE: usize = 2; +} + +#[embassy_executor::task(pool_size = config::MY_TASK_POOL_SIZE)] async fn my_task(spawner: Spawner, n: u32) { Timer::after(Duration::from_secs(1)).await; info!("Spawning self! {}", n); From e7bc84dda8cc28835d1b7d3574a94b6142e29864 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Mon, 26 Jun 2023 09:42:25 +0200 Subject: [PATCH 40/74] fix issues when DAC2 present, add additional options to DMA (NOT YET WORKING with STM32H7A3ZI) --- embassy-stm32/build.rs | 4 +- embassy-stm32/src/dac/mod.rs | 267 ++++++++++++++++++++--------------- embassy-stm32/src/dma/dma.rs | 26 +++- 3 files changed, 178 insertions(+), 119 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index f7a25743c..7fa4fae45 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -699,8 +699,8 @@ fn main() { // SDMMCv1 uses the same channel for both directions, so just implement for RX (("sdmmc", "RX"), quote!(crate::sdmmc::SdmmcDma)), (("quadspi", "QUADSPI"), quote!(crate::qspi::QuadDma)), - (("dac", "CH1"), quote!(crate::dac::Dma)), - (("dac", "CH2"), quote!(crate::dac::Dma)), + (("dac", "CH1"), quote!(crate::dac::DmaCh1)), + (("dac", "CH2"), quote!(crate::dac::DmaCh2)), ] .into(); diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index d95674ff0..6ead00e15 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -171,13 +171,6 @@ pub trait DacChannel { } Ok(()) } - - /// Write `data` to the DAC channel via DMA. - /// - /// `circular` sets the DMA to circular mode. - async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> - where - Tx: Dma; } /// Hold two DAC channels @@ -244,6 +237,81 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { }); Ok(()) } + + /// Write `data` to the DAC CH1 via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. + /// + /// **Important:** Channel 1 has to be configured for the DAC instance! + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: DmaCh1, + { + let channel = Channel::Ch1.index(); + debug!("Writing to channel {}", channel); + + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(channel, true); + w.set_dmaen(channel, true); + }); + + let tx_request = self.dma.request(); + let dma_channel = &self.dma; + + let tx_options = TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + ..Default::default() + }; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr8r(channel).as_ptr() as *mut u8, + tx_options, + ) + }, + ValueArray::Bit12Left(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12l(channel).as_ptr() as *mut u16, + tx_options, + ) + }, + ValueArray::Bit12Right(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12r(channel).as_ptr() as *mut u16, + tx_options, + ) + }, + }; + + tx_f.await; + + // finish dma + // TODO: Do we need to check any status registers here? + T::regs().cr().modify(|w| { + // Disable the DAC peripheral + w.set_en(channel, false); + // Disable the DMA. TODO: Is this necessary? + w.set_dmaen(channel, false); + }); + + Ok(()) + } } impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { @@ -279,6 +347,81 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { }); Ok(()) } + + /// Write `data` to the DAC CH2 via DMA. + /// + /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. + /// This will configure a circular DMA transfer that periodically outputs the `data`. + /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. + /// + /// **Important:** Channel 2 has to be configured for the DAC instance! + pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> + where + Tx: DmaCh2, + { + let channel = Channel::Ch2.index(); + debug!("Writing to channel {}", channel); + + // Enable DAC and DMA + T::regs().cr().modify(|w| { + w.set_en(channel, true); + w.set_dmaen(channel, true); + }); + + let tx_request = self.dma.request(); + let dma_channel = &self.dma; + + let tx_options = TransferOptions { + circular, + half_transfer_ir: false, + complete_transfer_ir: !circular, + ..Default::default() + }; + + // Initiate the correct type of DMA transfer depending on what data is passed + let tx_f = match data { + ValueArray::Bit8(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr8r(channel).as_ptr() as *mut u8, + tx_options, + ) + }, + ValueArray::Bit12Left(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12l(channel).as_ptr() as *mut u16, + tx_options, + ) + }, + ValueArray::Bit12Right(buf) => unsafe { + Transfer::new_write( + dma_channel, + tx_request, + buf, + T::regs().dhr12r(channel).as_ptr() as *mut u16, + tx_options, + ) + }, + }; + + tx_f.await; + + // finish dma + // TODO: Do we need to check any status registers here? + T::regs().cr().modify(|w| { + // Disable the DAC peripheral + w.set_en(channel, false); + // Disable the DMA. TODO: Is this necessary? + w.set_dmaen(channel, false); + }); + + Ok(()) + } } impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { @@ -350,117 +493,10 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { impl<'d, T: Instance, Tx> DacChannel for DacCh1<'d, T, Tx> { const CHANNEL: Channel = Channel::Ch1; - - /// Write `data` to the DAC CH1 via DMA. - /// - /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. - /// This will configure a circular DMA transfer that periodically outputs the `data`. - /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. - /// - /// **Important:** Channel 1 has to be configured for the DAC instance! - async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - write_inner(Self::CHANNEL, &self.dma, data, circular).await - } } impl<'d, T: Instance, Tx> DacChannel for DacCh2<'d, T, Tx> { const CHANNEL: Channel = Channel::Ch2; - - /// Write `data` to the DAC CH2 via DMA. - /// - /// To prevent delays/glitches when outputting a periodic waveform, the `circular` flag can be set. - /// This will configure a circular DMA transfer that periodically outputs the `data`. - /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. - /// - /// **Important:** Channel 2 has to be configured for the DAC instance! - async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> - where - Tx: Dma, - { - write_inner(Self::CHANNEL, &self.dma, data, circular).await - } -} - -/// Shared utility function to perform the actual DMA config and write. -async fn write_inner( - ch: Channel, - dma: &PeripheralRef<'_, Tx>, - data: ValueArray<'_>, - circular: bool, -) -> Result<(), Error> -where - Tx: Dma, -{ - let channel = ch.index(); - debug!("Writing to channel {}", channel); - - // Enable DAC and DMA - T::regs().cr().modify(|w| { - w.set_en(channel, true); - w.set_dmaen(channel, true); - }); - - let tx_request = dma.request(); - let dma_channel = dma; - - // Initiate the correct type of DMA transfer depending on what data is passed - let tx_f = match data { - ValueArray::Bit8(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr8r(channel).as_ptr() as *mut u8, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - ValueArray::Bit12Left(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12l(channel).as_ptr() as *mut u16, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - ValueArray::Bit12Right(buf) => unsafe { - Transfer::new_write( - dma_channel, - tx_request, - buf, - T::regs().dhr12r(channel).as_ptr() as *mut u16, - TransferOptions { - circular, - half_transfer_ir: false, - complete_transfer_ir: !circular, - }, - ) - }, - }; - - tx_f.await; - - // finish dma - // TODO: Do we need to check any status registers here? - T::regs().cr().modify(|w| { - // Disable the DAC peripheral - w.set_en(channel, false); - // Disable the DMA. TODO: Is this necessary? - w.set_dmaen(channel, false); - }); - - Ok(()) } pub(crate) mod sealed { @@ -470,7 +506,8 @@ pub(crate) mod sealed { } pub trait Instance: sealed::Instance + RccPeripheral + 'static {} -dma_trait!(Dma, Instance); +dma_trait!(DmaCh1, Instance); +dma_trait!(DmaCh2, Instance); /// Marks a pin that can be used with the DAC pub trait DacPin: crate::gpio::Pin + 'static {} diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 8abe541d3..a5f828948 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -29,6 +29,12 @@ pub struct TransferOptions { pub flow_ctrl: FlowControl, /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. pub fifo_threshold: Option, + /// Enable circular DMA + pub circular: bool, + /// Enable half transfer interrupt + pub half_transfer_ir: bool, + /// Enable transfer complete interrupt + pub complete_transfer_ir: bool, } impl Default for TransferOptions { @@ -38,6 +44,9 @@ impl Default for TransferOptions { mburst: Burst::Single, flow_ctrl: FlowControl::Dma, fifo_threshold: None, + circular: false, + half_transfer_ir: false, + complete_transfer_ir: true, } } } @@ -366,13 +375,20 @@ impl<'a, C: Channel> Transfer<'a, C> { }); w.set_pinc(vals::Inc::FIXED); w.set_teie(true); - w.set_tcie(true); + w.set_tcie(options.complete_transfer_ir); + w.set_htie(options.half_transfer_ir); #[cfg(dma_v1)] w.set_trbuff(true); #[cfg(dma_v2)] w.set_chsel(_request); + if options.circular { + w.set_circ(vals::Circ::ENABLED); + debug!("Setting circular mode"); + } else { + w.set_circ(vals::Circ::DISABLED); + } w.set_pburst(options.pburst.into()); w.set_mburst(options.mburst.into()); w.set_pfctrl(options.flow_ctrl.into()); @@ -404,8 +420,14 @@ impl<'a, C: Channel> Transfer<'a, C> { } pub fn is_running(&mut self) -> bool { + //let ch = self.channel.regs().st(self.channel.num()); + //ch.cr().read().en() + let ch = self.channel.regs().st(self.channel.num()); - ch.cr().read().en() + let en = ch.cr().read().en(); + let circular = ch.cr().read().circ() == vals::Circ::ENABLED; + let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; + en && (circular || !tcif) } /// Gets the total remaining transfers for the channel From 64cba950e55dd5cdd7d6ef13c2dbb03825bc6d01 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Jun 2023 01:59:25 +0200 Subject: [PATCH 41/74] Update smoltcp. --- embassy-net/Cargo.toml | 4 ++-- embassy-net/src/device.rs | 3 ++- embassy-net/src/lib.rs | 18 +++++++++++++----- embassy-net/src/udp.rs | 2 +- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 4ac572577..63947c261 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -38,10 +38,10 @@ igmp = ["smoltcp/proto-igmp"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { version = "0.9.0", default-features = false, features = [ +smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "803840b5ccac01cc0f108993958f637835f0adbe", default-features = false, features = [ "socket", "async", -]} +] } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } diff --git a/embassy-net/src/device.rs b/embassy-net/src/device.rs index 583cdc87f..4513c86d3 100644 --- a/embassy-net/src/device.rs +++ b/embassy-net/src/device.rs @@ -51,8 +51,9 @@ where Medium::Ethernet => phy::Medium::Ethernet, #[cfg(feature = "medium-ip")] Medium::Ip => phy::Medium::Ip, + #[allow(unreachable_patterns)] _ => panic!( - "Unsupported medium {:?}. MAke sure to enable it in embassy-net's Cargo features.", + "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.", caps.medium ), }; diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 7e8f765f9..3e83da7aa 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -235,12 +235,19 @@ impl Stack { #[cfg(feature = "medium-ethernet")] let medium = device.capabilities().medium; - let mut iface_cfg = smoltcp::iface::Config::new(); + let hardware_addr = match medium { + #[cfg(feature = "medium-ethernet")] + Medium::Ethernet => HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address())), + #[cfg(feature = "medium-ip")] + Medium::Ip => HardwareAddress::Ip, + #[allow(unreachable_patterns)] + _ => panic!( + "Unsupported medium {:?}. Make sure to enable it in embassy-net's Cargo features.", + medium + ), + }; + let mut iface_cfg = smoltcp::iface::Config::new(hardware_addr); iface_cfg.random_seed = random_seed; - #[cfg(feature = "medium-ethernet")] - if medium == Medium::Ethernet { - iface_cfg.hardware_addr = Some(HardwareAddress::Ethernet(EthernetAddress(device.ethernet_address()))); - } let iface = Interface::new( iface_cfg, @@ -248,6 +255,7 @@ impl Stack { inner: &mut device, cx: None, }, + instant_to_smoltcp(Instant::now()), ); let sockets = SocketSet::new(&mut resources.sockets[..]); diff --git a/embassy-net/src/udp.rs b/embassy-net/src/udp.rs index c9843cfe8..36f8d06f2 100644 --- a/embassy-net/src/udp.rs +++ b/embassy-net/src/udp.rs @@ -104,7 +104,7 @@ impl<'a> UdpSocket<'a> { pub async fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, IpEndpoint), Error> { poll_fn(move |cx| { self.with_mut(|s, _| match s.recv_slice(buf) { - Ok(x) => Poll::Ready(Ok(x)), + Ok((n, meta)) => Poll::Ready(Ok((n, meta.endpoint))), // No data ready Err(udp::RecvError::Exhausted) => { s.register_recv_waker(cx.waker()); From 715bf20c4159f2b11f4edf0cd3b1b999ef19b56b Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 26 Jun 2023 20:13:55 +0200 Subject: [PATCH 42/74] Update smoltcp to 0.10 --- embassy-net/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 63947c261..cef8247eb 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -38,7 +38,7 @@ igmp = ["smoltcp/proto-igmp"] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } -smoltcp = { git = "https://github.com/smoltcp-rs/smoltcp", rev = "803840b5ccac01cc0f108993958f637835f0adbe", default-features = false, features = [ +smoltcp = { version = "0.10.0", default-features = false, features = [ "socket", "async", ] } From 28fb492c402c74add5c650b9d65687816585c923 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 00:42:24 +0200 Subject: [PATCH 43/74] stm32/otg: flush fifos on reconfigure and on ep disable. --- embassy-stm32/src/usb_otg/usb.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 8af5c7bd5..532157e6c 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -540,6 +540,19 @@ impl<'d, T: Instance> Bus<'d, T> { fifo_top <= T::FIFO_DEPTH_WORDS, "FIFO allocations exceeded maximum capacity" ); + + // Flush fifos + r.grstctl().write(|w| { + w.set_rxfflsh(true); + w.set_txfflsh(true); + w.set_txfnum(0x10); + }); + loop { + let x = r.grstctl().read(); + if !x.rxfflsh() && !x.txfflsh() { + break; + } + } } fn configure_endpoints(&mut self) { @@ -744,7 +757,19 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { r.doepctl(ep_addr.index()).modify(|w| { w.set_usbaep(enabled); - }) + }); + + // Flush tx fifo + r.grstctl().write(|w| { + w.set_txfflsh(true); + w.set_txfnum(ep_addr.index() as _); + }); + loop { + let x = r.grstctl().read(); + if !x.txfflsh() { + break; + } + } }); // Wake `Endpoint::wait_enabled()` From a575e40a3503f4bf500b7ee3cadcce44727c7c6f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 02:12:06 +0200 Subject: [PATCH 44/74] stm32/otg: clear NAK bit on endpoint enable. --- embassy-stm32/src/usb_otg/usb.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 532157e6c..1a0d44fd2 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -780,13 +780,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { // cancel transfer if active if !enabled && r.diepctl(ep_addr.index()).read().epena() { r.diepctl(ep_addr.index()).modify(|w| { - w.set_snak(true); + w.set_snak(true); // set NAK w.set_epdis(true); }) } r.diepctl(ep_addr.index()).modify(|w| { w.set_usbaep(enabled); + w.set_cnak(enabled); // clear NAK that might've been set by SNAK above. }) }); From 80407aa930279a7d23bd1295c7703d0d9064aa58 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 02:12:33 +0200 Subject: [PATCH 45/74] stm32/otg: set tx fifo num in IN endpoints on configure. --- embassy-stm32/src/usb_otg/usb.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 1a0d44fd2..b2f7eb852 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -124,7 +124,7 @@ impl interrupt::typelevel::Handler for InterruptHandl } state.ep_in_wakers[ep_num].wake(); - trace!("in ep={} irq val={:b}", ep_num, ep_ints.0); + trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0); } ep_mask >>= 1; @@ -144,7 +144,7 @@ impl interrupt::typelevel::Handler for InterruptHandl // // clear all // r.doepint(ep_num).write_value(ep_ints); // state.ep_out_wakers[ep_num].wake(); - // trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0); + // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0); // } // ep_mask >>= 1; @@ -571,6 +571,8 @@ impl<'d, T: Instance> Bus<'d, T> { w.set_mpsiz(ep.max_packet_size); w.set_eptyp(to_eptyp(ep.ep_type)); w.set_sd0pid_sevnfrm(true); + w.set_txfnum(index as _); + w.set_snak(true); } }); }); From 5e6e18b310ef3c19fd4cdc42fa74dd8ed455e444 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 03:56:09 +0200 Subject: [PATCH 46/74] stm32/usb: add TODO: implement VBUS detection. --- embassy-stm32/src/usb/usb.rs | 95 ++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 2367127e8..01b158b17 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -480,56 +480,57 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { poll_fn(move |cx| { BUS_WAKER.register(cx.waker()); - if self.inited { - let regs = T::regs(); - - if IRQ_RESUME.load(Ordering::Acquire) { - IRQ_RESUME.store(false, Ordering::Relaxed); - return Poll::Ready(Event::Resume); - } - - if IRQ_RESET.load(Ordering::Acquire) { - IRQ_RESET.store(false, Ordering::Relaxed); - - trace!("RESET"); - regs.daddr().write(|w| { - w.set_ef(true); - w.set_add(0); - }); - - regs.epr(0).write(|w| { - w.set_ep_type(EpType::CONTROL); - w.set_stat_rx(Stat::NAK); - w.set_stat_tx(Stat::NAK); - }); - - for i in 1..EP_COUNT { - regs.epr(i).write(|w| { - w.set_ea(i as _); - w.set_ep_type(self.ep_types[i - 1]); - }) - } - - for w in &EP_IN_WAKERS { - w.wake() - } - for w in &EP_OUT_WAKERS { - w.wake() - } - - return Poll::Ready(Event::Reset); - } - - if IRQ_SUSPEND.load(Ordering::Acquire) { - IRQ_SUSPEND.store(false, Ordering::Relaxed); - return Poll::Ready(Event::Suspend); - } - - Poll::Pending - } else { + // TODO: implement VBUS detection. + if !self.inited { self.inited = true; return Poll::Ready(Event::PowerDetected); } + + let regs = T::regs(); + + if IRQ_RESUME.load(Ordering::Acquire) { + IRQ_RESUME.store(false, Ordering::Relaxed); + return Poll::Ready(Event::Resume); + } + + if IRQ_RESET.load(Ordering::Acquire) { + IRQ_RESET.store(false, Ordering::Relaxed); + + trace!("RESET"); + regs.daddr().write(|w| { + w.set_ef(true); + w.set_add(0); + }); + + regs.epr(0).write(|w| { + w.set_ep_type(EpType::CONTROL); + w.set_stat_rx(Stat::NAK); + w.set_stat_tx(Stat::NAK); + }); + + for i in 1..EP_COUNT { + regs.epr(i).write(|w| { + w.set_ea(i as _); + w.set_ep_type(self.ep_types[i - 1]); + }) + } + + for w in &EP_IN_WAKERS { + w.wake() + } + for w in &EP_OUT_WAKERS { + w.wake() + } + + return Poll::Ready(Event::Reset); + } + + if IRQ_SUSPEND.load(Ordering::Acquire) { + IRQ_SUSPEND.store(false, Ordering::Relaxed); + return Poll::Ready(Event::Suspend); + } + + Poll::Pending }) .await } From a2d1e7f02ca8d94c755ced56f1db11646ac2aa72 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 03:56:25 +0200 Subject: [PATCH 47/74] rp/usb: add TODO: implement VBUS detection. --- embassy-rp/src/usb.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs index 1900ab416..b3f3bd927 100644 --- a/embassy-rp/src/usb.rs +++ b/embassy-rp/src/usb.rs @@ -353,6 +353,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { poll_fn(move |cx| { BUS_WAKER.register(cx.waker()); + // TODO: implement VBUS detection. if !self.inited { self.inited = true; return Poll::Ready(Event::PowerDetected); From 219ef5b37a1dff5f6e770da252ec010d55c43257 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 08:42:51 +0200 Subject: [PATCH 48/74] stm32/otg: add VBUS detection. Fixes #1442. --- embassy-stm32/src/usb_otg/usb.rs | 479 +++++++++++++---------- examples/stm32f4/src/bin/usb_ethernet.rs | 4 +- examples/stm32f4/src/bin/usb_serial.rs | 4 +- examples/stm32f7/src/bin/usb_serial.rs | 4 +- examples/stm32h7/src/bin/usb_serial.rs | 4 +- examples/stm32l4/src/bin/usb_serial.rs | 4 +- examples/stm32u5/src/bin/usb_serial.rs | 4 +- 7 files changed, 297 insertions(+), 206 deletions(-) diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index b2f7eb852..6c00c93d6 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; use embassy_hal_common::{into_ref, Peripheral}; use embassy_sync::waitqueue::AtomicWaker; use embassy_usb_driver::{ - self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, - EndpointType, Event, Unsupported, + self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, + EndpointOut, EndpointType, Event, Unsupported, }; use futures::future::poll_fn; @@ -31,7 +31,7 @@ impl interrupt::typelevel::Handler for InterruptHandl let state = T::state(); let ints = r.gintsts().read(); - if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { + if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { // Mask interrupts and notify `Bus` to process them r.gintmsk().write(|_| {}); T::state().bus_waker.wake(); @@ -256,7 +256,34 @@ struct EndpointData { fifo_size_words: u16, } +#[non_exhaustive] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Config { + /// Enable VBUS detection. + /// + /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly. + /// This is done by checkihg whether there is 5V on the VBUS pin or not. + /// + /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional. + /// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume + /// there's power in VBUS, i.e. the USB cable is always plugged in.) + /// + /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and + /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true. + /// + /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a + /// voltage divider. See ST application note AN4879 and the reference manual for more details. + pub vbus_detection: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { vbus_detection: true } + } +} + pub struct Driver<'d, T: Instance> { + config: Config, phantom: PhantomData<&'d mut T>, ep_in: [Option; MAX_EP_COUNT], ep_out: [Option; MAX_EP_COUNT], @@ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> { dp: impl Peripheral

> + 'd, dm: impl Peripheral

> + 'd, ep_out_buffer: &'d mut [u8], + config: Config, ) -> Self { into_ref!(dp, dm); @@ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> { dm.set_as_af(dm.af_num(), AFType::OutputPushPull); Self { + config, phantom: PhantomData, ep_in: [None; MAX_EP_COUNT], ep_out: [None; MAX_EP_COUNT], @@ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> { ulpi_d6: impl Peripheral

> + 'd, ulpi_d7: impl Peripheral

> + 'd, ep_out_buffer: &'d mut [u8], + config: Config, ) -> Self { assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); @@ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> { ); Self { + config, phantom: PhantomData, ep_in: [None; MAX_EP_COUNT], ep_out: [None; MAX_EP_COUNT], @@ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { ( Bus { + config: self.config, phantom: PhantomData, ep_in: self.ep_in, ep_out: self.ep_out, phy_type: self.phy_type, - enabled: false, + inited: false, }, ControlPipe { _phantom: PhantomData, @@ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { } pub struct Bus<'d, T: Instance> { + config: Config, phantom: PhantomData<&'d mut T>, ep_in: [Option; MAX_EP_COUNT], ep_out: [Option; MAX_EP_COUNT], phy_type: PhyType, - enabled: bool, + inited: bool, } impl<'d, T: Instance> Bus<'d, T> { @@ -498,11 +531,202 @@ impl<'d, T: Instance> Bus<'d, T> { w.set_iepint(true); w.set_oepint(true); w.set_rxflvlm(true); + w.set_srqim(true); + w.set_otgint(true); }); } } impl<'d, T: Instance> Bus<'d, T> { + fn init(&mut self) { + #[cfg(stm32l4)] + { + crate::peripherals::PWR::enable(); + critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); + } + + #[cfg(stm32f7)] + { + // Enable ULPI clock if external PHY is used + let ulpien = !self.phy_type.internal(); + critical_section::with(|_| { + crate::pac::RCC.ahb1enr().modify(|w| { + if T::HIGH_SPEED { + w.set_usb_otg_hsulpien(ulpien); + } else { + w.set_usb_otg_hsen(ulpien); + } + }); + + // Low power mode + crate::pac::RCC.ahb1lpenr().modify(|w| { + if T::HIGH_SPEED { + w.set_usb_otg_hsulpilpen(ulpien); + } else { + w.set_usb_otg_hslpen(ulpien); + } + }); + }); + } + + #[cfg(stm32h7)] + { + // If true, VDD33USB is generated by internal regulator from VDD50USB + // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) + // TODO: unhardcode + let internal_regulator = false; + + // Enable USB power + critical_section::with(|_| { + crate::pac::PWR.cr3().modify(|w| { + w.set_usb33den(true); + w.set_usbregen(internal_regulator); + }) + }); + + // Wait for USB power to stabilize + while !crate::pac::PWR.cr3().read().usb33rdy() {} + + // Use internal 48MHz HSI clock. Should be enabled in RCC by default. + critical_section::with(|_| { + crate::pac::RCC + .d2ccip2r() + .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) + }); + + // Enable ULPI clock if external PHY is used + let ulpien = !self.phy_type.internal(); + critical_section::with(|_| { + crate::pac::RCC.ahb1enr().modify(|w| { + if T::HIGH_SPEED { + w.set_usb_otg_hs_ulpien(ulpien); + } else { + w.set_usb_otg_fs_ulpien(ulpien); + } + }); + crate::pac::RCC.ahb1lpenr().modify(|w| { + if T::HIGH_SPEED { + w.set_usb_otg_hs_ulpilpen(ulpien); + } else { + w.set_usb_otg_fs_ulpilpen(ulpien); + } + }); + }); + } + + #[cfg(stm32u5)] + { + // Enable USB power + critical_section::with(|_| { + crate::pac::RCC.ahb3enr().modify(|w| { + w.set_pwren(true); + }); + cortex_m::asm::delay(2); + + crate::pac::PWR.svmcr().modify(|w| { + w.set_usv(true); + w.set_uvmen(true); + }); + }); + + // Wait for USB power to stabilize + while !crate::pac::PWR.svmsr().read().vddusbrdy() {} + + // Select HSI48 as USB clock source. + critical_section::with(|_| { + crate::pac::RCC.ccipr1().modify(|w| { + w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); + }) + }); + } + + ::enable(); + ::reset(); + + T::Interrupt::unpend(); + unsafe { T::Interrupt::enable() }; + + let r = T::regs(); + let core_id = r.cid().read().0; + info!("Core id {:08x}", core_id); + + // Wait for AHB ready. + while !r.grstctl().read().ahbidl() {} + + // Configure as device. + r.gusbcfg().write(|w| { + // Force device mode + w.set_fdmod(true); + // Enable internal full-speed PHY + w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); + }); + + // Configuring Vbus sense and SOF output + match core_id { + 0x0000_1200 | 0x0000_1100 => { + assert!(self.phy_type != PhyType::InternalHighSpeed); + + r.gccfg_v1().modify(|w| { + // Enable internal full-speed PHY, logic is inverted + w.set_pwrdwn(self.phy_type.internal()); + }); + + // F429-like chips have the GCCFG.NOVBUSSENS bit + r.gccfg_v1().modify(|w| { + w.set_novbussens(!self.config.vbus_detection); + w.set_vbusasen(false); + w.set_vbusbsen(self.config.vbus_detection); + w.set_sofouten(false); + }); + } + 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { + // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning + r.gccfg_v2().modify(|w| { + // Enable internal full-speed PHY, logic is inverted + w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); + w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); + }); + + r.gccfg_v2().modify(|w| { + w.set_vbden(self.config.vbus_detection); + }); + + // Force B-peripheral session + r.gotgctl().modify(|w| { + w.set_bvaloen(!self.config.vbus_detection); + w.set_bvaloval(true); + }); + } + _ => unimplemented!("Unknown USB core id {:X}", core_id), + } + + // Soft disconnect. + r.dctl().write(|w| w.set_sdis(true)); + + // Set speed. + r.dcfg().write(|w| { + w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); + w.set_dspd(self.phy_type.to_dspd()); + }); + + // Unmask transfer complete EP interrupt + r.diepmsk().write(|w| { + w.set_xfrcm(true); + }); + + // Unmask and clear core interrupts + Bus::::restore_irqs(); + r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); + + // Unmask global interrupt + r.gahbcfg().write(|w| { + w.set_gint(true); // unmask global interrupt + }); + + // Connect + r.dctl().write(|w| w.set_sdis(false)); + } + fn init_fifo(&mut self) { trace!("init_fifo"); @@ -613,6 +837,13 @@ impl<'d, T: Instance> Bus<'d, T> { }); } + fn disable_all_endpoints(&mut self) { + for i in 0..T::ENDPOINT_COUNT { + self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false); + self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false); + } + } + fn disable(&mut self) { T::Interrupt::disable(); @@ -627,9 +858,14 @@ impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { async fn poll(&mut self) -> Event { poll_fn(move |cx| { - // TODO: implement VBUS detection - if !self.enabled { - return Poll::Ready(Event::PowerDetected); + if !self.inited { + self.init(); + self.inited = true; + + // If no vbus detection, just return a single PowerDetected event at startup. + if !self.config.vbus_detection { + return Poll::Ready(Event::PowerDetected); + } } let r = T::regs(); @@ -637,6 +873,32 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { T::state().bus_waker.register(cx.waker()); let ints = r.gintsts().read(); + + if ints.srqint() { + trace!("vbus detected"); + + r.gintsts().write(|w| w.set_srqint(true)); // clear + Self::restore_irqs(); + + if self.config.vbus_detection { + return Poll::Ready(Event::PowerDetected); + } + } + + if ints.otgint() { + let otgints = r.gotgint().read(); + r.gotgint().write_value(otgints); // clear all + Self::restore_irqs(); + + if otgints.sedet() { + trace!("vbus removed"); + if self.config.vbus_detection { + self.disable_all_endpoints(); + return Poll::Ready(Event::PowerRemoved); + } + } + } + if ints.usbrst() { trace!("reset"); @@ -801,203 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { async fn enable(&mut self) { trace!("enable"); - - #[cfg(stm32l4)] - { - crate::peripherals::PWR::enable(); - critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); - } - - #[cfg(stm32f7)] - { - // Enable ULPI clock if external PHY is used - let ulpien = !self.phy_type.internal(); - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| { - if T::HIGH_SPEED { - w.set_usb_otg_hsulpien(ulpien); - } else { - w.set_usb_otg_hsen(ulpien); - } - }); - - // Low power mode - crate::pac::RCC.ahb1lpenr().modify(|w| { - if T::HIGH_SPEED { - w.set_usb_otg_hsulpilpen(ulpien); - } else { - w.set_usb_otg_hslpen(ulpien); - } - }); - }); - } - - #[cfg(stm32h7)] - { - // If true, VDD33USB is generated by internal regulator from VDD50USB - // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) - // TODO: unhardcode - let internal_regulator = false; - - // Enable USB power - critical_section::with(|_| { - crate::pac::PWR.cr3().modify(|w| { - w.set_usb33den(true); - w.set_usbregen(internal_regulator); - }) - }); - - // Wait for USB power to stabilize - while !crate::pac::PWR.cr3().read().usb33rdy() {} - - // Use internal 48MHz HSI clock. Should be enabled in RCC by default. - critical_section::with(|_| { - crate::pac::RCC - .d2ccip2r() - .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) - }); - - // Enable ULPI clock if external PHY is used - let ulpien = !self.phy_type.internal(); - critical_section::with(|_| { - crate::pac::RCC.ahb1enr().modify(|w| { - if T::HIGH_SPEED { - w.set_usb_otg_hs_ulpien(ulpien); - } else { - w.set_usb_otg_fs_ulpien(ulpien); - } - }); - crate::pac::RCC.ahb1lpenr().modify(|w| { - if T::HIGH_SPEED { - w.set_usb_otg_hs_ulpilpen(ulpien); - } else { - w.set_usb_otg_fs_ulpilpen(ulpien); - } - }); - }); - } - - #[cfg(stm32u5)] - { - // Enable USB power - critical_section::with(|_| { - crate::pac::RCC.ahb3enr().modify(|w| { - w.set_pwren(true); - }); - cortex_m::asm::delay(2); - - crate::pac::PWR.svmcr().modify(|w| { - w.set_usv(true); - w.set_uvmen(true); - }); - }); - - // Wait for USB power to stabilize - while !crate::pac::PWR.svmsr().read().vddusbrdy() {} - - // Select HSI48 as USB clock source. - critical_section::with(|_| { - crate::pac::RCC.ccipr1().modify(|w| { - w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); - }) - }); - } - - ::enable(); - ::reset(); - - T::Interrupt::unpend(); - unsafe { T::Interrupt::enable() }; - - let r = T::regs(); - let core_id = r.cid().read().0; - info!("Core id {:08x}", core_id); - - // Wait for AHB ready. - while !r.grstctl().read().ahbidl() {} - - // Configure as device. - r.gusbcfg().write(|w| { - // Force device mode - w.set_fdmod(true); - // Enable internal full-speed PHY - w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); - }); - - // Configuring Vbus sense and SOF output - match core_id { - 0x0000_1200 | 0x0000_1100 => { - assert!(self.phy_type != PhyType::InternalHighSpeed); - - r.gccfg_v1().modify(|w| { - // Enable internal full-speed PHY, logic is inverted - w.set_pwrdwn(self.phy_type.internal()); - }); - - // F429-like chips have the GCCFG.NOVBUSSENS bit - r.gccfg_v1().modify(|w| { - w.set_novbussens(true); - w.set_vbusasen(false); - w.set_vbusbsen(false); - w.set_sofouten(false); - }); - } - 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { - // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning - r.gccfg_v2().modify(|w| { - // Enable internal full-speed PHY, logic is inverted - w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); - w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); - }); - - r.gccfg_v2().modify(|w| { - w.set_vbden(false); - }); - - // Force B-peripheral session - r.gotgctl().modify(|w| { - w.set_bvaloen(true); - w.set_bvaloval(true); - }); - } - _ => unimplemented!("Unknown USB core id {:X}", core_id), - } - - // Soft disconnect. - r.dctl().write(|w| w.set_sdis(true)); - - // Set speed. - r.dcfg().write(|w| { - w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); - w.set_dspd(self.phy_type.to_dspd()); - }); - - // Unmask transfer complete EP interrupt - r.diepmsk().write(|w| { - w.set_xfrcm(true); - }); - - // Unmask and clear core interrupts - Bus::::restore_irqs(); - r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); - - // Unmask global interrupt - r.gahbcfg().write(|w| { - w.set_gint(true); // unmask global interrupt - }); - - // Connect - r.dctl().write(|w| w.set_sdis(false)); - - self.enabled = true; + // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb } async fn disable(&mut self) { trace!("disable"); - Bus::disable(self); - - self.enabled = false; + // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb + //Bus::disable(self); } async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { @@ -1140,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { state.ep_in_wakers[index].register(cx.waker()); let diepctl = r.diepctl(index).read(); + let dtxfsts = r.dtxfsts(index).read(); + info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0); if !diepctl.usbaep() { + trace!("write ep={:?} wait for prev: error disabled", self.info.addr); Poll::Ready(Err(EndpointError::Disabled)) } else if !diepctl.epena() { + trace!("write ep={:?} wait for prev: ready", self.info.addr); Poll::Ready(Ok(())) } else { + trace!("write ep={:?} wait for prev: pending", self.info.addr); Poll::Pending } }) @@ -1169,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { Poll::Pending } else { + trace!("write ep={:?} wait for fifo: ready", self.info.addr); Poll::Ready(()) } }) diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs index 953d99a45..b1f01417c 100644 --- a/examples/stm32f4/src/bin/usb_ethernet.rs +++ b/examples/stm32f4/src/bin/usb_ethernet.rs @@ -52,7 +52,9 @@ async fn main(spawner: Spawner) { // Create the driver, from the HAL. let ep_out_buffer = &mut make_static!([0; 256])[..]; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs index f8f5940a7..4ff6452ef 100644 --- a/examples/stm32f4/src/bin/usb_serial.rs +++ b/examples/stm32f4/src/bin/usb_serial.rs @@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs index 763309ce2..a2c76178b 100644 --- a/examples/stm32f7/src/bin/usb_serial.rs +++ b/examples/stm32f7/src/bin/usb_serial.rs @@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs index c622f19f7..97291f60c 100644 --- a/examples/stm32h7/src/bin/usb_serial.rs +++ b/examples/stm32h7/src/bin/usb_serial.rs @@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs index 80811a43e..410d6891b 100644 --- a/examples/stm32l4/src/bin/usb_serial.rs +++ b/examples/stm32l4/src/bin/usb_serial.rs @@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs index f36daf91b..9e47fb18a 100644 --- a/examples/stm32u5/src/bin/usb_serial.rs +++ b/examples/stm32u5/src/bin/usb_serial.rs @@ -31,7 +31,9 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; - let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); + let mut config = embassy_stm32::usb_otg::Config::default(); + config.vbus_detection = true; + let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); // Create embassy-usb Config let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); From afec1b439bb40b769c8ccd1c1b19d58edd034c3d Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Tue, 27 Jun 2023 18:17:51 +0200 Subject: [PATCH 49/74] feature-gate dma write, make trigger not return a result --- embassy-stm32/src/dac/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 6ead00e15..3e48d558a 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -153,11 +153,10 @@ pub trait DacChannel { } /// Perform a software trigger on `ch` - fn trigger(&mut self) -> Result<(), Error> { + fn trigger(&mut self) { T::regs().swtrigr().write(|reg| { reg.set_swtrig(Self::CHANNEL.index(), true); }); - Ok(()) } /// Set a value to be output by the DAC on trigger. @@ -230,6 +229,8 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { } /// Select a new trigger for this channel + /// + /// **Important**: This disables the channel! pub fn select_trigger(&mut self, trigger: Ch1Trigger) -> Result<(), Error> { unwrap!(self.disable_channel()); T::regs().cr().modify(|reg| { @@ -245,6 +246,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// /// **Important:** Channel 1 has to be configured for the DAC instance! + #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though) pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: DmaCh1, @@ -355,6 +357,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { /// Note that for performance reasons in circular mode the transfer complete interrupt is disabled. /// /// **Important:** Channel 2 has to be configured for the DAC instance! + #[cfg(all(bdma, not(dma)))] // It currently only works with BDMA-only chips (DMA should theoretically work though) pub async fn write(&mut self, data: ValueArray<'_>, circular: bool) -> Result<(), Error> where Tx: DmaCh2, From 56dd22f0ac49be2b824e88026d38b69843b56972 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Tue, 27 Jun 2023 21:23:47 +0200 Subject: [PATCH 50/74] feature-gate set_channel_mode, undo dma.rs changes --- embassy-stm32/src/dac/mod.rs | 17 ++++++++++------- embassy-stm32/src/dma/dma.rs | 18 +----------------- 2 files changed, 11 insertions(+), 24 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 3e48d558a..b53083524 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -127,6 +127,7 @@ pub trait DacChannel { } /// Set mode register of the given channel + #[cfg(dac_v2)] fn set_channel_mode(&mut self, val: u8) -> Result<(), Error> { T::regs().mcr().modify(|reg| { reg.set_mode(Self::CHANNEL.index(), val); @@ -221,6 +222,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { // Configure each activated channel. All results can be `unwrap`ed since they // will only error if the channel is not configured (i.e. ch1, ch2 are false) + #[cfg(dac_v2)] dac.set_channel_mode(0).unwrap(); dac.enable_channel().unwrap(); dac.set_trigger_enable(true).unwrap(); @@ -334,6 +336,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { // Configure each activated channel. All results can be `unwrap`ed since they // will only error if the channel is not configured (i.e. ch1, ch2 are false) + #[cfg(dac_v2)] dac.set_channel_mode(0).unwrap(); dac.enable_channel().unwrap(); dac.set_trigger_enable(true).unwrap(); @@ -454,10 +457,12 @@ impl<'d, T: Instance, TxCh1, TxCh2> Dac<'d, T, TxCh1, TxCh2> { // Configure each activated channel. All results can be `unwrap`ed since they // will only error if the channel is not configured (i.e. ch1, ch2 are false) + #[cfg(dac_v2)] dac_ch1.set_channel_mode(0).unwrap(); dac_ch1.enable_channel().unwrap(); dac_ch1.set_trigger_enable(true).unwrap(); + #[cfg(dac_v2)] dac_ch2.set_channel_mode(0).unwrap(); dac_ch2.enable_channel().unwrap(); dac_ch2.set_trigger_enable(true).unwrap(); @@ -521,27 +526,25 @@ foreach_peripheral!( #[cfg(rcc_h7)] impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { fn frequency() -> crate::time::Hertz { - critical_section::with(|_| unsafe { - crate::rcc::get_freqs().apb1 - }) + critical_section::with(|_| crate::rcc::get_freqs().apb1) } fn reset() { - critical_section::with(|_| unsafe { + critical_section::with(|_| { crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true)); crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false)); }) } fn enable() { - critical_section::with(|_| unsafe { + critical_section::with(|_| { crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true)); }) } fn disable() { - critical_section::with(|_| unsafe { - crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)); + critical_section::with(|_| { + crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false)) }) } } diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index a5f828948..0b7b60789 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -29,12 +29,6 @@ pub struct TransferOptions { pub flow_ctrl: FlowControl, /// FIFO threshold for DMA FIFO mode. If none, direct mode is used. pub fifo_threshold: Option, - /// Enable circular DMA - pub circular: bool, - /// Enable half transfer interrupt - pub half_transfer_ir: bool, - /// Enable transfer complete interrupt - pub complete_transfer_ir: bool, } impl Default for TransferOptions { @@ -44,9 +38,6 @@ impl Default for TransferOptions { mburst: Burst::Single, flow_ctrl: FlowControl::Dma, fifo_threshold: None, - circular: false, - half_transfer_ir: false, - complete_transfer_ir: true, } } } @@ -375,20 +366,13 @@ impl<'a, C: Channel> Transfer<'a, C> { }); w.set_pinc(vals::Inc::FIXED); w.set_teie(true); - w.set_tcie(options.complete_transfer_ir); - w.set_htie(options.half_transfer_ir); + w.set_tcie(true); #[cfg(dma_v1)] w.set_trbuff(true); #[cfg(dma_v2)] w.set_chsel(_request); - if options.circular { - w.set_circ(vals::Circ::ENABLED); - debug!("Setting circular mode"); - } else { - w.set_circ(vals::Circ::DISABLED); - } w.set_pburst(options.pburst.into()); w.set_mburst(options.mburst.into()); w.set_pfctrl(options.flow_ctrl.into()); From 60c54107ce5cc50f9d9365297d31973d96f00021 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Tue, 27 Jun 2023 21:58:56 +0200 Subject: [PATCH 51/74] fix sdmmc bdma transferconfig fields --- embassy-stm32/src/sdmmc/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/sdmmc/mod.rs b/embassy-stm32/src/sdmmc/mod.rs index 80a336a48..698292bff 100644 --- a/embassy-stm32/src/sdmmc/mod.rs +++ b/embassy-stm32/src/sdmmc/mod.rs @@ -227,7 +227,11 @@ const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOp fifo_threshold: Some(crate::dma::FifoThreshold::Full), }; #[cfg(all(sdmmc_v1, not(dma)))] -const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions {}; +const DMA_TRANSFER_OPTIONS: crate::dma::TransferOptions = crate::dma::TransferOptions { + circular: false, + half_transfer_ir: false, + complete_transfer_ir: true, +}; /// SDMMC configuration /// From 9c81d6315500b236adc7634d2d2d6ef776f984eb Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Tue, 27 Jun 2023 22:33:17 +0200 Subject: [PATCH 52/74] fix warnings --- embassy-stm32/src/dac/mod.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index b53083524..6686a387a 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -5,7 +5,6 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; -use crate::dma::{Transfer, TransferOptions}; use crate::pac::dac; use crate::rcc::RccPeripheral; use crate::{peripherals, Peripheral}; @@ -195,6 +194,7 @@ pub struct Dac<'d, T: Instance, TxCh1, TxCh2> { pub struct DacCh1<'d, T: Instance, Tx> { /// To consume T _peri: PeripheralRef<'d, T>, + #[allow(unused)] // For chips whose DMA is not (yet) supported dma: PeripheralRef<'d, Tx>, } @@ -204,6 +204,7 @@ pub struct DacCh1<'d, T: Instance, Tx> { pub struct DacCh2<'d, T: Instance, Tx> { /// Instead of PeripheralRef to consume T phantom: PhantomData<&'d mut T>, + #[allow(unused)] // For chips whose DMA is not (yet) supported dma: PeripheralRef<'d, Tx>, } @@ -265,7 +266,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { let tx_request = self.dma.request(); let dma_channel = &self.dma; - let tx_options = TransferOptions { + let tx_options = crate::dma::TransferOptions { circular, half_transfer_ir: false, complete_transfer_ir: !circular, @@ -275,7 +276,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { // Initiate the correct type of DMA transfer depending on what data is passed let tx_f = match data { ValueArray::Bit8(buf) => unsafe { - Transfer::new_write( + crate::dma::Transfer::new_write( dma_channel, tx_request, buf, @@ -284,7 +285,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { ) }, ValueArray::Bit12Left(buf) => unsafe { - Transfer::new_write( + crate::dma::Transfer::new_write( dma_channel, tx_request, buf, @@ -293,7 +294,7 @@ impl<'d, T: Instance, Tx> DacCh1<'d, T, Tx> { ) }, ValueArray::Bit12Right(buf) => unsafe { - Transfer::new_write( + crate::dma::Transfer::new_write( dma_channel, tx_request, buf, @@ -377,7 +378,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { let tx_request = self.dma.request(); let dma_channel = &self.dma; - let tx_options = TransferOptions { + let tx_options = crate::dma::TransferOptions { circular, half_transfer_ir: false, complete_transfer_ir: !circular, @@ -387,7 +388,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { // Initiate the correct type of DMA transfer depending on what data is passed let tx_f = match data { ValueArray::Bit8(buf) => unsafe { - Transfer::new_write( + crate::dma::Transfer::new_write( dma_channel, tx_request, buf, @@ -396,7 +397,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { ) }, ValueArray::Bit12Left(buf) => unsafe { - Transfer::new_write( + crate::dma::Transfer::new_write( dma_channel, tx_request, buf, @@ -405,7 +406,7 @@ impl<'d, T: Instance, Tx> DacCh2<'d, T, Tx> { ) }, ValueArray::Bit12Right(buf) => unsafe { - Transfer::new_write( + crate::dma::Transfer::new_write( dma_channel, tx_request, buf, @@ -526,7 +527,7 @@ foreach_peripheral!( #[cfg(rcc_h7)] impl crate::rcc::sealed::RccPeripheral for peripherals::$inst { fn frequency() -> crate::time::Hertz { - critical_section::with(|_| crate::rcc::get_freqs().apb1) + critical_section::with(|_| unsafe { crate::rcc::get_freqs().apb1 }) } fn reset() { From f5ca687e9bbeb81ce24f56db6cd7defbcb5c2db2 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 23:49:12 +0200 Subject: [PATCH 53/74] sync/pipe: fix doc typos. --- embassy-sync/src/pipe.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs index db6ebb08b..13bf4ef01 100644 --- a/embassy-sync/src/pipe.rs +++ b/embassy-sync/src/pipe.rs @@ -282,7 +282,7 @@ where /// returns the amount of bytes written. /// /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full, - /// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that + /// this method will wait until it isn't. See [`try_write`](Self::try_write) for a variant that /// returns an error instead of waiting. /// /// It is not guaranteed that all bytes in the buffer are written, even if there's enough @@ -319,7 +319,7 @@ where /// returns the amount of bytes read. /// /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty, - /// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that + /// this method will wait until it isn't. See [`try_read`](Self::try_read) for a variant that /// returns an error instead of waiting. /// /// It is not guaranteed that all bytes in the buffer are read, even if there's enough From ed493be869fa653dc14d31060375e17e2469ce11 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 27 Jun 2023 23:49:30 +0200 Subject: [PATCH 54/74] stm32: update metapac, includes fix for OTG with 9 endpoints (H7) --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/rcc/l0.rs | 4 ++-- examples/stm32g4/src/bin/usb_serial.rs | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3d9ee8261..f15c6d0b7 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = "10" +stm32-metapac = "11" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} +stm32-metapac = { version = "11", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index 42a481a74..d53b61069 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -1,7 +1,7 @@ use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::RCC; #[cfg(crs)] -use crate::pac::{CRS, SYSCFG}; +use crate::pac::{crs, CRS, SYSCFG}; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) { CRS.cfgr().write(|w| // Select LSE as synchronization source - w.set_syncsrc(0b01)); + w.set_syncsrc(crs::vals::Syncsrc::LSE)); CRS.cr().modify(|w| { w.set_autotrimen(true); w.set_cen(true); diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index c111a9787..289d0ed86 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -38,7 +38,9 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(config); info!("Hello World!"); - pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); + pac::RCC.ccipr().write(|w| { + w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK); + }); let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); From 91c31d5e437b510af3c535f5e597881042563496 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:58:25 +0200 Subject: [PATCH 55/74] Update DAC examples, add DAC + DMA example --- embassy-stm32/src/dac/mod.rs | 2 +- examples/stm32f4/src/bin/dac.rs | 9 +- examples/stm32h7/src/bin/dac.rs | 9 +- examples/stm32l4/Cargo.toml | 2 + examples/stm32l4/src/bin/dac.rs | 16 ++- examples/stm32l4/src/bin/dac_dma.rs | 148 ++++++++++++++++++++++++++++ 6 files changed, 167 insertions(+), 19 deletions(-) create mode 100644 examples/stm32l4/src/bin/dac_dma.rs diff --git a/embassy-stm32/src/dac/mod.rs b/embassy-stm32/src/dac/mod.rs index 6686a387a..1dc13949d 100644 --- a/embassy-stm32/src/dac/mod.rs +++ b/embassy-stm32/src/dac/mod.rs @@ -178,7 +178,7 @@ pub trait DacChannel { /// /// # Example for obtaining both DAC channels /// -/// ```no_run +/// ```ignore /// // DMA channels and pins may need to be changed for your controller /// let (dac_ch1, dac_ch2) = /// embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); diff --git a/examples/stm32f4/src/bin/dac.rs b/examples/stm32f4/src/bin/dac.rs index d97ae7082..3a6216712 100644 --- a/examples/stm32f4/src/bin/dac.rs +++ b/examples/stm32f4/src/bin/dac.rs @@ -4,7 +4,8 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::dac::{Channel, Dac, Value}; +use embassy_stm32::dac::{DacCh1, DacChannel, Value}; +use embassy_stm32::dma::NoDma; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,12 +13,12 @@ async fn main(_spawner: Spawner) -> ! { let p = embassy_stm32::init(Default::default()); info!("Hello World, dude!"); - let mut dac = Dac::new_1ch(p.DAC, p.PA4); + let mut dac = DacCh1::new(p.DAC, NoDma, p.PA4); loop { for v in 0..=255 { - unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); - unwrap!(dac.trigger(Channel::Ch1)); + unwrap!(dac.set(Value::Bit8(to_sine_wave(v)))); + dac.trigger(); } } } diff --git a/examples/stm32h7/src/bin/dac.rs b/examples/stm32h7/src/bin/dac.rs index f12716370..586b4154b 100644 --- a/examples/stm32h7/src/bin/dac.rs +++ b/examples/stm32h7/src/bin/dac.rs @@ -4,7 +4,8 @@ use cortex_m_rt::entry; use defmt::*; -use embassy_stm32::dac::{Channel, Dac, Value}; +use embassy_stm32::dac::{DacCh1, DacChannel, Value}; +use embassy_stm32::dma::NoDma; use embassy_stm32::time::mhz; use embassy_stm32::Config; use {defmt_rtt as _, panic_probe as _}; @@ -19,12 +20,12 @@ fn main() -> ! { config.rcc.pll1.q_ck = Some(mhz(100)); let p = embassy_stm32::init(config); - let mut dac = Dac::new_1ch(p.DAC1, p.PA4); + let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); loop { for v in 0..=255 { - unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); - unwrap!(dac.trigger(Channel::Ch1)); + unwrap!(dac.set(Value::Bit8(to_sine_wave(v)))); + dac.trigger(); } } } diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index 3bb473ef5..d2d228282 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -25,3 +25,5 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.7.5", default-features = false } micromath = "2.0.0" + +static_cell = "1.0.0" diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index a36ed5d90..8aad27646 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs @@ -3,26 +3,22 @@ #![feature(type_alias_impl_trait)] use defmt::*; -use embassy_stm32::dac::{Channel, Dac, Value}; +use embassy_stm32::dac::{DacCh1, DacChannel, Value}; +use embassy_stm32::dma::NoDma; use embassy_stm32::pac; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] fn main() -> ! { + let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - pac::RCC.apb1enr1().modify(|w| { - w.set_dac1en(true); - }); - - let p = embassy_stm32::init(Default::default()); - - let mut dac = Dac::new_1ch(p.DAC1, p.PA4); + let mut dac = DacCh1::new(p.DAC1, NoDma, p.PA4); loop { for v in 0..=255 { - unwrap!(dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)))); - unwrap!(dac.trigger(Channel::Ch1)); + unwrap!(dac.set(Value::Bit8(to_sine_wave(v)))); + dac.trigger(); } } } diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs new file mode 100644 index 000000000..81e6a58e4 --- /dev/null +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -0,0 +1,148 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::dac::{DacChannel, ValueArray}; +use embassy_stm32::pac::timer::vals::{Mms, Opm}; +use embassy_stm32::peripherals::{TIM6, TIM7}; +use embassy_stm32::rcc::low_level::RccPeripheral; +use embassy_stm32::time::Hertz; +use embassy_stm32::timer::low_level::Basic16bitInstance; +use micromath::F32Ext; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +pub type Dac1Type<'d> = + embassy_stm32::dac::DacCh1<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>; + +pub type Dac2Type<'d> = + embassy_stm32::dac::DacCh2<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>; + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let config = embassy_stm32::Config::default(); + + // Initialize the board and obtain a Peripherals instance + let p: embassy_stm32::Peripherals = embassy_stm32::init(config); + + // Obtain two independent channels (p.DAC1 can only be consumed once, though!) + let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); + + let dac1 = { + type T = impl Sized; + static STATIC_CELL: StaticCell = StaticCell::new(); + STATIC_CELL.init(dac_ch1) + }; + + let dac2 = { + type T = impl Sized; + static STATIC_CELL: StaticCell = StaticCell::new(); + STATIC_CELL.init(dac_ch2) + }; + + spawner.spawn(dac_task1(dac1)).ok(); + spawner.spawn(dac_task2(dac2)).ok(); +} + +#[embassy_executor::task] +async fn dac_task1(dac: &'static mut Dac1Type<'static>) { + let data: &[u8; 256] = &calculate_array::<256>(); + + info!("TIM6 frequency is {}", TIM6::frequency()); + const FREQUENCY: Hertz = Hertz::hz(200); + let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; + + // Depends on your clock and on the specific chip used, you may need higher or lower values here + if reload < 10 { + error!("Reload value {} below threshold!", reload); + } + + dac.select_trigger(embassy_stm32::dac::Ch1Trigger::Tim6).unwrap(); + dac.enable_channel().unwrap(); + + TIM6::enable(); + TIM6::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); + TIM6::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + TIM6::regs().cr1().modify(|w| { + w.set_opm(Opm::DISABLED); + w.set_cen(true); + }); + + debug!( + "TIM6 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", + TIM6::frequency(), + FREQUENCY, + reload, + reload as u16, + data.len() + ); + + // Loop technically not necessary if DMA circular mode is enabled + loop { + info!("Loop DAC1"); + if let Err(e) = dac.write(ValueArray::Bit8(data), true).await { + error!("Could not write to dac: {}", e); + } + } +} + +#[embassy_executor::task] +async fn dac_task2(dac: &'static mut Dac2Type<'static>) { + let data: &[u8; 256] = &calculate_array::<256>(); + + info!("TIM7 frequency is {}", TIM7::frequency()); + + const FREQUENCY: Hertz = Hertz::hz(600); + let reload: u32 = (TIM7::frequency().0 / FREQUENCY.0) / data.len() as u32; + + if reload < 10 { + error!("Reload value {} below threshold!", reload); + } + + TIM7::enable(); + TIM7::regs().arr().modify(|w| w.set_arr(reload as u16 - 1)); + TIM7::regs().cr2().modify(|w| w.set_mms(Mms::UPDATE)); + TIM7::regs().cr1().modify(|w| { + w.set_opm(Opm::DISABLED); + w.set_cen(true); + }); + + dac.select_trigger(embassy_stm32::dac::Ch2Trigger::Tim7).unwrap(); + + debug!( + "TIM7 Frequency {}, Target Frequency {}, Reload {}, Reload as u16 {}, Samples {}", + TIM7::frequency(), + FREQUENCY, + reload, + reload as u16, + data.len() + ); + + if let Err(e) = dac.write(ValueArray::Bit8(data), true).await { + error!("Could not write to dac: {}", e); + } +} + +fn to_sine_wave(v: u8) -> u8 { + if v >= 128 { + // top half + let r = 3.14 * ((v - 128) as f32 / 128.0); + (r.sin() * 128.0 + 127.0) as u8 + } else { + // bottom half + let r = 3.14 + 3.14 * (v as f32 / 128.0); + (r.sin() * 128.0 + 127.0) as u8 + } +} + +fn calculate_array() -> [u8; N] { + let mut res = [0; N]; + let mut i = 0; + while i < N { + res[i] = to_sine_wave(i as u8); + i += 1; + } + res +} From 59f829c6cce3427f95b7c5b137f62f8af0c3c40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 28 Jun 2023 15:03:57 +0200 Subject: [PATCH 56/74] Make StackResources::new() const --- embassy-net/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 3e83da7aa..17a7a22a2 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -57,7 +57,7 @@ pub struct StackResources { impl StackResources { /// Create a new set of stack resources. - pub fn new() -> Self { + pub const fn new() -> Self { #[cfg(feature = "dns")] const INIT: Option = None; Self { From 27a89019adaebfd1916d3b71dde1db3a6a768883 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:21:24 +0200 Subject: [PATCH 57/74] add doc --- examples/stm32l4/src/bin/dac_dma.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 81e6a58e4..aefc8412f 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -52,6 +52,8 @@ async fn dac_task1(dac: &'static mut Dac1Type<'static>) { info!("TIM6 frequency is {}", TIM6::frequency()); const FREQUENCY: Hertz = Hertz::hz(200); + + // Compute the reload value such that we obtain the FREQUENCY for the sine let reload: u32 = (TIM6::frequency().0 / FREQUENCY.0) / data.len() as u32; // Depends on your clock and on the specific chip used, you may need higher or lower values here From f2e7a23148f0c1f663744bfe47fbbb37d9552080 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:25:57 +0200 Subject: [PATCH 58/74] attempt at fixing ci --- examples/stm32l4/.cargo/config.toml | 3 ++- examples/stm32l4/memory.x | 8 ++++---- examples/stm32l4/src/bin/dac_dma.rs | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index abf55eb2e..4ccdf121e 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -2,7 +2,8 @@ # replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` #runner = "probe-rs-cli run --chip STM32L475VGT6" #runner = "probe-rs-cli run --chip STM32L475VG" -runner = "probe-rs-cli run --chip STM32L4S5VI" +#runner = "probe-rs-cli run --chip STM32L4S5VI" +runner = "probe-run --chip STM32L432KCUx" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32l4/memory.x b/examples/stm32l4/memory.x index eb87d1b54..0cef526ae 100644 --- a/examples/stm32l4/memory.x +++ b/examples/stm32l4/memory.x @@ -1,7 +1,7 @@ MEMORY { - /* NOTE 1 K = 1 KiBi = 1024 bytes */ - /* These values correspond to the STM32L4S5 */ - FLASH : ORIGIN = 0x08000000, LENGTH = 1024K - RAM : ORIGIN = 0x20000000, LENGTH = 128K + /* NOTE K = KiBi = 1024 bytes */ + /* TODO Adjust these memory regions to match your device memory layout */ + FLASH : ORIGIN = 0x8000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 64K } diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index aefc8412f..7c0df835b 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -93,7 +93,7 @@ async fn dac_task1(dac: &'static mut Dac1Type<'static>) { #[embassy_executor::task] async fn dac_task2(dac: &'static mut Dac2Type<'static>) { let data: &[u8; 256] = &calculate_array::<256>(); - + info!("TIM7 frequency is {}", TIM7::frequency()); const FREQUENCY: Hertz = Hertz::hz(600); From 02f367f733591c9423731a86ea7726772a88dac0 Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:28:10 +0200 Subject: [PATCH 59/74] attempt at fixing ci --- examples/stm32l4/src/bin/dac.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs index 8aad27646..ade43eb35 100644 --- a/examples/stm32l4/src/bin/dac.rs +++ b/examples/stm32l4/src/bin/dac.rs @@ -5,7 +5,6 @@ use defmt::*; use embassy_stm32::dac::{DacCh1, DacChannel, Value}; use embassy_stm32::dma::NoDma; -use embassy_stm32::pac; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] From bf7e24e9d7abc5d31b75ef97418577920bd4600c Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:37:29 +0200 Subject: [PATCH 60/74] revert to STM32L4S5VI --- examples/stm32l4/.cargo/config.toml | 3 +-- examples/stm32l4/memory.x | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index 4ccdf121e..abf55eb2e 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -2,8 +2,7 @@ # replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` #runner = "probe-rs-cli run --chip STM32L475VGT6" #runner = "probe-rs-cli run --chip STM32L475VG" -#runner = "probe-rs-cli run --chip STM32L4S5VI" -runner = "probe-run --chip STM32L432KCUx" +runner = "probe-rs-cli run --chip STM32L4S5VI" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32l4/memory.x b/examples/stm32l4/memory.x index 0cef526ae..eb87d1b54 100644 --- a/examples/stm32l4/memory.x +++ b/examples/stm32l4/memory.x @@ -1,7 +1,7 @@ MEMORY { - /* NOTE K = KiBi = 1024 bytes */ - /* TODO Adjust these memory regions to match your device memory layout */ - FLASH : ORIGIN = 0x8000000, LENGTH = 256K - RAM : ORIGIN = 0x20000000, LENGTH = 64K + /* NOTE 1 K = 1 KiBi = 1024 bytes */ + /* These values correspond to the STM32L4S5 */ + FLASH : ORIGIN = 0x08000000, LENGTH = 1024K + RAM : ORIGIN = 0x20000000, LENGTH = 128K } From daedfbbd8756e921cc6343ad531401d309966eaa Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:39:36 +0200 Subject: [PATCH 61/74] add dma is_running change doc --- embassy-stm32/src/dma/dma.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 0b7b60789..9c03599eb 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -404,11 +404,9 @@ impl<'a, C: Channel> Transfer<'a, C> { } pub fn is_running(&mut self) -> bool { - //let ch = self.channel.regs().st(self.channel.num()); - //ch.cr().read().en() - let ch = self.channel.regs().st(self.channel.num()); let en = ch.cr().read().en(); + // Check if circular mode is enabled, if so it will still be running even if tcif == 1 let circular = ch.cr().read().circ() == vals::Circ::ENABLED; let tcif = STATE.complete_count[self.channel.index()].load(Ordering::Acquire) != 0; en && (circular || !tcif) From d5898c11ebef63fa0ec6dba8381484f4cfabd65c Mon Sep 17 00:00:00 2001 From: JuliDi <20155974+JuliDi@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:40:50 +0200 Subject: [PATCH 62/74] remove need for StaticCell in dac_dma example for stm32l4 --- examples/stm32l4/Cargo.toml | 2 -- examples/stm32l4/src/bin/dac_dma.rs | 29 ++++++++--------------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/examples/stm32l4/Cargo.toml b/examples/stm32l4/Cargo.toml index d2d228282..3bb473ef5 100644 --- a/examples/stm32l4/Cargo.toml +++ b/examples/stm32l4/Cargo.toml @@ -25,5 +25,3 @@ futures = { version = "0.3.17", default-features = false, features = ["async-awa heapless = { version = "0.7.5", default-features = false } micromath = "2.0.0" - -static_cell = "1.0.0" diff --git a/examples/stm32l4/src/bin/dac_dma.rs b/examples/stm32l4/src/bin/dac_dma.rs index 7c0df835b..c27cc03e1 100644 --- a/examples/stm32l4/src/bin/dac_dma.rs +++ b/examples/stm32l4/src/bin/dac_dma.rs @@ -11,14 +11,13 @@ use embassy_stm32::rcc::low_level::RccPeripheral; use embassy_stm32::time::Hertz; use embassy_stm32::timer::low_level::Basic16bitInstance; use micromath::F32Ext; -use static_cell::StaticCell; use {defmt_rtt as _, panic_probe as _}; -pub type Dac1Type<'d> = - embassy_stm32::dac::DacCh1<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>; +pub type Dac1Type = + embassy_stm32::dac::DacCh1<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH3>; -pub type Dac2Type<'d> = - embassy_stm32::dac::DacCh2<'d, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>; +pub type Dac2Type = + embassy_stm32::dac::DacCh2<'static, embassy_stm32::peripherals::DAC1, embassy_stm32::peripherals::DMA1_CH4>; #[embassy_executor::main] async fn main(spawner: Spawner) { @@ -30,24 +29,12 @@ async fn main(spawner: Spawner) { // Obtain two independent channels (p.DAC1 can only be consumed once, though!) let (dac_ch1, dac_ch2) = embassy_stm32::dac::Dac::new(p.DAC1, p.DMA1_CH3, p.DMA1_CH4, p.PA4, p.PA5).split(); - let dac1 = { - type T = impl Sized; - static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init(dac_ch1) - }; - - let dac2 = { - type T = impl Sized; - static STATIC_CELL: StaticCell = StaticCell::new(); - STATIC_CELL.init(dac_ch2) - }; - - spawner.spawn(dac_task1(dac1)).ok(); - spawner.spawn(dac_task2(dac2)).ok(); + spawner.spawn(dac_task1(dac_ch1)).ok(); + spawner.spawn(dac_task2(dac_ch2)).ok(); } #[embassy_executor::task] -async fn dac_task1(dac: &'static mut Dac1Type<'static>) { +async fn dac_task1(mut dac: Dac1Type) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM6 frequency is {}", TIM6::frequency()); @@ -91,7 +78,7 @@ async fn dac_task1(dac: &'static mut Dac1Type<'static>) { } #[embassy_executor::task] -async fn dac_task2(dac: &'static mut Dac2Type<'static>) { +async fn dac_task2(mut dac: Dac2Type) { let data: &[u8; 256] = &calculate_array::<256>(); info!("TIM7 frequency is {}", TIM7::frequency()); From 5666c569033d59fc894230ed4161e6c686733b2d Mon Sep 17 00:00:00 2001 From: Kevin Lannen Date: Wed, 28 Jun 2023 13:05:39 -0600 Subject: [PATCH 63/74] STM32G4: Add CRS support to RCC Create working CRS USB Example --- embassy-stm32/src/rcc/g4.rs | 77 +++++++++++++++++++++++++- examples/stm32g4/src/bin/usb_serial.rs | 30 ++++++---- 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/rcc/g4.rs b/embassy-stm32/src/rcc/g4.rs index 9401af4c3..ff8f97541 100644 --- a/embassy-stm32/src/rcc/g4.rs +++ b/embassy-stm32/src/rcc/g4.rs @@ -3,6 +3,7 @@ use stm32_metapac::rcc::vals::{Hpre, Pllsrc, Ppre, Sw}; use stm32_metapac::FLASH; use crate::pac::{PWR, RCC}; +use crate::rcc::sealed::RccPeripheral; use crate::rcc::{set_freqs, Clocks}; use crate::time::Hertz; @@ -316,6 +317,27 @@ impl Into for AHBPrescaler { } } +/// Sets the source for the 48MHz clock to the USB and RNG peripherals. +pub enum Clock48MhzSrc { + /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the + /// oscillator to comply with the USB specification for oscillator tolerance. + Hsi48(Option), + /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the + /// PLL needs to be using the HSE source to comply with the USB specification for oscillator + /// tolerance. + PllQ, +} + +/// Sets the sync source for the Clock Recovery System (CRS). +pub enum CrsSyncSource { + /// Use an external GPIO to sync the CRS. + Gpio, + /// Use the Low Speed External oscillator to sync the CRS. + Lse, + /// Use the USB SOF to sync the CRS. + Usb, +} + /// Clocks configutation pub struct Config { pub mux: ClockSrc, @@ -326,6 +348,14 @@ pub struct Config { /// Iff PLL is requested as the main clock source in the `mux` field then the PLL configuration /// MUST turn on the PLLR output. pub pll: Option, + /// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals. + pub clock_48mhz_src: Option, +} + +/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator. +pub struct CrsConfig { + /// Sync source for the CRS. + pub sync_src: CrsSyncSource, } impl Default for Config { @@ -338,6 +368,7 @@ impl Default for Config { apb2_pre: APBPrescaler::NotDivided, low_power_run: false, pll: None, + clock_48mhz_src: None, } } } @@ -430,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) { assert!(pll_freq.is_some()); assert!(pll_freq.as_ref().unwrap().pll_r.is_some()); - let freq = pll_freq.unwrap().pll_r.unwrap().0; + let freq = pll_freq.as_ref().unwrap().pll_r.unwrap().0; assert!(freq <= 170_000_000); @@ -497,6 +528,50 @@ pub(crate) unsafe fn init(config: Config) { } }; + // Setup the 48 MHz clock if needed + if let Some(clock_48mhz_src) = config.clock_48mhz_src { + let source = match clock_48mhz_src { + Clock48MhzSrc::PllQ => { + // Make sure the PLLQ is enabled and running at 48Mhz + let pllq_freq = pll_freq.as_ref().and_then(|f| f.pll_q); + assert!(pllq_freq.is_some() && pllq_freq.unwrap().0 == 48_000_000); + + crate::pac::rcc::vals::Clk48sel::PLLQCLK + } + Clock48MhzSrc::Hsi48(crs_config) => { + // Enable HSI48 + RCC.crrcr().modify(|w| w.set_hsi48on(true)); + // Wait for HSI48 to turn on + while RCC.crrcr().read().hsi48rdy() == false {} + + // Enable and setup CRS if needed + if let Some(crs_config) = crs_config { + crate::peripherals::CRS::enable(); + + let sync_src = match crs_config.sync_src { + CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO, + CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE, + CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB, + }; + + crate::pac::CRS.cfgr().modify(|w| { + w.set_syncsrc(sync_src); + }); + + // These are the correct settings for standard USB operation. If other settings + // are needed there will need to be additional config options for the CRS. + crate::pac::CRS.cr().modify(|w| { + w.set_autotrimen(true); + w.set_cen(true); + }); + } + crate::pac::rcc::vals::Clk48sel::HSI48 + } + }; + + RCC.ccipr().modify(|w| w.set_clk48sel(source)); + } + if config.low_power_run { assert!(sys_clk <= 2_000_000); PWR.cr1().modify(|w| w.set_lpr(true)); diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs index 289d0ed86..77cfa67d3 100644 --- a/examples/stm32g4/src/bin/usb_serial.rs +++ b/examples/stm32g4/src/bin/usb_serial.rs @@ -4,10 +4,10 @@ use defmt::{panic, *}; use embassy_executor::Spawner; -use embassy_stm32::rcc::{ClockSrc, Pll, PllM, PllN, PllQ, PllR, PllSrc}; +use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc}; use embassy_stm32::time::Hertz; use embassy_stm32::usb::{self, Driver, Instance}; -use embassy_stm32::{bind_interrupts, pac, peripherals, Config}; +use embassy_stm32::{bind_interrupts, peripherals, Config}; use embassy_usb::class::cdc_acm::{CdcAcmClass, State}; use embassy_usb::driver::EndpointError; use embassy_usb::Builder; @@ -22,25 +22,35 @@ bind_interrupts!(struct Irqs { async fn main(_spawner: Spawner) { let mut config = Config::default(); + // Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE. + const USE_HSI48: bool = true; + + let pllq_div = if USE_HSI48 { None } else { Some(PllQ::Div6) }; + config.rcc.pll = Some(Pll { - source: PllSrc::HSE(Hertz(8000000)), + source: PllSrc::HSE(Hertz(8_000_000)), prediv_m: PllM::Div2, mul_n: PllN::Mul72, div_p: None, - // USB and CAN at 48 MHz - div_q: Some(PllQ::Div6), + div_q: pllq_div, // Main system clock at 144 MHz div_r: Some(PllR::Div2), }); config.rcc.mux = ClockSrc::PLL; - let p = embassy_stm32::init(config); - info!("Hello World!"); + if USE_HSI48 { + // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. + config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig { + sync_src: CrsSyncSource::Usb, + }))); + } else { + config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ); + } - pac::RCC.ccipr().write(|w| { - w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK); - }); + let p = embassy_stm32::init(config); + + info!("Hello World!"); let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); From e892014b6572e74b58ea653cfed06614c496e6a5 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jun 2023 01:51:19 +0200 Subject: [PATCH 64/74] Update stm32-metapac, includes chiptool changes to use real Rust enums now. --- embassy-stm32/Cargo.toml | 4 +- embassy-stm32/src/adc/v3.rs | 8 ++-- embassy-stm32/src/can/bxcan.rs | 8 ++-- embassy-stm32/src/eth/v1/rx_desc.rs | 2 +- embassy-stm32/src/pwm/complementary_pwm.rs | 2 +- embassy-stm32/src/rcc/c0.rs | 10 ++-- embassy-stm32/src/rcc/f0.rs | 23 +++++---- embassy-stm32/src/rcc/f1.rs | 36 +++++++------- embassy-stm32/src/rcc/f2.rs | 2 +- embassy-stm32/src/rcc/f4.rs | 12 ++--- embassy-stm32/src/rcc/f7.rs | 12 ++--- embassy-stm32/src/rcc/g0.rs | 10 ++-- embassy-stm32/src/rcc/h7.rs | 17 +++---- embassy-stm32/src/rcc/l0.rs | 6 +-- embassy-stm32/src/rcc/l1.rs | 6 +-- embassy-stm32/src/rcc/l4.rs | 6 +-- embassy-stm32/src/rcc/l5.rs | 6 +-- embassy-stm32/src/rcc/u5.rs | 2 +- embassy-stm32/src/rtc/v2.rs | 4 +- embassy-stm32/src/rtc/v3.rs | 2 +- embassy-stm32/src/spi/mod.rs | 4 +- embassy-stm32/src/usart/mod.rs | 2 +- embassy-stm32/src/usb/usb.rs | 56 +++++++++++----------- embassy-stm32/src/usb_otg/usb.rs | 4 +- embassy-stm32/src/wdg/mod.rs | 2 +- 25 files changed, 121 insertions(+), 125 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index f15c6d0b7..b3fe9c1f5 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = "11" +stm32-metapac = "12" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] } [build-dependencies] proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { version = "11", default-features = false, features = ["metadata"]} +stm32-metapac = { version = "12", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 94cdc86cd..3a6e58cf6 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -211,10 +211,8 @@ impl<'d, T: Instance> Adc<'d, T> { #[cfg(not(stm32g0))] fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { let sample_time = sample_time.into(); - if ch <= 9 { - T::regs().smpr1().modify(|reg| reg.set_smp(ch as _, sample_time)); - } else { - T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); - } + T::regs() + .smpr(ch as usize / 10) + .modify(|reg| reg.set_smp(ch as usize % 10, sample_time)); } } diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 88eef528f..73861776a 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -116,10 +116,10 @@ impl<'d, T: Instance> Can<'d, T> { T::regs().ier().write(|w| { // TODO: fix metapac - w.set_errie(Errie(1)); - w.set_fmpie(0, Fmpie(1)); - w.set_fmpie(1, Fmpie(1)); - w.set_tmeie(Tmeie(1)); + w.set_errie(Errie::from_bits(1)); + w.set_fmpie(0, Fmpie::from_bits(1)); + w.set_fmpie(1, Fmpie::from_bits(1)); + w.set_tmeie(Tmeie::from_bits(1)); }); T::regs().mcr().write(|w| { diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs index 01a073bb9..668378bea 100644 --- a/embassy-stm32/src/eth/v1/rx_desc.rs +++ b/embassy-stm32/src/eth/v1/rx_desc.rs @@ -174,7 +174,7 @@ impl<'a> RDesRing<'a> { // Receive descriptor unavailable Rps::SUSPENDED => RunningState::Stopped, // Closing receive descriptor - Rps(0b101) => RunningState::Running, + Rps::_RESERVED_5 => RunningState::Running, // Transferring the receive packet data from receive buffer to host memory Rps::RUNNINGWRITING => RunningState::Running, _ => RunningState::Unknown, diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index 0e153202e..4d64d005c 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -243,7 +243,7 @@ mod tests { for test_run in fn_results { let (ckd, bits) = compute_dead_time_value(test_run.value); - assert_eq!(ckd.0, test_run.ckd.0); + assert_eq!(ckd.to_bits(), test_run.ckd.to_bits()); assert_eq!(bits, test_run.bits); } } diff --git a/embassy-stm32/src/rcc/c0.rs b/embassy-stm32/src/rcc/c0.rs index 6c7b36647..df6e9047c 100644 --- a/embassy-stm32/src/rcc/c0.rs +++ b/embassy-stm32/src/rcc/c0.rs @@ -126,7 +126,7 @@ pub(crate) unsafe fn init(config: Config) { }); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0 >> div.0, Sw::HSI) + (HSI_FREQ.0 >> div.to_bits(), Sw::HSI) } ClockSrc::HSE(freq) => { // Enable HSE @@ -157,7 +157,7 @@ pub(crate) unsafe fn init(config: Config) { let mut set_flash_latency_after = false; FLASH.acr().modify(|w| { // Is the current flash latency less than what we need at the new SYSCLK? - if w.latency().0 <= target_flash_latency.0 { + if w.latency().to_bits() <= target_flash_latency.to_bits() { // We must increase the number of wait states now w.set_latency(target_flash_latency) } else { @@ -171,12 +171,12 @@ pub(crate) unsafe fn init(config: Config) { // > Flash memory. // // Enable flash prefetching if we have at least one wait state, and disable it otherwise. - w.set_prften(target_flash_latency.0 > 0); + w.set_prften(target_flash_latency.to_bits() > 0); }); if !set_flash_latency_after { // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency().0 < target_flash_latency.0 {} + while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once @@ -218,7 +218,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } diff --git a/embassy-stm32/src/rcc/f0.rs b/embassy-stm32/src/rcc/f0.rs index eb62ab661..ca6eed284 100644 --- a/embassy-stm32/src/rcc/f0.rs +++ b/embassy-stm32/src/rcc/f0.rs @@ -1,3 +1,5 @@ +use stm32_metapac::flash::vals::Latency; + use super::{set_freqs, Clocks}; use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw}; use crate::pac::{FLASH, RCC}; @@ -85,14 +87,11 @@ pub(crate) unsafe fn init(config: Config) { let timer_mul = if ppre == 1 { 1 } else { 2 }; FLASH.acr().write(|w| { - let latency = if real_sysclk <= 24_000_000 { - 0 - } else if real_sysclk <= 48_000_000 { - 1 + w.set_latency(if real_sysclk <= 24_000_000 { + Latency::WS0 } else { - 2 - }; - w.latency().0 = latency; + Latency::WS1 + }); }); match (config.hse.is_some(), use_hsi48) { @@ -134,20 +133,20 @@ pub(crate) unsafe fn init(config: Config) { // TODO: Option to use CRS (Clock Recovery) if let Some(pllmul_bits) = pllmul_bits { - RCC.cfgr().modify(|w| w.set_pllmul(Pllmul(pllmul_bits))); + RCC.cfgr().modify(|w| w.set_pllmul(Pllmul::from_bits(pllmul_bits))); RCC.cr().modify(|w| w.set_pllon(true)); while !RCC.cr().read().pllrdy() {} RCC.cfgr().modify(|w| { - w.set_ppre(Ppre(ppre_bits)); - w.set_hpre(Hpre(hpre_bits)); + w.set_ppre(Ppre::from_bits(ppre_bits)); + w.set_hpre(Hpre::from_bits(hpre_bits)); w.set_sw(Sw::PLL) }); } else { RCC.cfgr().modify(|w| { - w.set_ppre(Ppre(ppre_bits)); - w.set_hpre(Hpre(hpre_bits)); + w.set_ppre(Ppre::from_bits(ppre_bits)); + w.set_hpre(Hpre::from_bits(hpre_bits)); if config.hse.is_some() { w.set_sw(Sw::HSE); diff --git a/embassy-stm32/src/rcc/f1.rs b/embassy-stm32/src/rcc/f1.rs index 4769b7059..b6200231e 100644 --- a/embassy-stm32/src/rcc/f1.rs +++ b/embassy-stm32/src/rcc/f1.rs @@ -106,11 +106,11 @@ pub(crate) unsafe fn init(config: Config) { // Only needed for stm32f103? FLASH.acr().write(|w| { w.set_latency(if real_sysclk <= 24_000_000 { - Latency(0b000) + Latency::WS0 } else if real_sysclk <= 48_000_000 { - Latency(0b001) + Latency::WS1 } else { - Latency(0b010) + Latency::WS2 }); }); @@ -147,12 +147,13 @@ pub(crate) unsafe fn init(config: Config) { if let Some(pllmul_bits) = pllmul_bits { let pllctpre_flag: u8 = if config.pllxtpre { 1 } else { 0 }; - RCC.cfgr().modify(|w| w.set_pllxtpre(Pllxtpre(pllctpre_flag))); + RCC.cfgr() + .modify(|w| w.set_pllxtpre(Pllxtpre::from_bits(pllctpre_flag))); // enable PLL and wait for it to be ready RCC.cfgr().modify(|w| { - w.set_pllmul(Pllmul(pllmul_bits)); - w.set_pllsrc(Pllsrc(config.hse.is_some() as u8)); + w.set_pllmul(Pllmul::from_bits(pllmul_bits)); + w.set_pllsrc(Pllsrc::from_bits(config.hse.is_some() as u8)); }); RCC.cr().modify(|w| w.set_pllon(true)); @@ -161,22 +162,19 @@ pub(crate) unsafe fn init(config: Config) { // Only needed for stm32f103? RCC.cfgr().modify(|w| { - w.set_adcpre(Adcpre(apre_bits)); - w.set_ppre2(Ppre1(ppre2_bits)); - w.set_ppre1(Ppre1(ppre1_bits)); - w.set_hpre(Hpre(hpre_bits)); + w.set_adcpre(Adcpre::from_bits(apre_bits)); + w.set_ppre2(Ppre1::from_bits(ppre2_bits)); + w.set_ppre1(Ppre1::from_bits(ppre1_bits)); + w.set_hpre(Hpre::from_bits(hpre_bits)); #[cfg(not(rcc_f100))] - w.set_usbpre(Usbpre(usbpre as u8)); - w.set_sw(Sw(if pllmul_bits.is_some() { - // PLL - 0b10 + w.set_usbpre(Usbpre::from_bits(usbpre as u8)); + w.set_sw(if pllmul_bits.is_some() { + Sw::PLL } else if config.hse.is_some() { - // HSE - 0b1 + Sw::HSE } else { - // HSI - 0b0 - })); + Sw::HSI + }); }); set_freqs(Clocks { diff --git a/embassy-stm32/src/rcc/f2.rs b/embassy-stm32/src/rcc/f2.rs index bcae64d0f..1525cc3c3 100644 --- a/embassy-stm32/src/rcc/f2.rs +++ b/embassy-stm32/src/rcc/f2.rs @@ -485,7 +485,7 @@ pub(crate) unsafe fn init(config: Config) { w.set_ppre1(config.apb1_pre.into()); w.set_ppre2(config.apb2_pre.into()); }); - while RCC.cfgr().read().sws() != sw.0 {} + while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} // Turn off HSI to save power if we don't need it if !config.hsi { diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index bc430afb2..b84470440 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs @@ -87,7 +87,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, plli2s: Opti let sysclk = pllsysclk.unwrap_or(pllsrcclk); if pllsysclk.is_none() && !pll48clk { - RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); + RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8))); return PllResults { use_pll: false, @@ -141,9 +141,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, plli2s: Opti RCC.pllcfgr().modify(|w| { w.set_pllm(pllm as u8); w.set_plln(plln as u16); - w.set_pllp(Pllp(pllp as u8)); + w.set_pllp(Pllp::from_bits(pllp as u8)); w.set_pllq(pllq as u8); - w.set_pllsrc(Pllsrc(use_hse as u8)); + w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); }); let real_pllsysclk = vco_in * plln / sysclk_div; @@ -323,7 +323,7 @@ fn flash_setup(sysclk: u32) { critical_section::with(|_| { FLASH .acr() - .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); + .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); }); } @@ -440,8 +440,8 @@ pub(crate) unsafe fn init(config: Config) { } RCC.cfgr().modify(|w| { - w.set_ppre2(Ppre(ppre2_bits)); - w.set_ppre1(Ppre(ppre1_bits)); + w.set_ppre2(Ppre::from_bits(ppre2_bits)); + w.set_ppre1(Ppre::from_bits(ppre1_bits)); w.set_hpre(hpre_bits); }); diff --git a/embassy-stm32/src/rcc/f7.rs b/embassy-stm32/src/rcc/f7.rs index 71215cac5..85cb9c661 100644 --- a/embassy-stm32/src/rcc/f7.rs +++ b/embassy-stm32/src/rcc/f7.rs @@ -30,7 +30,7 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bo let sysclk = pllsysclk.unwrap_or(pllsrcclk); if pllsysclk.is_none() && !pll48clk { - RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc(use_hse as u8))); + RCC.pllcfgr().modify(|w| w.set_pllsrc(Pllsrc::from_bits(use_hse as u8))); return PllResults { use_pll: false, @@ -83,9 +83,9 @@ fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option, pll48clk: bo RCC.pllcfgr().modify(|w| { w.set_pllm(pllm as u8); w.set_plln(plln as u16); - w.set_pllp(Pllp(pllp as u8)); + w.set_pllp(Pllp::from_bits(pllp as u8)); w.set_pllq(pllq as u8); - w.set_pllsrc(Pllsrc(use_hse as u8)); + w.set_pllsrc(Pllsrc::from_bits(use_hse as u8)); }); let real_pllsysclk = vco_in * plln / sysclk_div; @@ -106,7 +106,7 @@ fn flash_setup(sysclk: u32) { critical_section::with(|_| { FLASH .acr() - .modify(|w| w.set_latency(Latency(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); + .modify(|w| w.set_latency(Latency::from_bits(((sysclk - 1) / FLASH_LATENCY_STEP) as u8))); }); } @@ -246,8 +246,8 @@ pub(crate) unsafe fn init(config: Config) { } RCC.cfgr().modify(|w| { - w.set_ppre2(Ppre(ppre2_bits)); - w.set_ppre1(Ppre(ppre1_bits)); + w.set_ppre2(Ppre::from_bits(ppre2_bits)); + w.set_ppre1(Ppre::from_bits(ppre1_bits)); w.set_hpre(hpre_bits); }); diff --git a/embassy-stm32/src/rcc/g0.rs b/embassy-stm32/src/rcc/g0.rs index 17c73c36b..5e3a7911a 100644 --- a/embassy-stm32/src/rcc/g0.rs +++ b/embassy-stm32/src/rcc/g0.rs @@ -344,7 +344,7 @@ pub(crate) unsafe fn init(config: Config) { }); while !RCC.cr().read().hsirdy() {} - (HSI_FREQ.0 >> div.0, Sw::HSI) + (HSI_FREQ.0 >> div.to_bits(), Sw::HSI) } ClockSrc::HSE(freq) => { // Enable HSE @@ -381,7 +381,7 @@ pub(crate) unsafe fn init(config: Config) { let mut set_flash_latency_after = false; FLASH.acr().modify(|w| { // Is the current flash latency less than what we need at the new SYSCLK? - if w.latency().0 <= target_flash_latency.0 { + if w.latency().to_bits() <= target_flash_latency.to_bits() { // We must increase the number of wait states now w.set_latency(target_flash_latency) } else { @@ -395,12 +395,12 @@ pub(crate) unsafe fn init(config: Config) { // > Flash memory. // // Enable flash prefetching if we have at least one wait state, and disable it otherwise. - w.set_prften(target_flash_latency.0 > 0); + w.set_prften(target_flash_latency.to_bits() > 0); }); if !set_flash_latency_after { // Spin until the effective flash latency is compatible with the clock change - while FLASH.acr().read().latency().0 < target_flash_latency.0 {} + while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {} } // Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once @@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } diff --git a/embassy-stm32/src/rcc/h7.rs b/embassy-stm32/src/rcc/h7.rs index daa1cd61f..f3a98c794 100644 --- a/embassy-stm32/src/rcc/h7.rs +++ b/embassy-stm32/src/rcc/h7.rs @@ -601,22 +601,22 @@ pub(crate) unsafe fn init(mut config: Config) { // Core Prescaler / AHB Prescaler / APB3 Prescaler RCC.d1cfgr().modify(|w| { - w.set_d1cpre(Hpre(d1cpre_bits)); - w.set_d1ppre(Dppre(ppre3_bits)); + w.set_d1cpre(Hpre::from_bits(d1cpre_bits)); + w.set_d1ppre(Dppre::from_bits(ppre3_bits)); w.set_hpre(hpre_bits) }); // Ensure core prescaler value is valid before future lower // core voltage - while RCC.d1cfgr().read().d1cpre().0 != d1cpre_bits {} + while RCC.d1cfgr().read().d1cpre().to_bits() != d1cpre_bits {} // APB1 / APB2 Prescaler RCC.d2cfgr().modify(|w| { - w.set_d2ppre1(Dppre(ppre1_bits)); - w.set_d2ppre2(Dppre(ppre2_bits)); + w.set_d2ppre1(Dppre::from_bits(ppre1_bits)); + w.set_d2ppre2(Dppre::from_bits(ppre2_bits)); }); // APB4 Prescaler - RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre(ppre4_bits))); + RCC.d3cfgr().modify(|w| w.set_d3ppre(Dppre::from_bits(ppre4_bits))); // Peripheral Clock (per_ck) RCC.d1ccipr().modify(|w| w.set_ckpersel(ckpersel)); @@ -640,7 +640,7 @@ pub(crate) unsafe fn init(mut config: Config) { _ => Sw::HSI, }; RCC.cfgr().modify(|w| w.set_sw(sw)); - while RCC.cfgr().read().sws() != sw.0 {} + while RCC.cfgr().read().sws().to_bits() != sw.to_bits() {} // IO compensation cell - Requires CSI clock and SYSCFG assert!(RCC.cr().read().csirdy()); @@ -806,7 +806,8 @@ mod pll { RCC.pllcfgr().modify(|w| w.set_pllfracen(plln, false)); let vco_ck = ref_x_ck * pll_x_n; - RCC.plldivr(plln).modify(|w| w.set_divp1(Divp((pll_x_p - 1) as u8))); + RCC.plldivr(plln) + .modify(|w| w.set_divp1(Divp::from_bits((pll_x_p - 1) as u8))); RCC.pllcfgr().modify(|w| w.set_divpen(plln, true)); // Calulate additional output dividers diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs index d53b61069..46a528e31 100644 --- a/embassy-stm32/src/rcc/l0.rs +++ b/embassy-stm32/src/rcc/l0.rs @@ -293,7 +293,7 @@ pub(crate) unsafe fn init(config: Config) { AHBPrescaler::NotDivided => sys_clk, pre => { let pre: Hpre = pre.into(); - let pre = 1 << (pre.0 as u32 - 7); + let pre = 1 << (pre.to_bits() as u32 - 7); sys_clk / pre } }; @@ -302,7 +302,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } @@ -312,7 +312,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } diff --git a/embassy-stm32/src/rcc/l1.rs b/embassy-stm32/src/rcc/l1.rs index c907fa88a..59a6eac8f 100644 --- a/embassy-stm32/src/rcc/l1.rs +++ b/embassy-stm32/src/rcc/l1.rs @@ -294,7 +294,7 @@ pub(crate) unsafe fn init(config: Config) { AHBPrescaler::NotDivided => sys_clk, pre => { let pre: Hpre = pre.into(); - let pre = 1 << (pre.0 as u32 - 7); + let pre = 1 << (pre.to_bits() as u32 - 7); sys_clk / pre } }; @@ -303,7 +303,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } @@ -313,7 +313,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index f8c1a6e06..20cb8c91c 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs @@ -635,7 +635,7 @@ pub(crate) unsafe fn init(config: Config) { AHBPrescaler::NotDivided => sys_clk, pre => { let pre: Hpre = pre.into(); - let pre = 1 << (pre.0 as u32 - 7); + let pre = 1 << (pre.to_bits() as u32 - 7); sys_clk / pre } }; @@ -644,7 +644,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } @@ -654,7 +654,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } diff --git a/embassy-stm32/src/rcc/l5.rs b/embassy-stm32/src/rcc/l5.rs index f56fce365..16da65d5e 100644 --- a/embassy-stm32/src/rcc/l5.rs +++ b/embassy-stm32/src/rcc/l5.rs @@ -461,7 +461,7 @@ pub(crate) unsafe fn init(config: Config) { AHBPrescaler::NotDivided => sys_clk, pre => { let pre: Hpre = pre.into(); - let pre = 1 << (pre.0 as u32 - 7); + let pre = 1 << (pre.to_bits() as u32 - 7); sys_clk / pre } }; @@ -470,7 +470,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } @@ -480,7 +480,7 @@ pub(crate) unsafe fn init(config: Config) { APBPrescaler::NotDivided => (ahb_freq, ahb_freq), pre => { let pre: Ppre = pre.into(); - let pre: u8 = 1 << (pre.0 - 3); + let pre: u8 = 1 << (pre.to_bits() - 3); let freq = ahb_freq / pre as u32; (freq, freq * 2) } diff --git a/embassy-stm32/src/rcc/u5.rs b/embassy-stm32/src/rcc/u5.rs index 81507a4d6..cfc07f069 100644 --- a/embassy-stm32/src/rcc/u5.rs +++ b/embassy-stm32/src/rcc/u5.rs @@ -126,7 +126,7 @@ pub enum PllM { impl Into for PllM { fn into(self) -> Pllm { - Pllm(self as u8) + Pllm::from_bits(self as u8) } } diff --git a/embassy-stm32/src/rtc/v2.rs b/embassy-stm32/src/rtc/v2.rs index e1615b34c..a2eace6d3 100644 --- a/embassy-stm32/src/rtc/v2.rs +++ b/embassy-stm32/src/rtc/v2.rs @@ -36,7 +36,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> { #[cfg(rtc_v2wb)] let rtcsel = reg.rtcsel(); #[cfg(not(rtc_v2wb))] - let rtcsel = reg.rtcsel().0; + let rtcsel = reg.rtcsel().to_bits(); if !reg.rtcen() || rtcsel != clock_config { #[cfg(not(any(rtc_v2l0, rtc_v2l1)))] @@ -54,7 +54,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> { // Select RTC source #[cfg(not(rtc_v2wb))] - w.set_rtcsel(Rtcsel(clock_config)); + w.set_rtcsel(Rtcsel::from_bits(clock_config)); #[cfg(rtc_v2wb)] w.set_rtcsel(clock_config); w.set_rtcen(true); diff --git a/embassy-stm32/src/rtc/v3.rs b/embassy-stm32/src/rtc/v3.rs index 7c91046a2..7e5c64d90 100644 --- a/embassy-stm32/src/rtc/v3.rs +++ b/embassy-stm32/src/rtc/v3.rs @@ -26,7 +26,7 @@ impl<'d, T: Instance> super::Rtc<'d, T> { let config_rtcsel = rtc_config.clock_config as u8; #[cfg(not(any(rcc_wl5, rcc_wle)))] - let config_rtcsel = crate::pac::rcc::vals::Rtcsel(config_rtcsel); + let config_rtcsel = crate::pac::rcc::vals::Rtcsel::from_bits(config_rtcsel); if !reg.rtcen() || reg.rtcsel() != config_rtcsel { crate::pac::RCC.bdcr().modify(|w| w.set_bdrst(true)); diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 1cddac992..c3224073d 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -650,7 +650,7 @@ fn compute_baud_rate(clocks: Hertz, freq: Hertz) -> Br { _ => 0b111, }; - Br(val) + Br::from_bits(val) } trait RegsExt { @@ -772,7 +772,7 @@ fn set_rxdmaen(regs: Regs, val: bool) { fn finish_dma(regs: Regs) { #[cfg(spi_v2)] - while regs.sr().read().ftlvl() > 0 {} + while regs.sr().read().ftlvl().to_bits() > 0 {} #[cfg(any(spi_v3, spi_v4, spi_v5))] while !regs.sr().read().txc() {} diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index 47a79c187..c97efbf0a 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -869,7 +869,7 @@ fn configure(r: Regs, config: &Config, pclk_freq: Hertz, kind: Kind, enable_rx: _ => vals::Ps::EVEN, }); #[cfg(not(usart_v1))] - w.set_over8(vals::Over8(over8 as _)); + w.set_over8(vals::Over8::from_bits(over8 as _)); }); #[cfg(not(usart_v1))] diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs index 01b158b17..ecdd1d0b8 100644 --- a/embassy-stm32/src/usb/usb.rs +++ b/embassy-stm32/src/usb/usb.rs @@ -97,8 +97,8 @@ impl interrupt::typelevel::Handler for InterruptHandl } epr.set_dtog_rx(false); epr.set_dtog_tx(false); - epr.set_stat_rx(Stat(0)); - epr.set_stat_tx(Stat(0)); + epr.set_stat_rx(Stat::from_bits(0)); + epr.set_stat_tx(Stat::from_bits(0)); epr.set_ctr_rx(!epr.ctr_rx()); epr.set_ctr_tx(!epr.ctr_tx()); regs.epr(index).write_value(epr); @@ -143,8 +143,8 @@ fn invariant(mut r: regs::Epr) -> regs::Epr { r.set_ctr_tx(true); // don't clear r.set_dtog_rx(false); // don't toggle r.set_dtog_tx(false); // don't toggle - r.set_stat_rx(Stat(0)); - r.set_stat_tx(Stat(0)); + r.set_stat_rx(Stat::from_bits(0)); + r.set_stat_tx(Stat::from_bits(0)); r } @@ -551,7 +551,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { true => Stat::STALL, }; let mut w = invariant(r); - w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); + w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits())); reg.write_value(w); } } @@ -570,7 +570,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { true => Stat::STALL, }; let mut w = invariant(r); - w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); + w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits())); reg.write_value(w); } } @@ -606,7 +606,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { break; } let mut w = invariant(r); - w.set_stat_tx(Stat(r.stat_tx().0 ^ want_stat.0)); + w.set_stat_tx(Stat::from_bits(r.stat_tx().to_bits() ^ want_stat.to_bits())); reg.write_value(w); } EP_IN_WAKERS[ep_addr.index()].wake(); @@ -622,7 +622,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> { break; } let mut w = invariant(r); - w.set_stat_rx(Stat(r.stat_rx().0 ^ want_stat.0)); + w.set_stat_rx(Stat::from_bits(r.stat_rx().to_bits() ^ want_stat.to_bits())); reg.write_value(w); } EP_OUT_WAKERS[ep_addr.index()].wake(); @@ -763,8 +763,8 @@ impl<'d, T: Instance> driver::EndpointOut for Endpoint<'d, T, Out> { regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); - w.set_stat_rx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); - w.set_stat_tx(Stat(0)); + w.set_stat_rx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + w.set_stat_tx(Stat::from_bits(0)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); @@ -805,8 +805,8 @@ impl<'d, T: Instance> driver::EndpointIn for Endpoint<'d, T, In> { regs.epr(index).write(|w| { w.set_ep_type(convert_type(self.info.ep_type)); w.set_ea(self.info.addr.index() as _); - w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); - w.set_stat_rx(Stat(0)); + w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); + w.set_stat_rx(Stat::from_bits(0)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); @@ -869,19 +869,19 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let mut stat_tx = 0; if first { // change NAK -> VALID - stat_rx ^= Stat::NAK.0 ^ Stat::VALID.0; - stat_tx ^= Stat::NAK.0 ^ Stat::STALL.0; + stat_rx ^= Stat::NAK.to_bits() ^ Stat::VALID.to_bits(); + stat_tx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits(); } if last { // change STALL -> VALID - stat_tx ^= Stat::STALL.0 ^ Stat::NAK.0; + stat_tx ^= Stat::STALL.to_bits() ^ Stat::NAK.to_bits(); } // Note: if this is the first AND last transfer, the above effectively // changes stat_tx like NAK -> NAK, so noop. regs.epr(0).write(|w| { w.set_ep_type(EpType::CONTROL); - w.set_stat_rx(Stat(stat_rx)); - w.set_stat_tx(Stat(stat_tx)); + w.set_stat_rx(Stat::from_bits(stat_rx)); + w.set_stat_tx(Stat::from_bits(stat_tx)); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); @@ -908,11 +908,11 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { regs.epr(0).write(|w| { w.set_ep_type(EpType::CONTROL); - w.set_stat_rx(Stat(match last { + w.set_stat_rx(Stat::from_bits(match last { // If last, set STAT_RX=STALL. - true => Stat::NAK.0 ^ Stat::STALL.0, + true => Stat::NAK.to_bits() ^ Stat::STALL.to_bits(), // Otherwise, set STAT_RX=VALID, to allow the host to send the next packet. - false => Stat::NAK.0 ^ Stat::VALID.0, + false => Stat::NAK.to_bits() ^ Stat::VALID.to_bits(), })); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear @@ -937,17 +937,17 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let mut stat_rx = 0; if first { // change NAK -> STALL - stat_rx ^= Stat::NAK.0 ^ Stat::STALL.0; + stat_rx ^= Stat::NAK.to_bits() ^ Stat::STALL.to_bits(); } if last { // change STALL -> VALID - stat_rx ^= Stat::STALL.0 ^ Stat::VALID.0; + stat_rx ^= Stat::STALL.to_bits() ^ Stat::VALID.to_bits(); } // Note: if this is the first AND last transfer, the above effectively // does a change of NAK -> VALID. regs.epr(0).write(|w| { w.set_ep_type(EpType::CONTROL); - w.set_stat_rx(Stat(stat_rx)); + w.set_stat_rx(Stat::from_bits(stat_rx)); w.set_ep_kind(last); // set OUT_STATUS if last. w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear @@ -977,7 +977,7 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let regs = T::regs(); regs.epr(0).write(|w| { w.set_ep_type(EpType::CONTROL); - w.set_stat_tx(Stat(Stat::NAK.0 ^ Stat::VALID.0)); + w.set_stat_tx(Stat::from_bits(Stat::NAK.to_bits() ^ Stat::VALID.to_bits())); w.set_ep_kind(last); // set OUT_STATUS if last. w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear @@ -998,8 +998,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let epr = regs.epr(0).read(); regs.epr(0).write(|w| { w.set_ep_type(EpType::CONTROL); - w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); - w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::VALID.0)); + w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits())); + w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::VALID.to_bits())); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); @@ -1029,8 +1029,8 @@ impl<'d, T: Instance> driver::ControlPipe for ControlPipe<'d, T> { let epr = regs.epr(0).read(); regs.epr(0).write(|w| { w.set_ep_type(EpType::CONTROL); - w.set_stat_rx(Stat(epr.stat_rx().0 ^ Stat::STALL.0)); - w.set_stat_tx(Stat(epr.stat_tx().0 ^ Stat::STALL.0)); + w.set_stat_rx(Stat::from_bits(epr.stat_rx().to_bits() ^ Stat::STALL.to_bits())); + w.set_stat_tx(Stat::from_bits(epr.stat_tx().to_bits() ^ Stat::STALL.to_bits())); w.set_ctr_rx(true); // don't clear w.set_ctr_tx(true); // don't clear }); diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index 6c00c93d6..6783db28d 100644 --- a/embassy-stm32/src/usb_otg/usb.rs +++ b/embassy-stm32/src/usb_otg/usb.rs @@ -97,7 +97,7 @@ impl interrupt::typelevel::Handler for InterruptHandl vals::Pktstsd::SETUP_DATA_DONE => { trace!("SETUP_DATA_DONE ep={}", ep_num); } - x => trace!("unknown PKTSTS: {}", x.0), + x => trace!("unknown PKTSTS: {}", x.to_bits()), } } @@ -920,7 +920,7 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { trace!("enumdne"); let speed = r.dsts().read().enumspd(); - trace!(" speed={}", speed.0); + trace!(" speed={}", speed.to_bits()); r.gusbcfg().modify(|w| { w.set_trdt(calculate_trdt(speed, T::frequency())); diff --git a/embassy-stm32/src/wdg/mod.rs b/embassy-stm32/src/wdg/mod.rs index 5907a4e54..b03e81d6e 100644 --- a/embassy-stm32/src/wdg/mod.rs +++ b/embassy-stm32/src/wdg/mod.rs @@ -49,7 +49,7 @@ impl<'d, T: Instance> IndependentWatchdog<'d, T> { let wdg = T::regs(); wdg.kr().write(|w| w.set_key(Key::ENABLE)); - wdg.pr().write(|w| w.set_pr(Pr(pr))); + wdg.pr().write(|w| w.set_pr(Pr::from_bits(pr))); wdg.rlr().write(|w| w.set_rl(rl)); trace!( From ce889900d63f9f32f1a6b7540834d6f9558239e4 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jun 2023 02:08:55 +0200 Subject: [PATCH 65/74] Update rp-pac. --- embassy-rp/Cargo.toml | 2 +- embassy-rp/src/clocks.rs | 92 ++++++++++++++++++++-------------------- embassy-rp/src/gpio.rs | 4 +- embassy-rp/src/pio.rs | 4 +- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 49aa6a4d5..66823771a 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -76,7 +76,7 @@ embedded-storage = { version = "0.3" } rand_core = "0.6.4" fixed = "1.23.1" -rp-pac = { version = "5" } +rp-pac = { version = "6" } embedded-hal-02 = { package = "embedded-hal", version = "0.2.6", features = ["unproven"] } embedded-hal-1 = { package = "embedded-hal", version = "=1.0.0-alpha.10", optional = true} diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs index 4c6223107..ddd61d224 100644 --- a/embassy-rp/src/clocks.rs +++ b/embassy-rp/src/clocks.rs @@ -46,13 +46,13 @@ static CLOCKS: Clocks = Clocks { #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum PeriClkSrc { - Sys = ClkPeriCtrlAuxsrc::CLK_SYS.0, - PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS.0, - PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB.0, - Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH.0, - Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC.0, - // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0.0, - // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1.0, + Sys = ClkPeriCtrlAuxsrc::CLK_SYS as _, + PllSys = ClkPeriCtrlAuxsrc::CLKSRC_PLL_SYS as _, + PllUsb = ClkPeriCtrlAuxsrc::CLKSRC_PLL_USB as _, + Rosc = ClkPeriCtrlAuxsrc::ROSC_CLKSRC_PH as _, + Xosc = ClkPeriCtrlAuxsrc::XOSC_CLKSRC as _, + // Gpin0 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN0 as _ , + // Gpin1 = ClkPeriCtrlAuxsrc::CLKSRC_GPIN1 as _ , } #[non_exhaustive] @@ -251,12 +251,12 @@ pub struct SysClkConfig { #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum UsbClkSrc { - PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB.0, - PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS.0, - Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH.0, - Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC.0, - // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0.0, - // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1.0, + PllUsb = ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB as _, + PllSys = ClkUsbCtrlAuxsrc::CLKSRC_PLL_SYS as _, + Rosc = ClkUsbCtrlAuxsrc::ROSC_CLKSRC_PH as _, + Xosc = ClkUsbCtrlAuxsrc::XOSC_CLKSRC as _, + // Gpin0 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN0 as _ , + // Gpin1 = ClkUsbCtrlAuxsrc::CLKSRC_GPIN1 as _ , } pub struct UsbClkConfig { @@ -269,12 +269,12 @@ pub struct UsbClkConfig { #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum AdcClkSrc { - PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB.0, - PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS.0, - Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH.0, - Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC.0, - // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0.0, - // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1.0, + PllUsb = ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB as _, + PllSys = ClkAdcCtrlAuxsrc::CLKSRC_PLL_SYS as _, + Rosc = ClkAdcCtrlAuxsrc::ROSC_CLKSRC_PH as _, + Xosc = ClkAdcCtrlAuxsrc::XOSC_CLKSRC as _, + // Gpin0 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN0 as _ , + // Gpin1 = ClkAdcCtrlAuxsrc::CLKSRC_GPIN1 as _ , } pub struct AdcClkConfig { @@ -287,12 +287,12 @@ pub struct AdcClkConfig { #[non_exhaustive] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RtcClkSrc { - PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB.0, - PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS.0, - Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH.0, - Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC.0, - // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0.0, - // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1.0, + PllUsb = ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB as _, + PllSys = ClkRtcCtrlAuxsrc::CLKSRC_PLL_SYS as _, + Rosc = ClkRtcCtrlAuxsrc::ROSC_CLKSRC_PH as _, + Xosc = ClkRtcCtrlAuxsrc::XOSC_CLKSRC as _, + // Gpin0 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN0 as _ , + // Gpin1 = ClkRtcCtrlAuxsrc::CLKSRC_GPIN1 as _ , } pub struct RtcClkConfig { @@ -396,7 +396,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { w.set_src(ref_src); w.set_auxsrc(ref_aux); }); - while c.clk_ref_selected().read() != 1 << ref_src.0 {} + while c.clk_ref_selected().read() != 1 << ref_src as u32 {} c.clk_ref_div().write(|w| { w.set_int(config.ref_clk.div); }); @@ -425,13 +425,13 @@ pub(crate) unsafe fn init(config: ClockConfig) { CLOCKS.sys.store(clk_sys_freq, Ordering::Relaxed); if sys_src != ClkSysCtrlSrc::CLK_REF { c.clk_sys_ctrl().write(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); - while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} + while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF as u32 {} } c.clk_sys_ctrl().write(|w| { w.set_auxsrc(sys_aux); w.set_src(sys_src); }); - while c.clk_sys_selected().read() != 1 << sys_src.0 {} + while c.clk_sys_selected().read() != 1 << sys_src as u32 {} c.clk_sys_div().write(|w| { w.set_int(config.sys_clk.div_int); w.set_frac(config.sys_clk.div_frac); @@ -442,7 +442,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { if let Some(src) = config.peri_clk_src { c.clk_peri_ctrl().write(|w| { w.set_enable(true); - w.set_auxsrc(ClkPeriCtrlAuxsrc(src as _)); + w.set_auxsrc(ClkPeriCtrlAuxsrc::from_bits(src as _)); }); let peri_freq = match src { PeriClkSrc::Sys => clk_sys_freq, @@ -468,7 +468,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_usb_ctrl().write(|w| { w.set_phase(conf.phase); w.set_enable(true); - w.set_auxsrc(ClkUsbCtrlAuxsrc(conf.src as _)); + w.set_auxsrc(ClkUsbCtrlAuxsrc::from_bits(conf.src as _)); }); let usb_freq = match conf.src { UsbClkSrc::PllUsb => pll_usb_freq, @@ -491,7 +491,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_adc_ctrl().write(|w| { w.set_phase(conf.phase); w.set_enable(true); - w.set_auxsrc(ClkAdcCtrlAuxsrc(conf.src as _)); + w.set_auxsrc(ClkAdcCtrlAuxsrc::from_bits(conf.src as _)); }); let adc_in_freq = match conf.src { AdcClkSrc::PllUsb => pll_usb_freq, @@ -517,7 +517,7 @@ pub(crate) unsafe fn init(config: ClockConfig) { c.clk_rtc_ctrl().write(|w| { w.set_phase(conf.phase); w.set_enable(true); - w.set_auxsrc(ClkRtcCtrlAuxsrc(conf.src as _)); + w.set_auxsrc(ClkRtcCtrlAuxsrc::from_bits(conf.src as _)); }); let rtc_in_freq = match conf.src { RtcClkSrc::PllUsb => pll_usb_freq, @@ -718,7 +718,7 @@ impl<'d, T: Pin> Drop for Gpin<'d, T> { self.gpin .io() .ctrl() - .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); + .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _)); } } @@ -743,17 +743,17 @@ impl_gpoutpin!(PIN_25, 3); #[repr(u8)] pub enum GpoutSrc { - PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS.0, - // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0.0, - // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1.0, - PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB.0, - Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC.0, - Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC.0, - Sys = ClkGpoutCtrlAuxsrc::CLK_SYS.0, - Usb = ClkGpoutCtrlAuxsrc::CLK_USB.0, - Adc = ClkGpoutCtrlAuxsrc::CLK_ADC.0, - Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC.0, - Ref = ClkGpoutCtrlAuxsrc::CLK_REF.0, + PllSys = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_SYS as _, + // Gpin0 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN0 as _ , + // Gpin1 = ClkGpoutCtrlAuxsrc::CLKSRC_GPIN1 as _ , + PllUsb = ClkGpoutCtrlAuxsrc::CLKSRC_PLL_USB as _, + Rosc = ClkGpoutCtrlAuxsrc::ROSC_CLKSRC as _, + Xosc = ClkGpoutCtrlAuxsrc::XOSC_CLKSRC as _, + Sys = ClkGpoutCtrlAuxsrc::CLK_SYS as _, + Usb = ClkGpoutCtrlAuxsrc::CLK_USB as _, + Adc = ClkGpoutCtrlAuxsrc::CLK_ADC as _, + Rtc = ClkGpoutCtrlAuxsrc::CLK_RTC as _, + Ref = ClkGpoutCtrlAuxsrc::CLK_REF as _, } pub struct Gpout<'d, T: GpoutPin> { @@ -780,7 +780,7 @@ impl<'d, T: GpoutPin> Gpout<'d, T> { pub fn set_src(&self, src: GpoutSrc) { let c = pac::CLOCKS; c.clk_gpout_ctrl(self.gpout.number()).modify(|w| { - w.set_auxsrc(ClkGpoutCtrlAuxsrc(src as _)); + w.set_auxsrc(ClkGpoutCtrlAuxsrc::from_bits(src as _)); }); } @@ -831,7 +831,7 @@ impl<'d, T: GpoutPin> Drop for Gpout<'d, T> { self.gpout .io() .ctrl() - .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0)); + .write(|w| w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _)); } } diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index ce0d02557..f8048a4dd 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -452,7 +452,7 @@ impl<'d, T: Pin> Flex<'d, T> { }); pin.io().ctrl().write(|w| { - w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0.0); + w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::SIO_0 as _); }); Self { pin } @@ -618,7 +618,7 @@ impl<'d, T: Pin> Drop for Flex<'d, T> { fn drop(&mut self) { self.pin.pad_ctrl().write(|_| {}); self.pin.io().ctrl().write(|w| { - w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL.0); + w.set_funcsel(pac::io::vals::Gpio0ctrlFuncsel::NULL as _); }); } } diff --git a/embassy-rp/src/pio.rs b/embassy-rp/src/pio.rs index 1b36e0a54..30648e8ea 100644 --- a/embassy-rp/src/pio.rs +++ b/embassy-rp/src/pio.rs @@ -834,7 +834,7 @@ impl<'d, PIO: Instance> Common<'d, PIO> { /// of [`Pio`] do not keep pin registrations alive.** pub fn make_pio_pin(&mut self, pin: impl Peripheral

+ 'd) -> Pin<'d, PIO> { into_ref!(pin); - pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL.0)); + pin.io().ctrl().write(|w| w.set_funcsel(PIO::FUNCSEL as _)); // we can be relaxed about this because we're &mut here and nothing is cached PIO::state().used_pins.fetch_or(1 << pin.pin_bank(), Ordering::Relaxed); Pin { @@ -998,7 +998,7 @@ fn on_pio_drop() { let state = PIO::state(); if state.users.fetch_sub(1, Ordering::AcqRel) == 1 { let used_pins = state.used_pins.load(Ordering::Relaxed); - let null = Gpio0ctrlFuncsel::NULL.0; + let null = Gpio0ctrlFuncsel::NULL as _; // we only have 30 pins. don't test the other two since gpio() asserts. for i in 0..30 { if used_pins & (1 << i) != 0 { From f7ec579c18b2ec925afcd4ab9a840719f4ce08cc Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jun 2023 02:39:28 +0200 Subject: [PATCH 66/74] Update probe-rs-cli -> probe-rs --- .vscode/settings.json | 6 +++--- cyw43/README.md | 12 ++++++------ embassy-nrf/src/lib.rs | 6 +++--- examples/boot/application/nrf/.cargo/config.toml | 4 ++-- examples/boot/application/rp/.cargo/config.toml | 2 +- examples/boot/application/stm32f3/.cargo/config.toml | 4 ++-- examples/boot/application/stm32f7/.cargo/config.toml | 4 ++-- examples/boot/application/stm32h7/.cargo/config.toml | 4 ++-- examples/boot/application/stm32h7/flash-boot.sh | 2 +- examples/boot/application/stm32l0/.cargo/config.toml | 4 ++-- examples/boot/application/stm32l1/.cargo/config.toml | 4 ++-- examples/boot/application/stm32l4/.cargo/config.toml | 4 ++-- examples/boot/application/stm32wl/.cargo/config.toml | 4 ++-- examples/boot/bootloader/nrf/.cargo/config.toml | 2 +- examples/boot/bootloader/rp/.cargo/config.toml | 2 +- examples/nrf-rtos-trace/.cargo/config.toml | 4 ++-- examples/nrf52840-rtic/.cargo/config.toml | 4 ++-- examples/nrf52840/.cargo/config.toml | 4 ++-- examples/nrf52840/src/bin/nvmc.rs | 2 +- examples/nrf52840/src/bin/wdt.rs | 2 +- examples/nrf5340/.cargo/config.toml | 4 ++-- examples/rp/.cargo/config.toml | 2 +- examples/rp/src/bin/wifi_ap_tcp_server.rs | 4 ++-- examples/rp/src/bin/wifi_blinky.rs | 4 ++-- examples/rp/src/bin/wifi_scan.rs | 4 ++-- examples/rp/src/bin/wifi_tcp_server.rs | 4 ++-- examples/stm32c0/.cargo/config.toml | 4 ++-- examples/stm32f0/.cargo/config.toml | 2 +- examples/stm32f1/.cargo/config.toml | 4 ++-- examples/stm32f2/.cargo/config.toml | 4 ++-- examples/stm32f3/.cargo/config.toml | 4 ++-- examples/stm32f4/.cargo/config.toml | 4 ++-- examples/stm32f7/.cargo/config.toml | 4 ++-- examples/stm32g0/.cargo/config.toml | 4 ++-- examples/stm32g4/.cargo/config.toml | 4 ++-- examples/stm32h5/.cargo/config.toml | 2 +- examples/stm32h7/.cargo/config.toml | 2 +- examples/stm32l0/.cargo/config.toml | 4 ++-- examples/stm32l1/.cargo/config.toml | 4 ++-- examples/stm32l4/.cargo/config.toml | 8 ++++---- examples/stm32l5/.cargo/config.toml | 4 ++-- examples/stm32u5/.cargo/config.toml | 4 ++-- examples/stm32wb/.cargo/config.toml | 4 ++-- examples/stm32wl/.cargo/config.toml | 4 ++-- tests/rp/src/bin/cyw43-perf.rs | 4 ++-- 45 files changed, 88 insertions(+), 88 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9ef7fe1ce..725fb69d0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,16 +6,16 @@ "rust-analyzer.check.allTargets": false, "rust-analyzer.check.noDefaultFeatures": true, "rust-analyzer.cargo.noDefaultFeatures": true, - "rust-analyzer.cargo.target": "thumbv7em-none-eabi", + "rust-analyzer.cargo.target": "thumbv7m-none-eabi", //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", "rust-analyzer.cargo.features": [ - "nightly", + ///"nightly", ], "rust-analyzer.linkedProjects": [ // Declare for the target you wish to develop // "embassy-executor/Cargo.toml", // "embassy-sync/Cargo.toml", - "examples/nrf52840/Cargo.toml", + "examples/stm32wl/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", // "examples/rp/Cargo.toml", diff --git a/cyw43/README.md b/cyw43/README.md index defea489f..e4a81410d 100644 --- a/cyw43/README.md +++ b/cyw43/README.md @@ -1,6 +1,6 @@ # cyw43 -WIP driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). +Rust driver for the CYW43439 wifi chip, used in the Raspberry Pi Pico W. Implementation based on [Infineon/wifi-host-driver](https://github.com/Infineon/wifi-host-driver). ## Current status @@ -19,18 +19,18 @@ Working: TODO: - Setting a custom MAC address. -- Bus sleep (unclear what the benefit is. Is it needed for IRQs? or is it just power consumption optimization?) +- Bus sleep (for power consumption optimization) ## Running the examples -- `cargo install probe-rs-cli` -- `cd examples/rpi-pico-w` +- `cargo install probe-rs --features cli` +- `cd examples/rp` ### Example 1: Scan the wifi stations - `cargo run --release --bin wifi_scan` ### Example 2: Create an access point (IP and credentials in the code) -- `cargo run --release --bin tcp_server_ap` +- `cargo run --release --bin wifi_ap_tcp_server` ### Example 3: Connect to an existing network and create a server -- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release` +- `WIFI_NETWORK=MyWifiNetwork WIFI_PASSWORD=MyWifiPassword cargo run --release --bin wifi_tcp_server` After a few seconds, you should see that DHCP picks up an IP address like this ``` diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 691545662..d23759f9d 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -410,13 +410,13 @@ pub fn init(config: config::Config) -> Peripherals { warn!( "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\ However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ - To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." + To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." ); #[cfg(feature = "reset-pin-as-gpio")] warn!( "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\ However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ - To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." + To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." ); } } @@ -432,7 +432,7 @@ pub fn init(config: config::Config) -> Peripherals { warn!( "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\ However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ - To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." + To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`." ); } } diff --git a/examples/boot/application/nrf/.cargo/config.toml b/examples/boot/application/nrf/.cargo/config.toml index 3872e7189..17616a054 100644 --- a/examples/boot/application/nrf/.cargo/config.toml +++ b/examples/boot/application/nrf/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip nRF52840_xxAA" +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF52840_xxAA" [build] target = "thumbv7em-none-eabi" diff --git a/examples/boot/application/rp/.cargo/config.toml b/examples/boot/application/rp/.cargo/config.toml index 278c24a57..cd8d1ef02 100644 --- a/examples/boot/application/rp/.cargo/config.toml +++ b/examples/boot/application/rp/.cargo/config.toml @@ -3,7 +3,7 @@ build-std = ["core"] build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs-cli run --chip RP2040" +runner = "probe-rs run --chip RP2040" [build] target = "thumbv6m-none-eabi" diff --git a/examples/boot/application/stm32f3/.cargo/config.toml b/examples/boot/application/stm32f3/.cargo/config.toml index 9fc2396e8..4a7ec0a5b 100644 --- a/examples/boot/application/stm32f3/.cargo/config.toml +++ b/examples/boot/application/stm32f3/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F303VCTx" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F303VCTx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/boot/application/stm32f7/.cargo/config.toml b/examples/boot/application/stm32f7/.cargo/config.toml index 7d6c88a99..9088eea6e 100644 --- a/examples/boot/application/stm32f7/.cargo/config.toml +++ b/examples/boot/application/stm32f7/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F767ZITx" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F767ZITx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/boot/application/stm32h7/.cargo/config.toml b/examples/boot/application/stm32h7/.cargo/config.toml index 067a5c89b..caa0d3a93 100644 --- a/examples/boot/application/stm32h7/.cargo/config.toml +++ b/examples/boot/application/stm32h7/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32H743ZITx" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32H743ZITx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/boot/application/stm32h7/flash-boot.sh b/examples/boot/application/stm32h7/flash-boot.sh index a3003681a..4912a50b7 100755 --- a/examples/boot/application/stm32h7/flash-boot.sh +++ b/examples/boot/application/stm32h7/flash-boot.sh @@ -1,5 +1,5 @@ #!/bin/bash -probe-rs-cli erase --chip STM32H743ZITx +probe-rs erase --chip STM32H743ZITx mv ../../bootloader/stm32/memory.x ../../bootloader/stm32/memory-old.x cp memory-bl.x ../../bootloader/stm32/memory.x diff --git a/examples/boot/application/stm32l0/.cargo/config.toml b/examples/boot/application/stm32l0/.cargo/config.toml index ce0e460bd..6099f015c 100644 --- a/examples/boot/application/stm32l0/.cargo/config.toml +++ b/examples/boot/application/stm32l0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32L072CZTx" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L072CZTx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/boot/application/stm32l1/.cargo/config.toml b/examples/boot/application/stm32l1/.cargo/config.toml index 1401500a0..9cabd14ba 100644 --- a/examples/boot/application/stm32l1/.cargo/config.toml +++ b/examples/boot/application/stm32l1/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32L151CBxxA" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L151CBxxA" [build] target = "thumbv7m-none-eabi" diff --git a/examples/boot/application/stm32l4/.cargo/config.toml b/examples/boot/application/stm32l4/.cargo/config.toml index 48ff3734b..c803215f6 100644 --- a/examples/boot/application/stm32l4/.cargo/config.toml +++ b/examples/boot/application/stm32l4/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32L475VG" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L475VG" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/boot/application/stm32wl/.cargo/config.toml b/examples/boot/application/stm32wl/.cargo/config.toml index b49b582e0..4f8094ff2 100644 --- a/examples/boot/application/stm32wl/.cargo/config.toml +++ b/examples/boot/application/stm32wl/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32WLE5JCIx" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32WLE5JCIx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/boot/bootloader/nrf/.cargo/config.toml b/examples/boot/bootloader/nrf/.cargo/config.toml index d636b1d23..c292846aa 100644 --- a/examples/boot/bootloader/nrf/.cargo/config.toml +++ b/examples/boot/bootloader/nrf/.cargo/config.toml @@ -4,7 +4,7 @@ build-std-features = ["panic_immediate_abort"] [target.'cfg(all(target_arch = "arm", target_os = "none"))'] #runner = "./fruitrunner" -runner = "probe-rs-cli run --chip nrf52840_xxAA" +runner = "probe-rs run --chip nrf52840_xxAA" rustflags = [ # Code-size optimizations. diff --git a/examples/boot/bootloader/rp/.cargo/config.toml b/examples/boot/bootloader/rp/.cargo/config.toml index 795ee043a..9d48ecdc9 100644 --- a/examples/boot/bootloader/rp/.cargo/config.toml +++ b/examples/boot/bootloader/rp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs-cli run --chip RP2040" +runner = "probe-rs run --chip RP2040" [build] target = "thumbv6m-none-eabi" diff --git a/examples/nrf-rtos-trace/.cargo/config.toml b/examples/nrf-rtos-trace/.cargo/config.toml index 3872e7189..17616a054 100644 --- a/examples/nrf-rtos-trace/.cargo/config.toml +++ b/examples/nrf-rtos-trace/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip nRF52840_xxAA" +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF52840_xxAA" [build] target = "thumbv7em-none-eabi" diff --git a/examples/nrf52840-rtic/.cargo/config.toml b/examples/nrf52840-rtic/.cargo/config.toml index 3872e7189..17616a054 100644 --- a/examples/nrf52840-rtic/.cargo/config.toml +++ b/examples/nrf52840-rtic/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip nRF52840_xxAA" +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF52840_xxAA" [build] target = "thumbv7em-none-eabi" diff --git a/examples/nrf52840/.cargo/config.toml b/examples/nrf52840/.cargo/config.toml index 3872e7189..17616a054 100644 --- a/examples/nrf52840/.cargo/config.toml +++ b/examples/nrf52840/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF82840_xxAA with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip nRF52840_xxAA" +# replace nRF82840_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF52840_xxAA" [build] target = "thumbv7em-none-eabi" diff --git a/examples/nrf52840/src/bin/nvmc.rs b/examples/nrf52840/src/bin/nvmc.rs index 33a44516d..31c6fe4b6 100644 --- a/examples/nrf52840/src/bin/nvmc.rs +++ b/examples/nrf52840/src/bin/nvmc.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { let p = embassy_nrf::init(Default::default()); info!("Hello NVMC!"); - // probe-rs-cli run breaks without this, I'm not sure why. + // probe-rs run breaks without this, I'm not sure why. Timer::after(Duration::from_secs(1)).await; let mut f = Nvmc::new(p.NVMC); diff --git a/examples/nrf52840/src/bin/wdt.rs b/examples/nrf52840/src/bin/wdt.rs index ccfd0e439..058746518 100644 --- a/examples/nrf52840/src/bin/wdt.rs +++ b/examples/nrf52840/src/bin/wdt.rs @@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) { let mut config = Config::default(); config.timeout_ticks = 32768 * 3; // 3 seconds - // This is needed for `probe-rs-cli run` to be able to catch the panic message + // This is needed for `probe-rs run` to be able to catch the panic message // in the WDT interrupt. The core resets 2 ticks after firing the interrupt. config.run_during_debug_halt = false; diff --git a/examples/nrf5340/.cargo/config.toml b/examples/nrf5340/.cargo/config.toml index d25355894..4c3cf3d32 100644 --- a/examples/nrf5340/.cargo/config.toml +++ b/examples/nrf5340/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace nRF5340_xxAA with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip nRF5340_xxAA" +# replace nRF5340_xxAA with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip nRF5340_xxAA" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/rp/.cargo/config.toml b/examples/rp/.cargo/config.toml index 2ee6fcb00..3d7d61740 100644 --- a/examples/rp/.cargo/config.toml +++ b/examples/rp/.cargo/config.toml @@ -1,5 +1,5 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -runner = "probe-rs-cli run --chip RP2040" +runner = "probe-rs run --chip RP2040" [build] target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index e8197390c..310e84d92 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs @@ -42,8 +42,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 - // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index be965807b..bbcb1b5ec 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs @@ -27,8 +27,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 - // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 79534f229..391e12282 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs @@ -39,8 +39,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 - // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 026e056fa..e9d1079a6 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs @@ -42,8 +42,8 @@ async fn main(spawner: Spawner) { // To make flashing faster for development, you may want to flash the firmwares independently // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: - // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 - // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; diff --git a/examples/stm32c0/.cargo/config.toml b/examples/stm32c0/.cargo/config.toml index 517101fae..29a8be7e1 100644 --- a/examples/stm32c0/.cargo/config.toml +++ b/examples/stm32c0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --speed 100 --chip STM32c031c6tx" +# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --speed 100 --chip STM32c031c6tx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32f0/.cargo/config.toml b/examples/stm32f0/.cargo/config.toml index bd0c0cd97..def4c8c92 100644 --- a/examples/stm32f0/.cargo/config.toml +++ b/examples/stm32f0/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv6m-none-eabi] -runner = 'probe-rs-cli run --chip STM32F091RCTX' +runner = 'probe-rs run --chip STM32F091RCTX' [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32f1/.cargo/config.toml b/examples/stm32f1/.cargo/config.toml index 81199c5aa..ce6fef11b 100644 --- a/examples/stm32f1/.cargo/config.toml +++ b/examples/stm32f1/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F103C8 with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F103C8" +# replace STM32F103C8 with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F103C8" [build] target = "thumbv7m-none-eabi" diff --git a/examples/stm32f2/.cargo/config.toml b/examples/stm32f2/.cargo/config.toml index 5532779c8..1198fcab8 100644 --- a/examples/stm32f2/.cargo/config.toml +++ b/examples/stm32f2/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F207ZGTx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F207ZGTx" +# replace STM32F207ZGTx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F207ZGTx" [build] target = "thumbv7m-none-eabi" diff --git a/examples/stm32f3/.cargo/config.toml b/examples/stm32f3/.cargo/config.toml index 7f3fda529..cb8a7c5af 100644 --- a/examples/stm32f3/.cargo/config.toml +++ b/examples/stm32f3/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F303ZETx" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F303ZETx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/stm32f4/.cargo/config.toml b/examples/stm32f4/.cargo/config.toml index bed04b68f..16efa8e6f 100644 --- a/examples/stm32f4/.cargo/config.toml +++ b/examples/stm32f4/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F429ZITx" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F429ZITx" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32f7/.cargo/config.toml b/examples/stm32f7/.cargo/config.toml index 7d6c88a99..9088eea6e 100644 --- a/examples/stm32f7/.cargo/config.toml +++ b/examples/stm32f7/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F767ZITx" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32F767ZITx" [build] target = "thumbv7em-none-eabihf" diff --git a/examples/stm32g0/.cargo/config.toml b/examples/stm32g0/.cargo/config.toml index a7a5fbd84..35cca5412 100644 --- a/examples/stm32g0/.cargo/config.toml +++ b/examples/stm32g0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32G071RBTx" +# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32G071RBTx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml index 606d7d5a3..d28ad069e 100644 --- a/examples/stm32g4/.cargo/config.toml +++ b/examples/stm32g4/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32G071C8Rx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32G484VETx" +# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32G484VETx" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32h5/.cargo/config.toml b/examples/stm32h5/.cargo/config.toml index c8b864b6c..478146142 100644 --- a/examples/stm32h5/.cargo/config.toml +++ b/examples/stm32h5/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv8m.main-none-eabihf] -runner = 'probe-rs-cli run --chip STM32H563ZITx' +runner = 'probe-rs run --chip STM32H563ZITx' [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/stm32h7/.cargo/config.toml b/examples/stm32h7/.cargo/config.toml index f08f57a54..5f680dbce 100644 --- a/examples/stm32h7/.cargo/config.toml +++ b/examples/stm32h7/.cargo/config.toml @@ -1,5 +1,5 @@ [target.thumbv7em-none-eabihf] -runner = 'probe-rs-cli run --chip STM32H743ZITx' +runner = 'probe-rs run --chip STM32H743ZITx' [build] target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) diff --git a/examples/stm32l0/.cargo/config.toml b/examples/stm32l0/.cargo/config.toml index 526f5a1f7..b050334b2 100644 --- a/examples/stm32l0/.cargo/config.toml +++ b/examples/stm32l0/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32L053R8Tx" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L053R8Tx" [build] target = "thumbv6m-none-eabi" diff --git a/examples/stm32l1/.cargo/config.toml b/examples/stm32l1/.cargo/config.toml index 1401500a0..9cabd14ba 100644 --- a/examples/stm32l1/.cargo/config.toml +++ b/examples/stm32l1/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32L151CBxxA" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L151CBxxA" [build] target = "thumbv7m-none-eabi" diff --git a/examples/stm32l4/.cargo/config.toml b/examples/stm32l4/.cargo/config.toml index abf55eb2e..36e74e5a5 100644 --- a/examples/stm32l4/.cargo/config.toml +++ b/examples/stm32l4/.cargo/config.toml @@ -1,8 +1,8 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# 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" +# replace STM32F429ZITx with your chip as listed in `probe-rs chip list` +#runner = "probe-rs run --chip STM32L475VGT6" +#runner = "probe-rs run --chip STM32L475VG" +runner = "probe-rs run --chip STM32L4S5VI" [build] target = "thumbv7em-none-eabi" diff --git a/examples/stm32l5/.cargo/config.toml b/examples/stm32l5/.cargo/config.toml index 1dc3a6fb7..86a145a27 100644 --- a/examples/stm32l5/.cargo/config.toml +++ b/examples/stm32l5/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32L552ZETxQ with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32L552ZETxQ" +# replace STM32L552ZETxQ with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32L552ZETxQ" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/stm32u5/.cargo/config.toml b/examples/stm32u5/.cargo/config.toml index cecd01938..36c5b63a6 100644 --- a/examples/stm32u5/.cargo/config.toml +++ b/examples/stm32u5/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace STM32U585AIIx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32U585AIIx" +# replace STM32U585AIIx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32U585AIIx" [build] target = "thumbv8m.main-none-eabihf" diff --git a/examples/stm32wb/.cargo/config.toml b/examples/stm32wb/.cargo/config.toml index 35317a297..8b6d6d754 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 STM32WB55RGVx --speed 1000 --connect-under-reset" +# replace STM32WB55CCUx with your chip as listed in `probe-rs chip list` +# runner = "probe-rs run --chip STM32WB55RGVx --speed 1000 --connect-under-reset" runner = "teleprobe local run --chip STM32WB55RG --elf" [build] diff --git a/examples/stm32wl/.cargo/config.toml b/examples/stm32wl/.cargo/config.toml index b49b582e0..4f8094ff2 100644 --- a/examples/stm32wl/.cargo/config.toml +++ b/examples/stm32wl/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] -# replace your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32WLE5JCIx" +# replace your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip STM32WLE5JCIx" [build] target = "thumbv7em-none-eabihf" diff --git a/tests/rp/src/bin/cyw43-perf.rs b/tests/rp/src/bin/cyw43-perf.rs index 9fc537a4b..1ecaab266 100644 --- a/tests/rp/src/bin/cyw43-perf.rs +++ b/tests/rp/src/bin/cyw43-perf.rs @@ -44,8 +44,8 @@ async fn main(spawner: Spawner) { } // cyw43 firmware needs to be flashed manually: - // probe-rs-cli download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000 - // probe-rs-cli download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000 + // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x101c0000 + // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x101f8000 let fw = unsafe { core::slice::from_raw_parts(0x101c0000 as *const u8, 224190) }; let clm = unsafe { core::slice::from_raw_parts(0x101f8000 as *const u8, 4752) }; From 01101e3df0619dca85ab692be8b7c38f249b44e8 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jun 2023 03:11:22 +0200 Subject: [PATCH 67/74] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 315d247ee..b05e55aa5 100644 --- a/README.md +++ b/README.md @@ -99,10 +99,10 @@ Examples are found in the `examples/` folder seperated by the chip manufacturer ### Running examples -- Install `probe-rs-cli` with defmt support. +- Install `probe-rs`. ```bash -cargo install probe-rs-cli +cargo install probe-rs --features cli ``` - Change directory to the sample's base directory. For example: From 96f1525ffe675b7e3ca26f038bc558488c03af9b Mon Sep 17 00:00:00 2001 From: Julian <20155974+JuliDi@users.noreply.github.com> Date: Thu, 29 Jun 2023 09:20:25 +0200 Subject: [PATCH 68/74] Revert changes to dma.rs --- embassy-stm32/src/dma/dma.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/embassy-stm32/src/dma/dma.rs b/embassy-stm32/src/dma/dma.rs index 9c03599eb..8abe541d3 100644 --- a/embassy-stm32/src/dma/dma.rs +++ b/embassy-stm32/src/dma/dma.rs @@ -405,11 +405,7 @@ impl<'a, C: Channel> Transfer<'a, C> { pub fn is_running(&mut self) -> bool { 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) + ch.cr().read().en() } /// Gets the total remaining transfers for the channel From f0b17675d89f87350faa8c61b491be53ef666894 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jun 2023 12:20:51 +0200 Subject: [PATCH 69/74] usb: add missing builder reexports. Fixes #1176 cc #1596 --- embassy-usb/src/class/cdc_ncm/mod.rs | 4 ++-- embassy-usb/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-usb/src/class/cdc_ncm/mod.rs b/embassy-usb/src/class/cdc_ncm/mod.rs index d5556dd0b..fcfa0bfcd 100644 --- a/embassy-usb/src/class/cdc_ncm/mod.rs +++ b/embassy-usb/src/class/cdc_ncm/mod.rs @@ -11,8 +11,8 @@ //! - On Pixel 4a, it refused to work on Android 11, worked on Android 12. //! - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte), //! it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled. -//! This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417 -//! and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757 +//! This is due to regex spaghetti: +//! and this nonsense in the linux kernel: use core::intrinsics::copy_nonoverlapping; use core::mem::{size_of, MaybeUninit}; diff --git a/embassy-usb/src/lib.rs b/embassy-usb/src/lib.rs index d8563d59a..1180b9b66 100644 --- a/embassy-usb/src/lib.rs +++ b/embassy-usb/src/lib.rs @@ -23,7 +23,7 @@ mod config { use embassy_futures::select::{select, Either}; use heapless::Vec; -pub use crate::builder::{Builder, Config}; +pub use crate::builder::{Builder, Config, FunctionBuilder, InterfaceAltBuilder, InterfaceBuilder}; use crate::config::*; use crate::control::*; use crate::descriptor::*; From 837d3bcdbb87af69d13cb799a137ad88ee015538 Mon Sep 17 00:00:00 2001 From: Kaspar Schleiser Date: Thu, 29 Jun 2023 14:43:31 +0200 Subject: [PATCH 70/74] embassy-boot/nrf/README.md: typo fix --- embassy-boot/nrf/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-boot/nrf/README.md b/embassy-boot/nrf/README.md index 7ce3c7021..fe581823d 100644 --- a/embassy-boot/nrf/README.md +++ b/embassy-boot/nrf/README.md @@ -6,7 +6,7 @@ An adaptation of `embassy-boot` for nRF. ## Features -* Load applications with our without the softdevice. +* Load applications with or without the softdevice. * Configure bootloader partitions based on linker script. * Using watchdog timer to detect application failure. From 2aa2b843ce6b96aacd72e52fe29b550e7ebc55b3 Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 29 Jun 2023 17:11:36 +0200 Subject: [PATCH 71/74] feature(1355): Add trigger to task, triggered + clear to Event --- embassy-nrf/src/ppi/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 7c18da6ee..ba95849e8 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -137,6 +137,11 @@ impl Task { Self(ptr) } + // Triggers this task. + pub unsafe fn trigger(&mut self) { + self.0.write(|w| unsafe { w.bits(1) }); + } + pub(crate) fn from_reg(reg: &T) -> Self { Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) } @@ -173,6 +178,16 @@ impl Event { Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) } + // Describes whether this Event is currently in a triggered state. + pub unsafe fn is_triggered(&self) -> bool { + self.0.read().bits() == 1 + } + + // Clear the current register's triggered state, reverting it to 0. + pub unsafe fn clear(&mut self) { + self.0.write(|w| unsafe { w.bits(0) }); + } + /// Address of publish register for this event. #[cfg(feature = "_dppi")] pub fn publish_reg(&self) -> *mut u32 { From e90f47aba31be9d99935c758d87941c7106cbece Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 29 Jun 2023 17:37:51 +0200 Subject: [PATCH 72/74] Fixed Pointer Updates --- embassy-nrf/src/ppi/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index ba95849e8..0789e2694 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -137,9 +137,9 @@ impl Task { Self(ptr) } - // Triggers this task. + /// Triggers this task. pub unsafe fn trigger(&mut self) { - self.0.write(|w| unsafe { w.bits(1) }); + *self.0.as_ptr() = 1; } pub(crate) fn from_reg(reg: &T) -> Self { @@ -178,14 +178,14 @@ impl Event { Self(unsafe { NonNull::new_unchecked(reg as *const _ as *mut _) }) } - // Describes whether this Event is currently in a triggered state. + /// Describes whether this Event is currently in a triggered state. pub unsafe fn is_triggered(&self) -> bool { - self.0.read().bits() == 1 + *self.0.as_ptr() == 1 } - // Clear the current register's triggered state, reverting it to 0. + /// Clear the current register's triggered state, reverting it to 0. pub unsafe fn clear(&mut self) { - self.0.write(|w| unsafe { w.bits(0) }); + *self.0.as_ptr() = 0; } /// Address of publish register for this event. From 3f19879f41e8c39c5c38e7905a180160b24807fc Mon Sep 17 00:00:00 2001 From: Cameron Date: Thu, 29 Jun 2023 17:44:46 +0200 Subject: [PATCH 73/74] PR Fixes --- embassy-nrf/src/ppi/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 0789e2694..76757a248 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -138,8 +138,8 @@ impl Task { } /// Triggers this task. - pub unsafe fn trigger(&mut self) { - *self.0.as_ptr() = 1; + pub fn trigger(&mut self) { + unsafe { self.0.as_ptr().write_volatile(1) }; } pub(crate) fn from_reg(reg: &T) -> Self { @@ -179,13 +179,13 @@ impl Event { } /// Describes whether this Event is currently in a triggered state. - pub unsafe fn is_triggered(&self) -> bool { - *self.0.as_ptr() == 1 + pub fn is_triggered(&self) -> bool { + unsafe { self.0.as_ptr().read_volatile() == 1 } } /// Clear the current register's triggered state, reverting it to 0. - pub unsafe fn clear(&mut self) { - *self.0.as_ptr() = 0; + pub fn clear(&mut self) { + unsafe { self.0.as_ptr().write_volatile(0) }; } /// Address of publish register for this event. From 6eac49186d5a5da4c310027e59adcd0bf44ae514 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 29 Jun 2023 19:51:16 +0200 Subject: [PATCH 74/74] Release embassy-net v0.1 --- embassy-net-driver-channel/Cargo.toml | 11 +++ embassy-net-driver-channel/README.md | 96 ++++++++++++++++++++ embassy-net-driver-channel/src/lib.rs | 1 + embassy-net-driver/Cargo.toml | 11 ++- embassy-net-driver/README.md | 16 ++++ embassy-net-w5500/src/lib.rs | 5 +- embassy-net/Cargo.toml | 9 +- embassy-net/README.md | 64 +++++++++---- embassy-net/src/lib.rs | 24 ++++- embassy-usb/src/class/cdc_ncm/embassy_net.rs | 5 +- examples/std/README.md | 23 +++++ 11 files changed, 238 insertions(+), 27 deletions(-) create mode 100644 embassy-net-driver-channel/README.md create mode 100644 examples/std/README.md diff --git a/embassy-net-driver-channel/Cargo.toml b/embassy-net-driver-channel/Cargo.toml index e475551e1..bee2e3021 100644 --- a/embassy-net-driver-channel/Cargo.toml +++ b/embassy-net-driver-channel/Cargo.toml @@ -2,6 +2,14 @@ name = "embassy-net-driver-channel" version = "0.1.0" edition = "2021" +license = "MIT OR Apache-2.0" +description = "High-level channel-based driver for the `embassy-net` async TCP/IP network stack." +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-channel-v$VERSION/embassy-net-driver-channel/src/" @@ -9,6 +17,9 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-d features = ["defmt"] target = "thumbv7em-none-eabi" +[package.metadata.docs.rs] +features = ["defmt"] + [dependencies] defmt = { version = "0.3", optional = true } log = { version = "0.4.14", optional = true } diff --git a/embassy-net-driver-channel/README.md b/embassy-net-driver-channel/README.md new file mode 100644 index 000000000..dd90e7ad2 --- /dev/null +++ b/embassy-net-driver-channel/README.md @@ -0,0 +1,96 @@ +# embassy-net-driver-channel + +This crate provides a toolkit for implementing [`embassy-net`](https://crates.io/crates/embassy-net) drivers in a +higher level way than implementing the [`embassy-net-driver`](https://crates.io/crates/embassy-net-driver) trait directly. + +The `embassy-net-driver` trait is polling-based. To implement it, you must write the packet receive/transmit state machines by +hand, and hook up the `Waker`s provided by `embassy-net` to the right interrupt handlers so that `embassy-net` +knows when to poll your driver again to make more progress. + +With `embassy-net-driver-channel` + +## A note about deadlocks + +When implementing a driver using this crate, it might be tempting to write it in the most straightforward way: + +```rust,ignore +loop { + // Wait for either.. + match select( + // ... the chip signaling an interrupt, indicating a packet is available to receive, or + irq_pin.wait_for_low(), + // ... a TX buffer becoming available, i.e. embassy-net wants to send a packet + tx_chan.tx_buf(), + ).await { + Either::First(_) => { + // a packet is ready to be received! + let buf = rx_chan.rx_buf().await; // allocate a rx buf from the packet queue + let n = receive_packet_over_spi(buf).await; + rx_chan.rx_done(n); + } + Either::Second(buf) => { + // a packet is ready to be sent! + send_packet_over_spi(buf).await; + tx_chan.tx_done(); + } + } +} +``` + +However, this code has a latent deadlock bug. The symptom is it can hang at `rx_chan.rx_buf().await` under load. + +The reason is that, under load, both the TX and RX queues can get full at the same time. When this happens, the `embassy-net` task stalls trying to send because the TX queue is full, therefore it stops processing packets in the RX queue. Your driver task also stalls because the RX queue is full, therefore it stops processing packets in the TX queue. + +The fix is to make sure to always service the TX queue while you're waiting for space to become available in the TX queue. For example, select on either "tx_chan.tx_buf() available" or "INT is low AND rx_chan.rx_buf() available": + +```rust,ignore +loop { + // Wait for either.. + match select( + async { + // ... the chip signaling an interrupt, indicating a packet is available to receive + irq_pin.wait_for_low().await; + // *AND* the buffer is ready... + rx_chan.rx_buf().await + }, + // ... or a TX buffer becoming available, i.e. embassy-net wants to send a packet + tx_chan.tx_buf(), + ).await { + Either::First(buf) => { + // a packet is ready to be received! + let n = receive_packet_over_spi(buf).await; + rx_chan.rx_done(n); + } + Either::Second(buf) => { + // a packet is ready to be sent! + send_packet_over_spi(buf).await; + tx_chan.tx_done(); + } + } +} +``` + +## Examples + +These `embassy-net` drivers are implemented using this crate. You can look at them for inspiration. + +- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W +- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. +- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip. +- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. + + +## Interoperability + +This crate can run on any executor. + + +## License + +This work is licensed under either of + +- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. diff --git a/embassy-net-driver-channel/src/lib.rs b/embassy-net-driver-channel/src/lib.rs index 0c8dcc22b..02a4c00d6 100644 --- a/embassy-net-driver-channel/src/lib.rs +++ b/embassy-net-driver-channel/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![doc = include_str!("../README.md")] // must go first! mod fmt; diff --git a/embassy-net-driver/Cargo.toml b/embassy-net-driver/Cargo.toml index ff6f29355..da6d9ad62 100644 --- a/embassy-net-driver/Cargo.toml +++ b/embassy-net-driver/Cargo.toml @@ -3,7 +3,13 @@ name = "embassy-net-driver" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" - +description = "Driver trait for the `embassy-net` async TCP/IP network stack." +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-driver-v$VERSION/embassy-net-driver/src/" @@ -11,5 +17,8 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-d features = ["defmt"] target = "thumbv7em-none-eabi" +[package.metadata.docs.rs] +features = ["defmt"] + [dependencies] defmt = { version = "0.3", optional = true } \ No newline at end of file diff --git a/embassy-net-driver/README.md b/embassy-net-driver/README.md index 84f25492d..6a757380d 100644 --- a/embassy-net-driver/README.md +++ b/embassy-net-driver/README.md @@ -1,5 +1,21 @@ # embassy-net-driver +This crate contains the driver trait necessary for adding [`embassy-net`](https://crates.io/crates/embassy-net) support +for a new hardware platform. + +If you want to *use* `embassy-net` with already made drivers, you should depend on the main `embassy-net` crate, not on this crate. + +If you are writing a driver, you should depend only on this crate, not on the main `embassy-net` crate. +This will allow your driver to continue working for newer `embassy-net` major versions, without needing an update, +if the driver trait has not had breaking changes. + +See also [`embassy-net-driver-channel`](https://crates.io/crates/embassy-net-driver-channel), which provides a higer-level API +to construct a driver that processes packets in its own background task and communicates with the `embassy-net` task via +packet queues for RX and TX. + +## Interoperability + +This crate can run on any executor. ## License diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-w5500/src/lib.rs index 6821373e3..efd9bed66 100644 --- a/embassy-net-w5500/src/lib.rs +++ b/embassy-net-w5500/src/lib.rs @@ -1,5 +1,6 @@ +//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. #![no_std] -/// [`embassy-net`](crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. + mod device; mod socket; mod spi; @@ -77,7 +78,7 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { } } -/// Obtain a driver for using the W5500 with [`embassy-net`](crates.io/crates/embassy-net). +/// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( mac_addr: [u8; 6], state: &'a mut State, diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index cef8247eb..e89039daa 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -3,7 +3,13 @@ name = "embassy-net" version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" - +description = "Async TCP/IP network stack for embedded systems" +repository = "https://github.com/embassy-rs/embassy" +categories = [ + "embedded", + "no-std", + "asynchronous", +] [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" @@ -44,7 +50,6 @@ smoltcp = { version = "0.10.0", default-features = false, features = [ ] } embassy-net-driver = { version = "0.1.0", path = "../embassy-net-driver" } -embassy-hal-common = { version = "0.1.0", path = "../embassy-hal-common" } embassy-time = { version = "0.1.0", path = "../embassy-time" } embassy-sync = { version = "0.2.0", path = "../embassy-sync" } embedded-io = { version = "0.4.0", optional = true } diff --git a/embassy-net/README.md b/embassy-net/README.md index 470926c58..48f9fd832 100644 --- a/embassy-net/README.md +++ b/embassy-net/README.md @@ -1,30 +1,56 @@ # embassy-net -embassy-net contains an async network API based on smoltcp and embassy, designed -for embedded systems. +`embassy-net` is a no-std no-alloc async network stack, designed for embedded systems. -## Running the example +It builds on [`smoltcp`](https://github.com/smoltcp-rs/smoltcp). It provides a higher-level and more opinionated +API. It glues together the components provided by `smoltcp`, handling the low-level details with defaults and +memory management designed to work well for embedded systems, aiiming for a more "Just Works" experience. -First, create the tap0 interface. You only need to do this once. +## Features -```sh -sudo ip tuntap add name tap0 mode tap user $USER -sudo ip link set tap0 up -sudo ip addr add 192.168.69.100/24 dev tap0 -sudo ip -6 addr add fe80::100/64 dev tap0 -sudo ip -6 addr add fdaa::100/64 dev tap0 -sudo ip -6 route add fe80::/64 dev tap0 -sudo ip -6 route add fdaa::/64 dev tap0 -``` +- IPv4, IPv6 +- Ethernet and bare-IP mediums. +- TCP, UDP, DNS, DHCPv4, IGMPv4 +- TCP sockets implement the `embedded-io` async traits. -Second, have something listening there. For example `nc -l 8000` +See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and +unimplemented features of the network protocols. -Then run the example located in the `examples` folder: +## Hardware support -```sh -cd $EMBASSY_ROOT/examples/std/ -cargo run --bin net -- --static-ip -``` +- [`esp-wifi`](https://github.com/esp-rs/esp-wifi) for WiFi support on bare-metal ESP32 chips. Maintained by Espressif. +- [`cyw43`](https://github.com/embassy-rs/embassy/tree/main/cyw43) for WiFi on CYW43xx chips, used in the Raspberry Pi Pico W +- [`embassy-usb`](https://github.com/embassy-rs/embassy/tree/main/embassy-usb) for Ethernet-over-USB (CDC NCM) support. +- [`embassy-stm32`](https://github.com/embassy-rs/embassy/tree/main/embassy-stm32) for the builtin Ethernet MAC in all STM32 chips (STM32F1, STM32F2, STM32F4, STM32F7, STM32H7, STM32H5). +- [`embassy-net-w5500`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-w5500) for Wiznet W5500 SPI Ethernet MAC+PHY chip. +- [`embassy-net-esp-hosted`](https://github.com/embassy-rs/embassy/tree/main/embassy-net-esp-hosted) for using ESP32 chips with the [`esp-hosted`](https://github.com/espressif/esp-hosted) firmware as WiFi adapters for another non-ESP32 MCU. + +## Examples + +- For usage with Embassy HALs and network chip drivers, search [here](https://github.com/embassy-rs/embassy/tree/main/examples) for `eth` or `wifi`. +- The [`esp-wifi` repo](https://github.com/esp-rs/esp-wifi) has examples for use on bare-metal ESP32 chips. +- For usage on `std` platforms, see [the `std` examples](https://github.com/embassy-rs/embassy/tree/main/examples/std/src/bin) + +## Adding support for new hardware + +To add `embassy-net` support for new hardware (i.e. a new Ethernet or WiFi chip, or +an Ethernet/WiFi MCU peripheral), you have to implement the [`embassy-net-driver`](https://crates.io/crates/embassy-net-driver) +traits. + +Alternatively, [`embassy-net-driver-channel`](https://crates.io/crates/embassy-net-driver-channel) provides a higer-level API +to construct a driver that processes packets in its own background task and communicates with the `embassy-net` task via +packet queues for RX and TX. + +Drivers should depend only on `embassy-net-driver` or `embassy-net-driver-channel`. Never on the main `embassy-net` crate. +This allows existing drivers to continue working for newer `embassy-net` major versions, without needing an update, if the driver +trait has not had breaking changes. + +## Interoperability + +This crate can run on any executor. + +[`embassy-time`](https://crates.io/crates/embassy-net-driver) is used for timekeeping and timeouts. You must +link an `embassy-time` driver in your project to use this crate. ## License diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 17a7a22a2..840d7a09a 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -419,7 +419,29 @@ impl Stack { }) .await?; - use embassy_hal_common::drop::OnDrop; + #[must_use = "to delay the drop handler invocation to the end of the scope"] + struct OnDrop { + f: core::mem::MaybeUninit, + } + + impl OnDrop { + fn new(f: F) -> Self { + Self { + f: core::mem::MaybeUninit::new(f), + } + } + + fn defuse(self) { + core::mem::forget(self) + } + } + + impl Drop for OnDrop { + fn drop(&mut self) { + unsafe { self.f.as_ptr().read()() } + } + } + let drop = OnDrop::new(|| { self.with_mut(|s, i| { let socket = s.sockets.get_mut::(i.dns_socket); diff --git a/embassy-usb/src/class/cdc_ncm/embassy_net.rs b/embassy-usb/src/class/cdc_ncm/embassy_net.rs index bc79b3671..670709021 100644 --- a/embassy-usb/src/class/cdc_ncm/embassy_net.rs +++ b/embassy-usb/src/class/cdc_ncm/embassy_net.rs @@ -1,4 +1,5 @@ -//! [`embassy-net`](crates.io/crates/embassy-net) driver for the CDC-NCM class. +//! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the CDC-NCM class. + use embassy_futures::select::{select, Either}; use embassy_net_driver_channel as ch; use embassy_net_driver_channel::driver::LinkState; @@ -79,7 +80,7 @@ impl<'d, D: Driver<'d>, const MTU: usize> Runner<'d, D, MTU> { pub type Device<'d, const MTU: usize> = embassy_net_driver_channel::Device<'d, MTU>; impl<'d, D: Driver<'d>> CdcNcmClass<'d, D> { - /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](crates.io/crates/embassy-net). + /// Obtain a driver for using the CDC-NCM class with [`embassy-net`](https://crates.io/crates/embassy-net). pub fn into_embassy_net_device( self, state: &'d mut State, diff --git a/examples/std/README.md b/examples/std/README.md new file mode 100644 index 000000000..adc795928 --- /dev/null +++ b/examples/std/README.md @@ -0,0 +1,23 @@ + +## Running the `embassy-net` examples + +First, create the tap0 interface. You only need to do this once. + +```sh +sudo ip tuntap add name tap0 mode tap user $USER +sudo ip link set tap0 up +sudo ip addr add 192.168.69.100/24 dev tap0 +sudo ip -6 addr add fe80::100/64 dev tap0 +sudo ip -6 addr add fdaa::100/64 dev tap0 +sudo ip -6 route add fe80::/64 dev tap0 +sudo ip -6 route add fdaa::/64 dev tap0 +``` + +Second, have something listening there. For example `nc -l 8000` + +Then run the example located in the `examples` folder: + +```sh +cd $EMBASSY_ROOT/examples/std/ +cargo run --bin net -- --static-ip +``` \ No newline at end of file