From 0427c442ea531673e18da304c7402927589b8d0b Mon Sep 17 00:00:00 2001 From: Gustav Toft Date: Thu, 4 Apr 2024 15:51:25 +0200 Subject: [PATCH 01/35] Implement raw sockets in embassy-net --- embassy-net/Cargo.toml | 6 +- embassy-net/src/lib.rs | 2 + embassy-net/src/raw.rs | 178 +++++++++++++++++++++++++++++++++++++++++ examples/rp/Cargo.toml | 2 +- 4 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 embassy-net/src/raw.rs diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index be9f1d784..47faaa205 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -16,11 +16,11 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" -features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp","raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] target = "thumbv7em-none-eabi" [package.metadata.docs.rs] -features = ["defmt", "tcp", "udp", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw","dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] [features] default = [] @@ -38,6 +38,8 @@ packet-trace = [] ## Enable UDP support udp = ["smoltcp/socket-udp"] +## Enable Raw support +raw = ["smoltcp/socket-raw"] ## Enable TCP support tcp = ["smoltcp/socket-tcp"] ## Enable DNS support diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 1c0cf1a12..05c8aec7b 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -20,6 +20,8 @@ pub mod tcp; mod time; #[cfg(feature = "udp")] pub mod udp; +#[cfg(feature = "raw")] +pub mod raw; use core::cell::RefCell; use core::future::{poll_fn, Future}; diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs new file mode 100644 index 000000000..a0e458fff --- /dev/null +++ b/embassy-net/src/raw.rs @@ -0,0 +1,178 @@ +//! Raw sockets. + +use core::cell::RefCell; +use core::future::poll_fn; +use core::mem; +use core::task::{Context, Poll}; + +use embassy_net_driver::Driver; +use smoltcp::iface::{Interface, SocketHandle}; +use smoltcp::socket::raw; +pub use smoltcp::socket::raw::PacketMetadata; +use smoltcp::wire::{IpProtocol, IpVersion}; + +use crate::{SocketStack, Stack}; + + +/// Unrelavent for RawSocket? +/* /// Error returned by [`RawSocket::bind`]. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum BindError { + /// The socket was already open. + InvalidState, + /// No route to host. + NoRoute, +} */ + +/// Error returned by [`RawSocket::recv_from`] and [`RawSocket::send_to`]. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum SendError { + /// No route to host. + NoRoute, + /// Socket not bound to an outgoing port. + SocketNotBound, +} + +/// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RecvError { + /// Provided buffer was smaller than the received packet. + Truncated, +} + +/// An Raw socket. +pub struct RawSocket<'a> { + stack: &'a RefCell, + handle: SocketHandle, +} + +impl<'a> RawSocket<'a> { + /// Create a new Raw socket using the provided stack and buffers. + pub fn new( + stack: &'a Stack, + ip_version: IpVersion, + ip_protocol: IpProtocol, + rx_meta: &'a mut [PacketMetadata], + rx_buffer: &'a mut [u8], + tx_meta: &'a mut [PacketMetadata], + tx_buffer: &'a mut [u8], + ) -> Self { + let s = &mut *stack.socket.borrow_mut(); + + let rx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(rx_meta) }; + let rx_buffer: &'static mut [u8] = unsafe { mem::transmute(rx_buffer) }; + let tx_meta: &'static mut [PacketMetadata] = unsafe { mem::transmute(tx_meta) }; + let tx_buffer: &'static mut [u8] = unsafe { mem::transmute(tx_buffer) }; + let handle = s.sockets.add(raw::Socket::new( + ip_version, + ip_protocol, + raw::PacketBuffer::new(rx_meta, rx_buffer), + raw::PacketBuffer::new(tx_meta, tx_buffer), + )); + + Self { + stack: &stack.socket, + handle, + } + } + + fn with_mut(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { + let s = &mut *self.stack.borrow_mut(); + let socket = s.sockets.get_mut::(self.handle); + let res = f(socket, &mut s.iface); + s.waker.wake(); + res + } + + /// Bind the socket to a local endpoint. + /// + /// How to handle this in RawSocket? no need for bind? + /// + /* pub fn bind(&mut self, endpoint: T) -> Result<(), BindError> + where + T: Into, + { + let mut endpoint = endpoint.into(); + + if endpoint.port == 0 { + // If user didn't specify port allocate a dynamic port. + endpoint.port = self.stack.borrow_mut().get_local_port(); + } + + match self.with_mut(|s, _| s.bind(endpoint)) { + Ok(()) => Ok(()), + Err(raw::BindError::InvalidState) => Err(BindError::InvalidState), + Err(raw::BindError::Unaddressable) => Err(BindError::NoRoute), + } + } + + fn with(&self, f: impl FnOnce(&raw::Socket, &Interface) -> R) -> R { + let s = &*self.stack.borrow(); + let socket = s.sockets.get::(self.handle); + f(socket, &s.iface) + } + + fn with_mut(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { + let s = &mut *self.stack.borrow_mut(); + let socket = s.sockets.get_mut::(self.handle); + let res = f(socket, &mut s.iface); + s.waker.wake(); + res + } */ + + /// Receive a datagram. + /// + /// This method will wait until a datagram is received. + pub async fn recv(&self, buf: &mut [u8]) -> Result { + poll_fn(move |cx| self.poll_recv(buf, cx)).await + } + + /// Receive a datagram. + /// + /// When no datagram is available, this method will return `Poll::Pending` and + /// register the current task to be notified when a datagram is received. + pub fn poll_recv(&self, buf: &mut [u8], cx: &mut Context<'_>) -> Poll> { + self.with_mut(|s, _| match s.recv_slice(buf) { + Ok(n) => Poll::Ready(Ok(n)), + // No data ready + Err(raw::RecvError::Truncated) => Poll::Ready(Err(RecvError::Truncated)), + Err(raw::RecvError::Exhausted) => { + s.register_recv_waker(cx.waker()); + Poll::Pending + } + }) + } + + /// Send a datagram. + /// + /// This method will wait until the datagram has been sent.` + pub async fn send(&self, buf: &[u8]) -> Result<(), SendError> { + poll_fn(move |cx| self.poll_send(buf, cx)).await + } + + /// Send a datagram. + /// + /// When the datagram has been sent, this method will return `Poll::Ready(Ok())`. + /// + /// When the socket's send buffer is full, this method will return `Poll::Pending` + /// and register the current task to be notified when the buffer has space available. + pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll>{ + self.with_mut(|s, _| match s.send_slice(buf) { + // Entire datagram has been sent + Ok(()) => Poll::Ready(Ok(())), + Err(raw::SendError::BufferFull) => { + s.register_send_waker(cx.waker()); + Poll::Pending + } + }) + } + } + +impl Drop for RawSocket<'_> { + fn drop(&mut self) { + self.stack.borrow_mut().sockets.remove(self.handle); + } +} diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 585349506..0f58f143c 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -12,7 +12,7 @@ embassy-executor = { version = "0.5.0", path = "../../embassy-executor", feature embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl"] } embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } -embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "dhcpv4", "medium-ethernet"] } +embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "udp", "raw", "dhcpv4", "medium-ethernet"] } embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-usb-logger = { version = "0.1.0", path = "../../embassy-usb-logger" } From c953b9045b40fd3ece546ef94714fa2f108e0c25 Mon Sep 17 00:00:00 2001 From: Torin Cooper-Bennun Date: Fri, 5 Apr 2024 13:00:33 +0100 Subject: [PATCH 02/35] stm32: adc: v3: [h5] set OR.OP0 to 1 when ADCx_INP0 is selected, per RM --- embassy-stm32/src/adc/v3.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 8c9b47197..e25630be2 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -222,6 +222,13 @@ impl<'d, T: Instance> Adc<'d, T> { // spin } + // RM0492, RM0481, etc. + // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." + #[cfg(adc_h5)] + if pin.channel() == 0 { + T::regs().or().modify(|reg| reg.set_op0(true)); + } + // Configure channel Self::set_channel_sample_time(pin.channel(), self.sample_time); @@ -244,6 +251,13 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|reg| reg.set_addis(true)); + // RM0492, RM0481, etc. + // "This option bit must be set to 1 when ADCx_INP0 or ADCx_INN1 channel is selected." + #[cfg(adc_h5)] + if pin.channel() == 0 { + T::regs().or().modify(|reg| reg.set_op0(false)); + } + val } From 2ad82c2adf123d3e555724f77149ce9ab9c2bd8c Mon Sep 17 00:00:00 2001 From: Dillon McEwan Date: Fri, 5 Apr 2024 10:07:15 -0700 Subject: [PATCH 03/35] Fix 'clocok' typo in RCC docs --- embassy-stm32/src/rcc/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index d53d02203..c328344aa 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -111,7 +111,7 @@ mod util { } } -/// Get the kernel clocok frequency of the peripheral `T`. +/// Get the kernel clock frequency of the peripheral `T`. /// /// # Panics /// From 99ea564f1c5cc3dcce908cb853f528a52cca8ae8 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Fri, 5 Apr 2024 22:11:01 +0200 Subject: [PATCH 04/35] Add VBUS detection blackpill comment --- examples/stm32f4/src/bin/usb_hid_keyboard.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/stm32f4/src/bin/usb_hid_keyboard.rs b/examples/stm32f4/src/bin/usb_hid_keyboard.rs index a799b4e72..d6e0be5ea 100644 --- a/examples/stm32f4/src/bin/usb_hid_keyboard.rs +++ b/examples/stm32f4/src/bin/usb_hid_keyboard.rs @@ -49,6 +49,7 @@ async fn main(_spawner: Spawner) { // Create the driver, from the HAL. let mut ep_out_buffer = [0u8; 256]; let mut config = embassy_stm32::usb::Config::default(); + // If the board you’re using doesn’t have the VBUS pin wired up correctly for detecting the USB bus voltage (e.g. on the f4 blackpill board), set this to false config.vbus_detection = true; let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); From cf0097162cb33d77d90ce5cb50f8fb5c24972748 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Sun, 7 Apr 2024 15:19:56 +0200 Subject: [PATCH 05/35] [embassy-stm32] added comments explaining multiprio interrupts --- examples/stm32f0/src/bin/multiprio.rs | 4 ++++ examples/stm32f3/src/bin/multiprio.rs | 4 ++++ examples/stm32f4/src/bin/multiprio.rs | 4 ++++ examples/stm32h7/src/bin/multiprio.rs | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index e49951726..e36c0d6c2 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs @@ -126,6 +126,10 @@ fn main() -> ! { // Initialize and create handle for devicer peripherals let _p = embassy_stm32::init(Default::default()); + // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used + // by the rest of your application. In this case we’re using UART1 and UART2, but there’s nothing special + // about them. Any otherwise unused interrupt vector would work exactly the same. + // High-priority executor: USART1, priority level 6 interrupt::USART1.set_priority(Priority::P6); let spawner = EXECUTOR_HIGH.start(interrupt::USART1); diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 328447210..3a3059db1 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs @@ -127,6 +127,10 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); + // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used + // by the rest of your application. In this case we’re using UART4 and UART5, but there’s nothing special + // about them. Any otherwise unused interrupt vector would work exactly the same. + // High-priority executor: UART4, priority level 6 interrupt::UART4.set_priority(Priority::P6); let spawner = EXECUTOR_HIGH.start(interrupt::UART4); diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 328447210..5a55cd291 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs @@ -127,6 +127,10 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); + // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used + // by the rest of your application. In this case we’re using UART6 and UART7, but there’s nothing special + // about them. Any otherwise unused interrupt vector would work exactly the same. + // High-priority executor: UART4, priority level 6 interrupt::UART4.set_priority(Priority::P6); let spawner = EXECUTOR_HIGH.start(interrupt::UART4); diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs index 73f8dd092..f9a00f806 100644 --- a/examples/stm32h7/src/bin/multiprio.rs +++ b/examples/stm32h7/src/bin/multiprio.rs @@ -127,6 +127,10 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); + // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used + // by the rest of your application. In this case we’re using UART6 and UART7, but there’s nothing special + // about them. Any otherwise unused interrupt vector would work exactly the same. + // High-priority executor: UART4, priority level 6 interrupt::UART4.set_priority(Priority::P6); let spawner = EXECUTOR_HIGH.start(interrupt::UART4); From 56d34eefaa2862ebaf883e5388f909f7989aba1f Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Sun, 7 Apr 2024 15:33:51 +0200 Subject: [PATCH 06/35] Apply suggestions from code review Co-authored-by: becothas <41289937+becothas@users.noreply.github.com> --- examples/stm32f4/src/bin/multiprio.rs | 2 +- examples/stm32h7/src/bin/multiprio.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 5a55cd291..3a3059db1 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs @@ -128,7 +128,7 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used - // by the rest of your application. In this case we’re using UART6 and UART7, but there’s nothing special + // by the rest of your application. In this case we’re using UART4 and UART5, but there’s nothing special // about them. Any otherwise unused interrupt vector would work exactly the same. // High-priority executor: UART4, priority level 6 diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs index f9a00f806..ded9d390e 100644 --- a/examples/stm32h7/src/bin/multiprio.rs +++ b/examples/stm32h7/src/bin/multiprio.rs @@ -128,7 +128,7 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used - // by the rest of your application. In this case we’re using UART6 and UART7, but there’s nothing special + // by the rest of your application. In this case we’re using UART4 and UART5, but there’s nothing special // about them. Any otherwise unused interrupt vector would work exactly the same. // High-priority executor: UART4, priority level 6 From effc08dde34c39da3f6bb4363d517de4f5c1ddd4 Mon Sep 17 00:00:00 2001 From: Barnaby Walters Date: Sun, 7 Apr 2024 16:22:42 +0200 Subject: [PATCH 07/35] =?UTF-8?q?Incorporated=20adam=E2=80=99s=20suggestio?= =?UTF-8?q?n=20into=20all=20multiprio=20comments?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/stm32f0/src/bin/multiprio.rs | 7 ++++--- examples/stm32f3/src/bin/multiprio.rs | 7 ++++--- examples/stm32f4/src/bin/multiprio.rs | 7 ++++--- examples/stm32h7/src/bin/multiprio.rs | 7 ++++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/examples/stm32f0/src/bin/multiprio.rs b/examples/stm32f0/src/bin/multiprio.rs index e36c0d6c2..1c3f3991a 100644 --- a/examples/stm32f0/src/bin/multiprio.rs +++ b/examples/stm32f0/src/bin/multiprio.rs @@ -126,9 +126,10 @@ fn main() -> ! { // Initialize and create handle for devicer peripherals let _p = embassy_stm32::init(Default::default()); - // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used - // by the rest of your application. In this case we’re using UART1 and UART2, but there’s nothing special - // about them. Any otherwise unused interrupt vector would work exactly the same. + // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as + // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. + // In this case we’re using UART1 and UART2, but there’s nothing special about them. Any otherwise unused interrupt + // vector would work exactly the same. // High-priority executor: USART1, priority level 6 interrupt::USART1.set_priority(Priority::P6); diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs index 3a3059db1..87830b416 100644 --- a/examples/stm32f3/src/bin/multiprio.rs +++ b/examples/stm32f3/src/bin/multiprio.rs @@ -127,9 +127,10 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); - // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used - // by the rest of your application. In this case we’re using UART4 and UART5, but there’s nothing special - // about them. Any otherwise unused interrupt vector would work exactly the same. + // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as + // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. + // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt + // vector would work exactly the same. // High-priority executor: UART4, priority level 6 interrupt::UART4.set_priority(Priority::P6); diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs index 3a3059db1..87830b416 100644 --- a/examples/stm32f4/src/bin/multiprio.rs +++ b/examples/stm32f4/src/bin/multiprio.rs @@ -127,9 +127,10 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); - // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used - // by the rest of your application. In this case we’re using UART4 and UART5, but there’s nothing special - // about them. Any otherwise unused interrupt vector would work exactly the same. + // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as + // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. + // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt + // vector would work exactly the same. // High-priority executor: UART4, priority level 6 interrupt::UART4.set_priority(Priority::P6); diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs index ded9d390e..fcbb6c653 100644 --- a/examples/stm32h7/src/bin/multiprio.rs +++ b/examples/stm32h7/src/bin/multiprio.rs @@ -127,9 +127,10 @@ fn main() -> ! { let _p = embassy_stm32::init(Default::default()); - // STM32s don’t have software-defined interrupts, so just use any free interrupt vectors which aren’t used - // by the rest of your application. In this case we’re using UART4 and UART5, but there’s nothing special - // about them. Any otherwise unused interrupt vector would work exactly the same. + // STM32s don’t have any interrupts exclusively for software use, but they can all be triggered by software as well as + // by the peripheral, so we can just use any free interrupt vectors which aren’t used by the rest of your application. + // In this case we’re using UART4 and UART5, but there’s nothing special about them. Any otherwise unused interrupt + // vector would work exactly the same. // High-priority executor: UART4, priority level 6 interrupt::UART4.set_priority(Priority::P6); From fa05256f0563716ffa6e865b73679f4d545bcff9 Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Mon, 8 Apr 2024 00:39:58 +0200 Subject: [PATCH 08/35] embassy-sync: Add len, is_empty and is_full functions to Channel. --- embassy-sync/CHANGELOG.md | 5 ++++- embassy-sync/src/channel.rs | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/embassy-sync/CHANGELOG.md b/embassy-sync/CHANGELOG.md index e7db97ef7..3f6b39d8b 100644 --- a/embassy-sync/CHANGELOG.md +++ b/embassy-sync/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +- Add `len`, `is_empty` and `is_full` functions to `Channel`. + ## 0.5.0 - 2023-12-04 - Add a PriorityChannel. @@ -35,7 +39,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove unnecessary uses of `atomic-polyfill` - Add `#[must_use]` to all futures. - ## 0.1.0 - 2022-08-26 - First release diff --git a/embassy-sync/src/channel.rs b/embassy-sync/src/channel.rs index 48f4dafd6..18be462cb 100644 --- a/embassy-sync/src/channel.rs +++ b/embassy-sync/src/channel.rs @@ -449,6 +449,18 @@ impl ChannelState { Poll::Pending } } + + fn len(&self) -> usize { + self.queue.len() + } + + fn is_empty(&self) -> bool { + self.queue.is_empty() + } + + fn is_full(&self) -> bool { + self.queue.is_full() + } } /// A bounded channel for communicating between asynchronous tasks @@ -572,6 +584,21 @@ where pub fn try_receive(&self) -> Result { self.lock(|c| c.try_receive()) } + + /// Returns the number of elements currently in the channel. + pub fn len(&self) -> usize { + self.lock(|c| c.len()) + } + + /// Returns whether the channel is empty. + pub fn is_empty(&self) -> bool { + self.lock(|c| c.is_empty()) + } + + /// Returns whether the channel is full. + pub fn is_full(&self) -> bool { + self.lock(|c| c.is_full()) + } } /// Implements the DynamicChannel to allow creating types that are unaware of the queue size with the From 03a87add156258ebb14d96e7d0b6b8597015e69a Mon Sep 17 00:00:00 2001 From: Adam Simpkins Date: Sun, 7 Apr 2024 14:37:52 -0700 Subject: [PATCH 09/35] USB: fix comments about the config.max_packet_size_0 field Fix the comment about the default value: this defaults to 64 rather than 8 bytes. It seems like the max packet size for endpoint 0 should normally be selected automatically, rather than being part of the config. At best it seems like this setting should just be a hint that gets used if when the bus is operating at full speed. The contents of the device descriptor should ideally be updated with the correct max packet size after bus enumeration completes. In practice always using 64 is probably fine if low speed environments never need to be supported. (Super speed requires a max packet size of 512 bytes, which I didn't list in the comments here.) --- embassy-usb/src/builder.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/embassy-usb/src/builder.rs b/embassy-usb/src/builder.rs index c06107396..387b780de 100644 --- a/embassy-usb/src/builder.rs +++ b/embassy-usb/src/builder.rs @@ -38,11 +38,12 @@ pub struct Config<'a> { /// Maximum packet size in bytes for the control endpoint 0. /// - /// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default - /// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in - /// which case using a larger packet size may be more efficient. + /// Valid values depend on the speed at which the bus is enumerated. + /// - low speed: 8 + /// - full speed: 8, 16, 32, or 64 + /// - high speed: 64 /// - /// Default: 8 bytes + /// Default: 64 bytes pub max_packet_size_0: u8, /// Manufacturer name string descriptor. From fd802ffdfd5611b9a4e0a967a7a13fd6f8159fa3 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Tue, 9 Apr 2024 22:32:09 +0300 Subject: [PATCH 10/35] stm32: use embedded_hal_1::delay::DelayNs This makes delay compatible with https://lib.rs/crates/rtic-monotonics. --- embassy-stm32/src/adc/f1.rs | 6 +++--- embassy-stm32/src/adc/f3.rs | 6 +++--- embassy-stm32/src/adc/v1.rs | 10 +++++----- embassy-stm32/src/adc/v2.rs | 4 ++-- embassy-stm32/src/adc/v3.rs | 6 +++--- embassy-stm32/src/adc/v4.rs | 6 +++--- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index cecf67947..2dbce8043 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embedded_hal_02::blocking::delay::DelayUs; +use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::time::Hertz; @@ -48,7 +48,7 @@ impl super::SealedAdcPin for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { into_ref!(adc); T::enable_and_reset(); T::regs().cr2().modify(|reg| reg.set_adon(true)); @@ -95,7 +95,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vref(&self, _delay: &mut impl DelayUs) -> Vref { + pub fn enable_vref(&self, _delay: &mut impl DelayNs) -> Vref { T::regs().cr2().modify(|reg| { reg.set_tsvrefe(true); }); diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index c5581dba1..4ffbe5bf1 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embedded_hal_02::blocking::delay::DelayUs; +use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; @@ -58,7 +58,7 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn new( adc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - delay: &mut impl DelayUs, + delay: &mut impl DelayNs, ) -> Self { use crate::pac::adc::vals; @@ -117,7 +117,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vref(&self, _delay: &mut impl DelayUs) -> Vref { + pub fn enable_vref(&self, _delay: &mut impl DelayNs) -> Vref { T::common_regs().ccr().modify(|w| w.set_vrefen(true)); Vref {} diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index e9b46be80..3099b47d1 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -3,7 +3,7 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embedded_hal_02::blocking::delay::DelayUs; +use embedded_hal_1::delay::DelayNs; #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; @@ -65,7 +65,7 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn new( adc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - delay: &mut impl DelayUs, + delay: &mut impl DelayNs, ) -> Self { into_ref!(adc); T::enable_and_reset(); @@ -114,7 +114,7 @@ impl<'d, T: Instance> Adc<'d, T> { } #[cfg(not(adc_l0))] - pub fn enable_vbat(&self, _delay: &mut impl DelayUs) -> Vbat { + pub fn enable_vbat(&self, _delay: &mut impl DelayNs) -> Vbat { // SMP must be ≥ 56 ADC clock cycles when using HSI14. // // 6.3.20 Vbat monitoring characteristics @@ -123,7 +123,7 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat } - pub fn enable_vref(&self, delay: &mut impl DelayUs) -> Vref { + pub fn enable_vref(&self, delay: &mut impl DelayNs) -> Vref { // Table 28. Embedded internal reference voltage // tstart = 10μs T::regs().ccr().modify(|reg| reg.set_vrefen(true)); @@ -131,7 +131,7 @@ impl<'d, T: Instance> Adc<'d, T> { Vref } - pub fn enable_temperature(&self, delay: &mut impl DelayUs) -> Temperature { + pub fn enable_temperature(&self, delay: &mut impl DelayNs) -> Temperature { // SMP must be ≥ 56 ADC clock cycles when using HSI14. // // 6.3.19 Temperature sensor characteristics diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index a43eb72db..21782cf89 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,5 +1,5 @@ use embassy_hal_internal::into_ref; -use embedded_hal_02::blocking::delay::DelayUs; +use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; @@ -97,7 +97,7 @@ impl<'d, T> Adc<'d, T> where T: Instance, { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { into_ref!(adc); T::enable_and_reset(); diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index e25630be2..ba01e71fd 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,6 +1,6 @@ use cfg_if::cfg_if; use embassy_hal_internal::into_ref; -use embedded_hal_02::blocking::delay::DelayUs; +use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::Peripheral; @@ -74,7 +74,7 @@ cfg_if! { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { into_ref!(adc); T::enable_and_reset(); T::regs().cr().modify(|reg| { @@ -106,7 +106,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vrefint(&self, delay: &mut impl DelayUs) -> VrefInt { + pub fn enable_vrefint(&self, delay: &mut impl DelayNs) -> VrefInt { #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 1ae25bea2..4320de714 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,4 +1,4 @@ -use embedded_hal_02::blocking::delay::DelayUs; +use embedded_hal_1::delay::DelayNs; #[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; @@ -129,7 +129,7 @@ impl Prescaler { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayUs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { embassy_hal_internal::into_ref!(adc); T::enable_and_reset(); @@ -173,7 +173,7 @@ impl<'d, T: Instance> Adc<'d, T> { s } - fn power_up(&mut self, delay: &mut impl DelayUs) { + fn power_up(&mut self, delay: &mut impl DelayNs) { T::regs().cr().modify(|reg| { reg.set_deeppwd(false); reg.set_advregen(true); From 6663be0b36a078893b0ef3f3f869b17adf62ca30 Mon Sep 17 00:00:00 2001 From: Gustav Toft Date: Wed, 10 Apr 2024 09:07:20 +0200 Subject: [PATCH 11/35] Fixed commented issues. --- .vscode/settings.json | 12 ++++---- embassy-net/Cargo.toml | 4 +-- embassy-net/src/lib.rs | 4 +-- embassy-net/src/raw.rs | 64 ++---------------------------------------- 4 files changed, 13 insertions(+), 71 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 0c195a13b..343331950 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,24 +10,24 @@ "rust-analyzer.cargo.noDefaultFeatures": true, "rust-analyzer.showUnlinkedFileNotification": false, // uncomment the target of your chip. - //"rust-analyzer.cargo.target": "thumbv6m-none-eabi", + "rust-analyzer.cargo.target": "thumbv6m-none-eabi", //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", - "rust-analyzer.cargo.target": "thumbv7em-none-eabi", + //"rust-analyzer.cargo.target": "thumbv7em-none-eabi", //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", - "rust-analyzer.cargo.features": [ + /* "rust-analyzer.cargo.features": [ "stm32f103c8", "time-driver-any", "unstable-pac", "exti", - ], + ], */ "rust-analyzer.linkedProjects": [ // Uncomment ONE line for the chip you want to work on. // This makes rust-analyzer work on the example crate and all its dependencies. - "embassy-stm32/Cargo.toml", + // "embassy-stm32/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", - // "examples/rp/Cargo.toml", + "examples/rp/Cargo.toml", // "examples/std/Cargo.toml", // "examples/stm32c0/Cargo.toml", // "examples/stm32f0/Cargo.toml", diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 47faaa205..ee7289ad8 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -16,11 +16,11 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" -features = ["defmt", "tcp", "udp","raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] target = "thumbv7em-none-eabi" [package.metadata.docs.rs] -features = ["defmt", "tcp", "udp", "raw","dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] [features] default = [] diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 05c8aec7b..86ced1ded 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -15,13 +15,13 @@ pub(crate) mod fmt; mod device; #[cfg(feature = "dns")] pub mod dns; +#[cfg(feature = "raw")] +pub mod raw; #[cfg(feature = "tcp")] pub mod tcp; mod time; #[cfg(feature = "udp")] pub mod udp; -#[cfg(feature = "raw")] -pub mod raw; use core::cell::RefCell; use core::future::{poll_fn, Future}; diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index a0e458fff..ad8d69853 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -13,28 +13,6 @@ use smoltcp::wire::{IpProtocol, IpVersion}; use crate::{SocketStack, Stack}; - -/// Unrelavent for RawSocket? -/* /// Error returned by [`RawSocket::bind`]. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum BindError { - /// The socket was already open. - InvalidState, - /// No route to host. - NoRoute, -} */ - -/// Error returned by [`RawSocket::recv_from`] and [`RawSocket::send_to`]. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum SendError { - /// No route to host. - NoRoute, - /// Socket not bound to an outgoing port. - SocketNotBound, -} - /// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -87,42 +65,6 @@ impl<'a> RawSocket<'a> { res } - /// Bind the socket to a local endpoint. - /// - /// How to handle this in RawSocket? no need for bind? - /// - /* pub fn bind(&mut self, endpoint: T) -> Result<(), BindError> - where - T: Into, - { - let mut endpoint = endpoint.into(); - - if endpoint.port == 0 { - // If user didn't specify port allocate a dynamic port. - endpoint.port = self.stack.borrow_mut().get_local_port(); - } - - match self.with_mut(|s, _| s.bind(endpoint)) { - Ok(()) => Ok(()), - Err(raw::BindError::InvalidState) => Err(BindError::InvalidState), - Err(raw::BindError::Unaddressable) => Err(BindError::NoRoute), - } - } - - fn with(&self, f: impl FnOnce(&raw::Socket, &Interface) -> R) -> R { - let s = &*self.stack.borrow(); - let socket = s.sockets.get::(self.handle); - f(socket, &s.iface) - } - - fn with_mut(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res - } */ - /// Receive a datagram. /// /// This method will wait until a datagram is received. @@ -149,7 +91,7 @@ impl<'a> RawSocket<'a> { /// Send a datagram. /// /// This method will wait until the datagram has been sent.` - pub async fn send(&self, buf: &[u8]) -> Result<(), SendError> { + pub async fn send(&self, buf: &[u8]) -> Result<(), raw::SendError> { poll_fn(move |cx| self.poll_send(buf, cx)).await } @@ -159,7 +101,7 @@ impl<'a> RawSocket<'a> { /// /// When the socket's send buffer is full, this method will return `Poll::Pending` /// and register the current task to be notified when the buffer has space available. - pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll>{ + pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll> { self.with_mut(|s, _| match s.send_slice(buf) { // Entire datagram has been sent Ok(()) => Poll::Ready(Ok(())), @@ -169,7 +111,7 @@ impl<'a> RawSocket<'a> { } }) } - } +} impl Drop for RawSocket<'_> { fn drop(&mut self) { From 68b1a840c6350f0c158ef17887a801808dc01f33 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 10 Apr 2024 10:30:24 +0300 Subject: [PATCH 12/35] stm32 adc: remove DelayNs --- embassy-stm32/src/adc/f1.rs | 19 +++++++++++++------ embassy-stm32/src/adc/f3.rs | 17 +++++++++++------ embassy-stm32/src/adc/v1.rs | 23 +++++++++++++++-------- embassy-stm32/src/adc/v2.rs | 11 +++++------ embassy-stm32/src/adc/v3.rs | 24 +++++++++++++++--------- embassy-stm32/src/adc/v4.rs | 17 +++++++++++------ 6 files changed, 70 insertions(+), 41 deletions(-) diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index 2dbce8043..dd4b3489b 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::time::Hertz; @@ -48,14 +47,18 @@ impl super::SealedAdcPin for Temperature { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd) -> Self { into_ref!(adc); T::enable_and_reset(); T::regs().cr2().modify(|reg| reg.set_adon(true)); // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) - // for at least two ADC clock cycles - delay.delay_us((1_000_000 * 2) / Self::freq().0 + 1); + // for at least two ADC clock cycles. + let us = (1_000_000 * 2) / Self::freq().0 + 1; + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(us)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / (1000_000 / us)); // Reset calibration T::regs().cr2().modify(|reg| reg.set_rstcal(true)); @@ -70,7 +73,11 @@ impl<'d, T: Instance> Adc<'d, T> { } // One cycle after calibration - delay.delay_us((1_000_000) / Self::freq().0 + 1); + let us = (1_000_000 * 1) / Self::freq().0 + 1; + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(us)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / (1000_000 / us)); Self { adc, @@ -95,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vref(&self, _delay: &mut impl DelayNs) -> Vref { + pub fn enable_vref(&self) -> Vref { T::regs().cr2().modify(|reg| { reg.set_tsvrefe(true); }); diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 4ffbe5bf1..1a62b7707 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; @@ -58,7 +57,6 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn new( adc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - delay: &mut impl DelayNs, ) -> Self { use crate::pac::adc::vals; @@ -71,7 +69,10 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); // Wait for the regulator to stabilize - delay.delay_us(10); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(10)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); assert!(!T::regs().cr().read().aden()); @@ -81,8 +82,12 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} - // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223) - delay.delay_us(1 + (6 * 1_000_000 / Self::freq().0)); + // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). + let us = (1_000_000 * 4) / Self::freq().0 + 1; + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(us)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / (1000_000 / us)); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); @@ -117,7 +122,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vref(&self, _delay: &mut impl DelayNs) -> Vref { + pub fn enable_vref(&self) -> Vref { T::common_regs().ccr().modify(|w| w.set_vrefen(true)); Vref {} diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 3099b47d1..960990c39 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -3,7 +3,6 @@ use core::marker::PhantomData; use core::task::Poll; use embassy_hal_internal::into_ref; -use embedded_hal_1::delay::DelayNs; #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; @@ -65,7 +64,6 @@ impl<'d, T: Instance> Adc<'d, T> { pub fn new( adc: impl Peripheral

+ 'd, _irq: impl interrupt::typelevel::Binding> + 'd, - delay: &mut impl DelayNs, ) -> Self { into_ref!(adc); T::enable_and_reset(); @@ -74,7 +72,10 @@ impl<'d, T: Instance> Adc<'d, T> { // // Table 57. ADC characteristics // tstab = 14 * 1/fadc - delay.delay_us(1); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(1)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1000_000); // set default PCKL/2 on L0s because HSI is disabled in the default clock config #[cfg(adc_l0)] @@ -114,7 +115,7 @@ impl<'d, T: Instance> Adc<'d, T> { } #[cfg(not(adc_l0))] - pub fn enable_vbat(&self, _delay: &mut impl DelayNs) -> Vbat { + pub fn enable_vbat(&self) -> Vbat { // SMP must be ≥ 56 ADC clock cycles when using HSI14. // // 6.3.20 Vbat monitoring characteristics @@ -123,22 +124,28 @@ impl<'d, T: Instance> Adc<'d, T> { Vbat } - pub fn enable_vref(&self, delay: &mut impl DelayNs) -> Vref { + pub fn enable_vref(&self) -> Vref { // Table 28. Embedded internal reference voltage // tstart = 10μs T::regs().ccr().modify(|reg| reg.set_vrefen(true)); - delay.delay_us(10); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(10)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); Vref } - pub fn enable_temperature(&self, delay: &mut impl DelayNs) -> Temperature { + pub fn enable_temperature(&self) -> Temperature { // SMP must be ≥ 56 ADC clock cycles when using HSI14. // // 6.3.19 Temperature sensor characteristics // tstart ≤ 10μs // ts_temp ≥ 4μs T::regs().ccr().modify(|reg| reg.set_tsen(true)); - delay.delay_us(10); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(10)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); Temperature } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 21782cf89..1ac119508 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,5 +1,4 @@ use embassy_hal_internal::into_ref; -use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; @@ -11,9 +10,6 @@ pub const VREF_DEFAULT_MV: u32 = 3300; /// VREF voltage used for factory calibration of VREFINTCAL register. pub const VREF_CALIB_MV: u32 = 3300; -/// ADC turn-on time -pub const ADC_POWERUP_TIME_US: u32 = 3; - pub struct VrefInt; impl AdcPin for VrefInt {} impl super::SealedAdcPin for VrefInt { @@ -97,7 +93,7 @@ impl<'d, T> Adc<'d, T> where T: Instance, { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd) -> Self { into_ref!(adc); T::enable_and_reset(); @@ -107,7 +103,10 @@ where reg.set_adon(true); }); - delay.delay_us(ADC_POWERUP_TIME_US); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(5)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 200_000); Self { adc, diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index ba01e71fd..a5e09646a 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,6 +1,5 @@ use cfg_if::cfg_if; use embassy_hal_internal::into_ref; -use embedded_hal_1::delay::DelayNs; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::Peripheral; @@ -74,7 +73,7 @@ cfg_if! { } impl<'d, T: Instance> Adc<'d, T> { - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd) -> Self { into_ref!(adc); T::enable_and_reset(); T::regs().cr().modify(|reg| { @@ -88,7 +87,10 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_chselrmod(false); }); - delay.delay_us(20); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(20)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 50_000); T::regs().cr().modify(|reg| { reg.set_adcal(true); @@ -98,7 +100,10 @@ impl<'d, T: Instance> Adc<'d, T> { // spin } - delay.delay_us(1); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(1)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1000_000); Self { adc, @@ -106,7 +111,7 @@ impl<'d, T: Instance> Adc<'d, T> { } } - pub fn enable_vrefint(&self, delay: &mut impl DelayNs) -> VrefInt { + pub fn enable_vrefint(&self) -> VrefInt { #[cfg(not(adc_g0))] T::common_regs().ccr().modify(|reg| { reg.set_vrefen(true); @@ -117,10 +122,11 @@ impl<'d, T: Instance> Adc<'d, T> { }); // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us - // to stabilize the internal voltage reference, we wait a little more. - // TODO: delay 15us - //cortex_m::asm::delay(20_000_000); - delay.delay_us(15); + // to stabilize the internal voltage reference. + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(20)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 50_000); VrefInt {} } diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 4320de714..018104dd6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -1,4 +1,3 @@ -use embedded_hal_1::delay::DelayNs; #[allow(unused)] use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; @@ -129,7 +128,7 @@ impl Prescaler { impl<'d, T: Instance> Adc<'d, T> { /// Create a new ADC driver. - pub fn new(adc: impl Peripheral

+ 'd, delay: &mut impl DelayNs) -> Self { + pub fn new(adc: impl Peripheral

+ 'd) -> Self { embassy_hal_internal::into_ref!(adc); T::enable_and_reset(); @@ -161,11 +160,14 @@ impl<'d, T: Instance> Adc<'d, T> { adc, sample_time: SampleTime::from_bits(0), }; - s.power_up(delay); + s.power_up(); s.configure_differential_inputs(); s.calibrate(); - delay.delay_us(1); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(1)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1000_000); s.enable(); s.configure(); @@ -173,13 +175,16 @@ impl<'d, T: Instance> Adc<'d, T> { s } - fn power_up(&mut self, delay: &mut impl DelayNs) { + fn power_up(&mut self) { T::regs().cr().modify(|reg| { reg.set_deeppwd(false); reg.set_advregen(true); }); - delay.delay_us(10); + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(10)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); } fn configure_differential_inputs(&mut self) { From fd901fc7e052cdf1b48327140d78712b1e076220 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 10 Apr 2024 10:49:42 +0300 Subject: [PATCH 13/35] stm32: update adc examples --- examples/stm32f0/src/bin/adc.rs | 6 +++--- examples/stm32f1/src/bin/adc.rs | 6 +++--- examples/stm32f334/src/bin/adc.rs | 6 +++--- examples/stm32f334/src/bin/opamp.rs | 6 +++--- examples/stm32f4/src/bin/adc.rs | 2 +- examples/stm32f7/src/bin/adc.rs | 4 ++-- examples/stm32g4/src/bin/adc.rs | 4 ++-- examples/stm32h7/src/bin/adc.rs | 4 ++-- examples/stm32l0/src/bin/adc.rs | 6 +++--- examples/stm32l4/src/bin/adc.rs | 3 +-- tests/stm32/src/bin/dac.rs | 4 ++-- 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/examples/stm32f0/src/bin/adc.rs b/examples/stm32f0/src/bin/adc.rs index c2fb143cd..a5a4186ea 100644 --- a/examples/stm32f0/src/bin/adc.rs +++ b/examples/stm32f0/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; use embassy_stm32::{adc, bind_interrupts}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC, Irqs); adc.set_sample_time(SampleTime::CYCLES71_5); let mut pin = p.PA1; - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32f031c6.pdf diff --git a/examples/stm32f1/src/bin/adc.rs b/examples/stm32f1/src/bin/adc.rs index 1440460a9..541ff159e 100644 --- a/examples/stm32f1/src/bin/adc.rs +++ b/examples/stm32f1/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::peripherals::ADC1; use embassy_stm32::{adc, bind_interrupts}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -18,10 +18,10 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1); let mut pin = p.PB1; - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From http://www.st.com/resource/en/datasheet/CD00161566.pdf diff --git a/examples/stm32f334/src/bin/adc.rs b/examples/stm32f334/src/bin/adc.rs index bd126ce68..0528a9637 100644 --- a/examples/stm32f334/src/bin/adc.rs +++ b/examples/stm32f334/src/bin/adc.rs @@ -7,7 +7,7 @@ use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC1; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -38,13 +38,13 @@ async fn main(_spawner: Spawner) -> ! { info!("create adc..."); - let mut adc = Adc::new(p.ADC1, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC1, Irqs); adc.set_sample_time(SampleTime::CYCLES601_5); info!("enable vrefint..."); - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); loop { diff --git a/examples/stm32f334/src/bin/opamp.rs b/examples/stm32f334/src/bin/opamp.rs index a5c710aa2..2dbf1bdab 100644 --- a/examples/stm32f334/src/bin/opamp.rs +++ b/examples/stm32f334/src/bin/opamp.rs @@ -8,7 +8,7 @@ use embassy_stm32::opamp::{OpAmp, OpAmpGain}; use embassy_stm32::peripherals::ADC2; use embassy_stm32::time::mhz; use embassy_stm32::{adc, bind_interrupts, Config}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -39,14 +39,14 @@ async fn main(_spawner: Spawner) -> ! { info!("create adc..."); - let mut adc = Adc::new(p.ADC2, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC2, Irqs); let mut opamp = OpAmp::new(p.OPAMP2); adc.set_sample_time(SampleTime::CYCLES601_5); info!("enable vrefint..."); - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let mut temperature = adc.enable_temperature(); let mut buffer = opamp.buffer_ext(&mut p.PA7, &mut p.PA6, OpAmpGain::Mul1); diff --git a/examples/stm32f4/src/bin/adc.rs b/examples/stm32f4/src/bin/adc.rs index 699c29c05..9473b7b7f 100644 --- a/examples/stm32f4/src/bin/adc.rs +++ b/examples/stm32f4/src/bin/adc.rs @@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut delay = Delay; - let mut adc = Adc::new(p.ADC1, &mut delay); + let mut adc = Adc::new(p.ADC1); let mut pin = p.PC1; let mut vrefint = adc.enable_vrefint(); diff --git a/examples/stm32f7/src/bin/adc.rs b/examples/stm32f7/src/bin/adc.rs index f8d7b691f..641157960 100644 --- a/examples/stm32f7/src/bin/adc.rs +++ b/examples/stm32f7/src/bin/adc.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::Adc; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -12,7 +12,7 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1); let mut pin = p.PA3; let mut vrefint = adc.enable_vrefint(); diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index ae64bc8e4..68b54e406 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { let mut p = embassy_stm32::init(config); info!("Hello World!"); - let mut adc = Adc::new(p.ADC2, &mut Delay); + let mut adc = Adc::new(p.ADC2); adc.set_sample_time(SampleTime::CYCLES32_5); loop { diff --git a/examples/stm32h7/src/bin/adc.rs b/examples/stm32h7/src/bin/adc.rs index a5594d10c..0009103d1 100644 --- a/examples/stm32h7/src/bin/adc.rs +++ b/examples/stm32h7/src/bin/adc.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::Config; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -44,7 +44,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); - let mut adc = Adc::new(p.ADC3, &mut Delay); + let mut adc = Adc::new(p.ADC3); adc.set_sample_time(SampleTime::CYCLES32_5); diff --git a/examples/stm32l0/src/bin/adc.rs b/examples/stm32l0/src/bin/adc.rs index 97d41ca4b..507c3204a 100644 --- a/examples/stm32l0/src/bin/adc.rs +++ b/examples/stm32l0/src/bin/adc.rs @@ -6,7 +6,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::{Adc, SampleTime}; use embassy_stm32::peripherals::ADC; use embassy_stm32::{adc, bind_interrupts}; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; bind_interrupts!(struct Irqs { @@ -18,11 +18,11 @@ async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); info!("Hello World!"); - let mut adc = Adc::new(p.ADC, Irqs, &mut Delay); + let mut adc = Adc::new(p.ADC, Irqs); adc.set_sample_time(SampleTime::CYCLES79_5); let mut pin = p.PA1; - let mut vrefint = adc.enable_vref(&mut Delay); + let mut vrefint = adc.enable_vref(); let vrefint_sample = adc.read(&mut vrefint).await; let convert_to_millivolts = |sample| { // From https://www.st.com/resource/en/datasheet/stm32l051c6.pdf diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs index a9f4604aa..7a89334e0 100644 --- a/examples/stm32l4/src/bin/adc.rs +++ b/examples/stm32l4/src/bin/adc.rs @@ -4,7 +4,6 @@ use defmt::*; use embassy_stm32::adc::{Adc, Resolution}; use embassy_stm32::Config; -use embassy_time::Delay; use {defmt_rtt as _, panic_probe as _}; #[cortex_m_rt::entry] @@ -18,7 +17,7 @@ fn main() -> ! { } let p = embassy_stm32::init(config); - let mut adc = Adc::new(p.ADC1, &mut Delay); + let mut adc = Adc::new(p.ADC1); //adc.enable_vref(); adc.set_resolution(Resolution::BITS8); let mut channel = p.PC0; diff --git a/tests/stm32/src/bin/dac.rs b/tests/stm32/src/bin/dac.rs index 9d64742df..06501ab14 100644 --- a/tests/stm32/src/bin/dac.rs +++ b/tests/stm32/src/bin/dac.rs @@ -13,7 +13,7 @@ use embassy_executor::Spawner; use embassy_stm32::adc::Adc; use embassy_stm32::dac::{DacCh1, Value}; use embassy_stm32::dma::NoDma; -use embassy_time::{Delay, Timer}; +use embassy_time::Timer; use micromath::F32Ext; use {defmt_rtt as _, panic_probe as _}; @@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) { let mut adc_pin = unsafe { core::ptr::read(&dac_pin) }; let mut dac = DacCh1::new(dac, NoDma, dac_pin); - let mut adc = Adc::new(adc, &mut Delay); + let mut adc = Adc::new(adc); #[cfg(feature = "stm32h755zi")] let normalization_factor = 256; From fcb270bcede54d975ff89c05691131d2a898638f Mon Sep 17 00:00:00 2001 From: Priit Laes Date: Wed, 10 Apr 2024 11:00:30 +0300 Subject: [PATCH 14/35] nrf: Add basic CHANGELOG summarizing changes in embassy-nrf --- embassy-nrf/CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 embassy-nrf/CHANGELOG.md diff --git a/embassy-nrf/CHANGELOG.md b/embassy-nrf/CHANGELOG.md new file mode 100644 index 000000000..773a1a108 --- /dev/null +++ b/embassy-nrf/CHANGELOG.md @@ -0,0 +1,40 @@ +# Changelog for embassy-nrf + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +- Drop `sealed` mod +- nrf52840: Add dcdc voltage parameter to configure REG0 regulator +- radio: Add support for IEEE 802.15.4 and BLE via radio peripheral +- spim: Reduce trace-level messages ("Copying SPIM tx buffer..") +- uart: Add support for rx- or tx-only BufferedUart +- uart: Implement splitting Rx/Tx +- spi: Allow specifying OutputDrive for SPI spins +- pdm: Fix gain register value derivation +- spim: Implement chunked DMA transfers +- spi: Add bounds checks for EasyDMA buffer size +- uarte: Add support for handling RX errors +- nrf51: Implement support for nrf51 chip +- pwm: Expose `duty` method +- pwm: Fix infinite loop +- spi: Add support for configuring bit order for bus +- pwm: Expose `pwm::PWM_CLK_HZ` and add `is_enabled` method +- gpio: Drop GPIO Pin generics (API break) + +## 0.1.0 - 2024-01-12 + +- First release with support for following NRF chips: + - nrf52805 + - nrf52810 + - nrf52811 + - nrf52820 + - nrf52832 + - nrf52833 + - nrf52840 + - nrf5340 + - nrf9160 + From 11bf2ca987f5830fe8637029adbc208b1ff7349d Mon Sep 17 00:00:00 2001 From: Gustav Toft Date: Wed, 10 Apr 2024 13:26:12 +0200 Subject: [PATCH 15/35] Fixed commented issues --- embassy-net/Cargo.toml | 4 +-- embassy-net/src/lib.rs | 4 +-- embassy-net/src/raw.rs | 64 ++---------------------------------------- 3 files changed, 7 insertions(+), 65 deletions(-) diff --git a/embassy-net/Cargo.toml b/embassy-net/Cargo.toml index 47faaa205..ee7289ad8 100644 --- a/embassy-net/Cargo.toml +++ b/embassy-net/Cargo.toml @@ -16,11 +16,11 @@ categories = [ [package.metadata.embassy_docs] src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-v$VERSION/embassy-net/src/" src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net/src/" -features = ["defmt", "tcp", "udp","raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] target = "thumbv7em-none-eabi" [package.metadata.docs.rs] -features = ["defmt", "tcp", "udp", "raw","dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] +features = ["defmt", "tcp", "udp", "raw", "dns", "dhcpv4", "proto-ipv6", "medium-ethernet", "medium-ip", "medium-ieee802154", "igmp", "dhcpv4-hostname"] [features] default = [] diff --git a/embassy-net/src/lib.rs b/embassy-net/src/lib.rs index 05c8aec7b..86ced1ded 100644 --- a/embassy-net/src/lib.rs +++ b/embassy-net/src/lib.rs @@ -15,13 +15,13 @@ pub(crate) mod fmt; mod device; #[cfg(feature = "dns")] pub mod dns; +#[cfg(feature = "raw")] +pub mod raw; #[cfg(feature = "tcp")] pub mod tcp; mod time; #[cfg(feature = "udp")] pub mod udp; -#[cfg(feature = "raw")] -pub mod raw; use core::cell::RefCell; use core::future::{poll_fn, Future}; diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index a0e458fff..ad8d69853 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -13,28 +13,6 @@ use smoltcp::wire::{IpProtocol, IpVersion}; use crate::{SocketStack, Stack}; - -/// Unrelavent for RawSocket? -/* /// Error returned by [`RawSocket::bind`]. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum BindError { - /// The socket was already open. - InvalidState, - /// No route to host. - NoRoute, -} */ - -/// Error returned by [`RawSocket::recv_from`] and [`RawSocket::send_to`]. -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum SendError { - /// No route to host. - NoRoute, - /// Socket not bound to an outgoing port. - SocketNotBound, -} - /// Error returned by [`RawSocket::recv`] and [`RawSocket::send`]. #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -87,42 +65,6 @@ impl<'a> RawSocket<'a> { res } - /// Bind the socket to a local endpoint. - /// - /// How to handle this in RawSocket? no need for bind? - /// - /* pub fn bind(&mut self, endpoint: T) -> Result<(), BindError> - where - T: Into, - { - let mut endpoint = endpoint.into(); - - if endpoint.port == 0 { - // If user didn't specify port allocate a dynamic port. - endpoint.port = self.stack.borrow_mut().get_local_port(); - } - - match self.with_mut(|s, _| s.bind(endpoint)) { - Ok(()) => Ok(()), - Err(raw::BindError::InvalidState) => Err(BindError::InvalidState), - Err(raw::BindError::Unaddressable) => Err(BindError::NoRoute), - } - } - - fn with(&self, f: impl FnOnce(&raw::Socket, &Interface) -> R) -> R { - let s = &*self.stack.borrow(); - let socket = s.sockets.get::(self.handle); - f(socket, &s.iface) - } - - fn with_mut(&self, f: impl FnOnce(&mut raw::Socket, &mut Interface) -> R) -> R { - let s = &mut *self.stack.borrow_mut(); - let socket = s.sockets.get_mut::(self.handle); - let res = f(socket, &mut s.iface); - s.waker.wake(); - res - } */ - /// Receive a datagram. /// /// This method will wait until a datagram is received. @@ -149,7 +91,7 @@ impl<'a> RawSocket<'a> { /// Send a datagram. /// /// This method will wait until the datagram has been sent.` - pub async fn send(&self, buf: &[u8]) -> Result<(), SendError> { + pub async fn send(&self, buf: &[u8]) -> Result<(), raw::SendError> { poll_fn(move |cx| self.poll_send(buf, cx)).await } @@ -159,7 +101,7 @@ impl<'a> RawSocket<'a> { /// /// When the socket's send buffer is full, this method will return `Poll::Pending` /// and register the current task to be notified when the buffer has space available. - pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll>{ + pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll> { self.with_mut(|s, _| match s.send_slice(buf) { // Entire datagram has been sent Ok(()) => Poll::Ready(Ok(())), @@ -169,7 +111,7 @@ impl<'a> RawSocket<'a> { } }) } - } +} impl Drop for RawSocket<'_> { fn drop(&mut self) { From 6e24dc58c6395cc5d733d676986d3b336ce7a220 Mon Sep 17 00:00:00 2001 From: Andres Vahter Date: Wed, 10 Apr 2024 16:47:58 +0300 Subject: [PATCH 16/35] stm32 adc: use fn blocking_delay_us(us: u32) --- embassy-stm32/src/adc/f1.rs | 13 +++---------- embassy-stm32/src/adc/f3.rs | 12 +++--------- embassy-stm32/src/adc/mod.rs | 9 +++++++++ embassy-stm32/src/adc/v1.rs | 16 ++++------------ embassy-stm32/src/adc/v2.rs | 6 ++---- embassy-stm32/src/adc/v3.rs | 16 ++++------------ embassy-stm32/src/adc/v4.rs | 12 +++--------- 7 files changed, 28 insertions(+), 56 deletions(-) diff --git a/embassy-stm32/src/adc/f1.rs b/embassy-stm32/src/adc/f1.rs index dd4b3489b..80eaecc14 100644 --- a/embassy-stm32/src/adc/f1.rs +++ b/embassy-stm32/src/adc/f1.rs @@ -4,6 +4,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; +use super::blocking_delay_us; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::time::Hertz; use crate::{interrupt, Peripheral}; @@ -54,11 +55,7 @@ impl<'d, T: Instance> Adc<'d, T> { // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) // for at least two ADC clock cycles. - let us = (1_000_000 * 2) / Self::freq().0 + 1; - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(us)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / (1000_000 / us)); + blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1); // Reset calibration T::regs().cr2().modify(|reg| reg.set_rstcal(true)); @@ -73,11 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> { } // One cycle after calibration - let us = (1_000_000 * 1) / Self::freq().0 + 1; - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(us)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / (1000_000 / us)); + blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); Self { adc, diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs index 1a62b7707..c22a3fe4a 100644 --- a/embassy-stm32/src/adc/f3.rs +++ b/embassy-stm32/src/adc/f3.rs @@ -4,6 +4,7 @@ use core::task::Poll; use embassy_hal_internal::into_ref; +use super::blocking_delay_us; use crate::adc::{Adc, AdcPin, Instance, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::time::Hertz; @@ -69,10 +70,7 @@ impl<'d, T: Instance> Adc<'d, T> { T::regs().cr().modify(|w| w.set_advregen(vals::Advregen::ENABLED)); // Wait for the regulator to stabilize - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(10)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); + blocking_delay_us(10); assert!(!T::regs().cr().read().aden()); @@ -83,11 +81,7 @@ impl<'d, T: Instance> Adc<'d, T> { while T::regs().cr().read().adcal() {} // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). - let us = (1_000_000 * 4) / Self::freq().0 + 1; - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(us)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / (1000_000 / us)); + blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1); // Enable the adc T::regs().cr().modify(|w| w.set_aden(true)); diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ead2357ce..24dd7cc3c 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -69,6 +69,15 @@ trait SealedInternalChannel { fn channel(&self) -> u8; } +/// Performs a busy-wait delay for a specified number of microseconds. +#[allow(unused)] +pub(crate) fn blocking_delay_us(us: u32) { + #[cfg(time)] + embassy_time::block_for(embassy_time::Duration::from_micros(us)); + #[cfg(not(time))] + cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 * us / 1_000_000); +} + /// ADC instance. #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))] #[allow(private_bounds)] diff --git a/embassy-stm32/src/adc/v1.rs b/embassy-stm32/src/adc/v1.rs index 960990c39..1dda28cf2 100644 --- a/embassy-stm32/src/adc/v1.rs +++ b/embassy-stm32/src/adc/v1.rs @@ -6,6 +6,7 @@ use embassy_hal_internal::into_ref; #[cfg(adc_l0)] use stm32_metapac::adc::vals::Ckmode; +use super::blocking_delay_us; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::interrupt::typelevel::Interrupt; use crate::peripherals::ADC; @@ -72,10 +73,7 @@ impl<'d, T: Instance> Adc<'d, T> { // // Table 57. ADC characteristics // tstab = 14 * 1/fadc - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(1)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1000_000); + blocking_delay_us(1); // set default PCKL/2 on L0s because HSI is disabled in the default clock config #[cfg(adc_l0)] @@ -128,10 +126,7 @@ impl<'d, T: Instance> Adc<'d, T> { // Table 28. Embedded internal reference voltage // tstart = 10μs T::regs().ccr().modify(|reg| reg.set_vrefen(true)); - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(10)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); + blocking_delay_us(10); Vref } @@ -142,10 +137,7 @@ impl<'d, T: Instance> Adc<'d, T> { // tstart ≤ 10μs // ts_temp ≥ 4μs T::regs().ccr().modify(|reg| reg.set_tsen(true)); - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(10)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); + blocking_delay_us(10); Temperature } diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 1ac119508..7771cf768 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs @@ -1,5 +1,6 @@ use embassy_hal_internal::into_ref; +use super::blocking_delay_us; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::peripherals::ADC1; use crate::time::Hertz; @@ -103,10 +104,7 @@ where reg.set_adon(true); }); - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(5)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 200_000); + blocking_delay_us(3); Self { adc, diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index a5e09646a..4fd8558ba 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs @@ -1,6 +1,7 @@ use cfg_if::cfg_if; use embassy_hal_internal::into_ref; +use super::blocking_delay_us; use crate::adc::{Adc, AdcPin, Instance, Resolution, SampleTime}; use crate::Peripheral; @@ -87,10 +88,7 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_chselrmod(false); }); - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(20)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 50_000); + blocking_delay_us(20); T::regs().cr().modify(|reg| { reg.set_adcal(true); @@ -100,10 +98,7 @@ impl<'d, T: Instance> Adc<'d, T> { // spin } - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(1)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1000_000); + blocking_delay_us(1); Self { adc, @@ -123,10 +118,7 @@ impl<'d, T: Instance> Adc<'d, T> { // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us // to stabilize the internal voltage reference. - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(20)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 50_000); + blocking_delay_us(15); VrefInt {} } diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 018104dd6..ca87b41ee 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs @@ -2,7 +2,7 @@ use pac::adc::vals::{Adcaldif, Boost, Difsel, Exten, Pcsel}; use pac::adccommon::vals::Presc; -use super::{Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; use crate::time::Hertz; use crate::{pac, Peripheral}; @@ -164,10 +164,7 @@ impl<'d, T: Instance> Adc<'d, T> { s.configure_differential_inputs(); s.calibrate(); - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(1)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 1000_000); + blocking_delay_us(1); s.enable(); s.configure(); @@ -181,10 +178,7 @@ impl<'d, T: Instance> Adc<'d, T> { reg.set_advregen(true); }); - #[cfg(time)] - embassy_time::block_for(embassy_time::Duration::from_micros(10)); - #[cfg(not(time))] - cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 100_000); + blocking_delay_us(10); } fn configure_differential_inputs(&mut self) { From ec0896037ad6c48d527e1abb88ca49ec0f376663 Mon Sep 17 00:00:00 2001 From: Gustav Toft Date: Thu, 11 Apr 2024 08:29:06 +0200 Subject: [PATCH 17/35] Removed Result for send and poll_send. --- embassy-net/src/raw.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index ad8d69853..a6500a51f 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -91,7 +91,7 @@ impl<'a> RawSocket<'a> { /// Send a datagram. /// /// This method will wait until the datagram has been sent.` - pub async fn send(&self, buf: &[u8]) -> Result<(), raw::SendError> { + pub async fn send(&self, buf: &[u8]) { poll_fn(move |cx| self.poll_send(buf, cx)).await } @@ -101,10 +101,10 @@ impl<'a> RawSocket<'a> { /// /// When the socket's send buffer is full, this method will return `Poll::Pending` /// and register the current task to be notified when the buffer has space available. - pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll> { + pub fn poll_send(&self, buf: &[u8], cx: &mut Context<'_>) -> Poll<()> { self.with_mut(|s, _| match s.send_slice(buf) { // Entire datagram has been sent - Ok(()) => Poll::Ready(Ok(())), + Ok(()) => Poll::Ready(()), Err(raw::SendError::BufferFull) => { s.register_send_waker(cx.waker()); Poll::Pending From fd5113eeb00add4af38cb0a3ff95c7d414c68b87 Mon Sep 17 00:00:00 2001 From: Gustav Toft Date: Thu, 11 Apr 2024 09:08:10 +0200 Subject: [PATCH 18/35] Restore vscode settings --- .vscode/settings.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 343331950..0c195a13b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,24 +10,24 @@ "rust-analyzer.cargo.noDefaultFeatures": true, "rust-analyzer.showUnlinkedFileNotification": false, // uncomment the target of your chip. - "rust-analyzer.cargo.target": "thumbv6m-none-eabi", + //"rust-analyzer.cargo.target": "thumbv6m-none-eabi", //"rust-analyzer.cargo.target": "thumbv7m-none-eabi", - //"rust-analyzer.cargo.target": "thumbv7em-none-eabi", + "rust-analyzer.cargo.target": "thumbv7em-none-eabi", //"rust-analyzer.cargo.target": "thumbv8m.main-none-eabihf", - /* "rust-analyzer.cargo.features": [ + "rust-analyzer.cargo.features": [ "stm32f103c8", "time-driver-any", "unstable-pac", "exti", - ], */ + ], "rust-analyzer.linkedProjects": [ // Uncomment ONE line for the chip you want to work on. // This makes rust-analyzer work on the example crate and all its dependencies. - // "embassy-stm32/Cargo.toml", + "embassy-stm32/Cargo.toml", // "examples/nrf52840-rtic/Cargo.toml", // "examples/nrf5340/Cargo.toml", // "examples/nrf-rtos-trace/Cargo.toml", - "examples/rp/Cargo.toml", + // "examples/rp/Cargo.toml", // "examples/std/Cargo.toml", // "examples/stm32c0/Cargo.toml", // "examples/stm32f0/Cargo.toml", From b578d3e645a534bdc76f43e603e9f5b2cab131fa Mon Sep 17 00:00:00 2001 From: Gustav Toft Date: Thu, 11 Apr 2024 10:34:17 +0200 Subject: [PATCH 19/35] Removed generic type parameter. --- embassy-net/src/raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-net/src/raw.rs b/embassy-net/src/raw.rs index a6500a51f..7ecd913e7 100644 --- a/embassy-net/src/raw.rs +++ b/embassy-net/src/raw.rs @@ -91,7 +91,7 @@ impl<'a> RawSocket<'a> { /// Send a datagram. /// /// This method will wait until the datagram has been sent.` - pub async fn send(&self, buf: &[u8]) { + pub async fn send(&self, buf: &[u8]) { poll_fn(move |cx| self.poll_send(buf, cx)).await } From 9053b6b5b3a09e48ed5e2476a5f712c9796828d5 Mon Sep 17 00:00:00 2001 From: Vega Deftwing Date: Thu, 11 Apr 2024 19:45:38 +0000 Subject: [PATCH 20/35] Fix spelling and white space mistakes --- NOTICE.md | 2 +- README.md | 8 ++++---- embassy-boot-nrf/README.md | 2 +- embassy-boot/README.md | 2 +- embassy-net/README.md | 4 ++-- embassy-time-queue-driver/README.md | 2 +- embassy-time/README.md | 2 +- embassy-usb/README.md | 4 ++-- examples/boot/bootloader/stm32-dual-bank/README.md | 8 ++++---- examples/stm32f4/src/bin/ws2812_spi.rs | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/NOTICE.md b/NOTICE.md index 868bec08f..a50b39494 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -12,5 +12,5 @@ listed source code repository logs. This program and the accompanying materials are made available under the terms of the Apache Software License 2.0 which is available at -https://www.apache.org/licenses/LICENSE-2.0, or the MIT license which is +https://www.apache.org/licenses/LICENSE-2.0, or the MIT license which is available at https://opensource.org/licenses/MIT diff --git a/README.md b/README.md index b6f667f75..0bd1ac594 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Embassy is the next-generation framework for embedded applications. Write safe, The Rust programming language is blazingly fast and memory-efficient, with no runtime, garbage collector or OS. It catches a wide variety of bugs at compile time, thanks to its full memory- and thread-safety, and expressive type system. -Rust's async/await allows for unprecedently easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is faster and smaller than one! +Rust's async/await allows for unprecedentedly easy and efficient multitasking in embedded systems. Tasks get transformed at compile time into state machines that get run cooperatively. It requires no dynamic memory allocation, and runs on a single stack, so no per-task stack size tuning is required. It obsoletes the need for a traditional RTOS with kernel context switching, and is faster and smaller than one! ## Batteries included @@ -89,7 +89,7 @@ async fn main(spawner: Spawner) { ## Examples -Examples are found in the `examples/` folder seperated by the chip manufacturer they are designed to run on. For example: +Examples are found in the `examples/` folder separated by the chip manufacturer they are designed to run on. For example: * `examples/nrf52840` run on the `nrf52840-dk` board (PCA10056) but should be easily adaptable to other nRF52 chips and boards. * `examples/nrf5340` run on the `nrf5340-dk` board (PCA10095). @@ -130,8 +130,8 @@ For more help getting started, see [Getting Started][1] and [Running the Example ## Developing Embassy with Rust Analyzer based editors The [Rust Analyzer](https://rust-analyzer.github.io/) is used by [Visual Studio Code](https://code.visualstudio.com/) -and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer -must be told of the target project to work with. In the case of Visual Studio Code, +and others. Given the multiple targets that Embassy serves, there is no Cargo workspace file. Instead, the Rust Analyzer +must be told of the target project to work with. In the case of Visual Studio Code, please refer to the `.vscode/settings.json` file's `rust-analyzer.linkedProjects`setting. ## Minimum supported Rust version (MSRV) diff --git a/embassy-boot-nrf/README.md b/embassy-boot-nrf/README.md index 9dc5b0eb9..f0d87e18c 100644 --- a/embassy-boot-nrf/README.md +++ b/embassy-boot-nrf/README.md @@ -2,7 +2,7 @@ An [Embassy](https://embassy.dev) project. -An adaptation of `embassy-boot` for nRF. +An adaptation of `embassy-boot` for nRF. ## Features diff --git a/embassy-boot/README.md b/embassy-boot/README.md index 3c2d45e96..812c43524 100644 --- a/embassy-boot/README.md +++ b/embassy-boot/README.md @@ -15,7 +15,7 @@ The bootloader divides the storage into 4 main partitions, configurable when cre * BOOTLOADER - Where the bootloader is placed. The bootloader itself consumes about 8kB of flash, but if you need to debug it and have space available, increasing this to 24kB will allow you to run the bootloader with probe-rs. * ACTIVE - Where the main application is placed. The bootloader will attempt to load the application at the start of this partition. The minimum size required for this partition is the size of your application. * DFU - Where the application-to-be-swapped is placed. This partition is written to by the application. This partition must be at least 1 page bigger than the ACTIVE partition. -* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped. +* BOOTLOADER STATE - Where the bootloader stores the current state describing if the active and dfu partitions need to be swapped. For any partition, the following preconditions are required: diff --git a/embassy-net/README.md b/embassy-net/README.md index 94aa6f550..ce59ea34a 100644 --- a/embassy-net/README.md +++ b/embassy-net/README.md @@ -13,8 +13,8 @@ memory management designed to work well for embedded systems, aiming for a more - TCP, UDP, DNS, DHCPv4, IGMPv4 - TCP sockets implement the `embedded-io` async traits. -See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and -unimplemented features of the network protocols. +See the [`smoltcp`](https://github.com/smoltcp-rs/smoltcp) README for a detailed list of implemented and +unimplemented features of the network protocols. ## Hardware support diff --git a/embassy-time-queue-driver/README.md b/embassy-time-queue-driver/README.md index 8852b0358..b9fb12d94 100644 --- a/embassy-time-queue-driver/README.md +++ b/embassy-time-queue-driver/README.md @@ -4,5 +4,5 @@ This crate contains the driver trait used by the [`embassy-time`](https://crates You should rarely need to use this crate directly. Only use it when implementing your own timer queue. -There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and +There is two timer queue implementations, one in `embassy-time` enabled by the `generic-queue` feature, and another in `embassy-executor` enabled by the `integrated-timers` feature. diff --git a/embassy-time/README.md b/embassy-time/README.md index f5d46df7b..6a4b049b4 100644 --- a/embassy-time/README.md +++ b/embassy-time/README.md @@ -5,7 +5,7 @@ Timekeeping, delays and timeouts. Timekeeping is done with elapsed time since system boot. Time is represented in ticks, where the tick rate is defined either by the driver (in the case of a fixed-rate tick) or chosen by the user with a [tick rate](#tick-rate) feature. The chosen -tick rate applies to everything in `embassy-time` and thus determines the maximum +tick rate applies to everything in `embassy-time` and thus determines the maximum timing resolution of (1 / tick_rate) seconds. Tick counts are 64 bits. The default tick rate of 1Mhz supports diff --git a/embassy-usb/README.md b/embassy-usb/README.md index d2adae4f5..400fc6695 100644 --- a/embassy-usb/README.md +++ b/embassy-usb/README.md @@ -34,8 +34,8 @@ They can be set in two ways: - Via Cargo features: enable a feature like `-`. `name` must be in lowercase and use dashes instead of underscores. For example. `max-interface-count-3`. Only a selection of values is available, check `Cargo.toml` for the list. -- Via environment variables at build time: set the variable named `EMBASSY_USB_`. For example -`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`. +- Via environment variables at build time: set the variable named `EMBASSY_USB_`. For example +`EMBASSY_USB_MAX_INTERFACE_COUNT=3 cargo build`. You can also set them in the `[env]` section of `.cargo/config.toml`. Any value can be set, unlike with Cargo features. Environment variables take precedence over Cargo features. If two Cargo features are enabled for the same setting diff --git a/examples/boot/bootloader/stm32-dual-bank/README.md b/examples/boot/bootloader/stm32-dual-bank/README.md index 3de3171cd..cd6c0bc84 100644 --- a/examples/boot/bootloader/stm32-dual-bank/README.md +++ b/examples/boot/bootloader/stm32-dual-bank/README.md @@ -2,16 +2,16 @@ ## Overview -This bootloader leverages `embassy-boot` to interact with the flash. -This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. +This bootloader leverages `embassy-boot` to interact with the flash. +This example targets STM32 devices with dual-bank flash memory, with a primary focus on the STM32H747XI series. Users must modify the `memory.x` configuration file to match with the memory layout of their specific STM32 device. Additionally, this example can be extended to utilize external flash memory, such as QSPI, for storing partitions. ## Memory Configuration -In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. -For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. +In this example's `memory.x` file, various symbols are defined to assist in effective memory management within the bootloader environment. +For dual-bank STM32 devices, it's crucial to assign these symbols correctly to their respective memory banks. ### Symbol Definitions diff --git a/examples/stm32f4/src/bin/ws2812_spi.rs b/examples/stm32f4/src/bin/ws2812_spi.rs index a280a3b77..56ccb67b8 100644 --- a/examples/stm32f4/src/bin/ws2812_spi.rs +++ b/examples/stm32f4/src/bin/ws2812_spi.rs @@ -8,7 +8,7 @@ // If you want to save SPI for other purpose, you may want to take a look at `ws2812_pwm_dma.rs` file, which make use of TIM and DMA. // // Warning: -// DO NOT stare at ws2812 directy (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. +// DO NOT stare at ws2812 directly (especially after each MCU Reset), its (max) brightness could easily make your eyes feel burn. #![no_std] #![no_main] From 80fadada7056516aa566033929a305b36f6b9be4 Mon Sep 17 00:00:00 2001 From: Vega Deftwing Date: Thu, 11 Apr 2024 19:47:31 +0000 Subject: [PATCH 21/35] .sh whitespace and shellcheck fixes --- .github/ci/build.sh | 2 +- .github/ci/crlf.sh | 2 +- .github/ci/rustfmt.sh | 2 +- .github/ci/test.sh | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ci/build.sh b/.github/ci/build.sh index 77d2b3cab..68a7c0c34 100755 --- a/.github/ci/build.sh +++ b/.github/ci/build.sh @@ -7,7 +7,7 @@ set -euo pipefail export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target -if [ -f /ci/secrets/teleprobe-token.txt ]; then +if [ -f /ci/secrets/teleprobe-token.txt ]; then echo Got teleprobe token! export TELEPROBE_HOST=https://teleprobe.embassy.dev export TELEPROBE_TOKEN=$(cat /ci/secrets/teleprobe-token.txt) diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh index 69838ce88..ede17c861 100755 --- a/.github/ci/crlf.sh +++ b/.github/ci/crlf.sh @@ -4,7 +4,7 @@ set -euo pipefail -FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true)) +FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs -0 file -N | (grep " CRLF " || true)) if [ -z "$FILES_WITH_CRLF" ]; then echo -e "No files with CRLF endings found." diff --git a/.github/ci/rustfmt.sh b/.github/ci/rustfmt.sh index 369239cfe..0080f0db8 100755 --- a/.github/ci/rustfmt.sh +++ b/.github/ci/rustfmt.sh @@ -9,4 +9,4 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target mv rust-toolchain-nightly.toml rust-toolchain.toml -find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021 +find . -name '*.rs' -not -path '*target*' | xargs -0 rustfmt --check --skip-children --unstable-features --edition 2021 diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 8a58939f6..6cb3a4bff 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -8,9 +8,9 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target -cargo test --manifest-path ./embassy-sync/Cargo.toml -cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml -cargo test --manifest-path ./embassy-hal-internal/Cargo.toml +cargo test --manifest-path ./embassy-sync/Cargo.toml +cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml +cargo test --manifest-path ./embassy-hal-internal/Cargo.toml cargo test --manifest-path ./embassy-time/Cargo.toml --features generic-queue,mock-driver cargo test --manifest-path ./embassy-time-driver/Cargo.toml From a3f8048877e658493b9147a122fab2c788463591 Mon Sep 17 00:00:00 2001 From: Vega Deftwing Date: Thu, 11 Apr 2024 20:21:30 +0000 Subject: [PATCH 22/35] Revert xargs changes --- .github/ci/crlf.sh | 2 +- .github/ci/rustfmt.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ci/crlf.sh b/.github/ci/crlf.sh index ede17c861..69838ce88 100755 --- a/.github/ci/crlf.sh +++ b/.github/ci/crlf.sh @@ -4,7 +4,7 @@ set -euo pipefail -FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs -0 file -N | (grep " CRLF " || true)) +FILES_WITH_CRLF=$(find ! -path "./.git/*" -not -type d | xargs file -N | (grep " CRLF " || true)) if [ -z "$FILES_WITH_CRLF" ]; then echo -e "No files with CRLF endings found." diff --git a/.github/ci/rustfmt.sh b/.github/ci/rustfmt.sh index 0080f0db8..369239cfe 100755 --- a/.github/ci/rustfmt.sh +++ b/.github/ci/rustfmt.sh @@ -9,4 +9,4 @@ export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target mv rust-toolchain-nightly.toml rust-toolchain.toml -find . -name '*.rs' -not -path '*target*' | xargs -0 rustfmt --check --skip-children --unstable-features --edition 2021 +find . -name '*.rs' -not -path '*target*' | xargs rustfmt --check --skip-children --unstable-features --edition 2021 From 98b4eb4491f285fd1008938c4116633f7646c042 Mon Sep 17 00:00:00 2001 From: Boris Faure Date: Sun, 7 Apr 2024 17:58:17 +0200 Subject: [PATCH 23/35] stm32: fix typo in doc --- embassy-stm32/src/usb/otg.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index b0e7067bd..1e88b6959 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -317,7 +317,7 @@ impl<'d, T: Instance> Driver<'d, T> { /// /// # Arguments /// - /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. + /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets. /// Must be large enough to fit all OUT endpoint max packet sizes. /// Endpoint allocation will fail if it is too small. pub fn new_fs( @@ -348,7 +348,7 @@ impl<'d, T: Instance> Driver<'d, T> { /// /// # Arguments /// - /// * `ep_out_buffer` - An internal buffer used to temporarily store recevied packets. + /// * `ep_out_buffer` - An internal buffer used to temporarily store received packets. /// Must be large enough to fit all OUT endpoint max packet sizes. /// Endpoint allocation will fail if it is too small. pub fn new_hs_ulpi( From 499c6e84a3d007e52de25104d658dd98724a2d5a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 12 Apr 2024 03:19:42 +0200 Subject: [PATCH 24/35] stm32/otg: fix OTG_HS in FS mode. --- embassy-stm32/src/usb/otg.rs | 58 +++++++++++------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/embassy-stm32/src/usb/otg.rs b/embassy-stm32/src/usb/otg.rs index 1e88b6959..cabc06367 100644 --- a/embassy-stm32/src/usb/otg.rs +++ b/embassy-stm32/src/usb/otg.rs @@ -562,51 +562,29 @@ impl<'d, T: Instance> Bus<'d, T> { fn init(&mut self) { super::common_init::(); - #[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); - } - }); + // Enable ULPI clock if external PHY is used + let _ulpien = !self.phy_type.internal(); - // 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(any(stm32f2, stm32f4, stm32f7))] + if T::HIGH_SPEED { + critical_section::with(|_| { + let rcc = crate::pac::RCC; + rcc.ahb1enr().modify(|w| w.set_usb_otg_hsulpien(_ulpien)); + rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hsulpilpen(_ulpien)); }); } #[cfg(stm32h7)] - { - // 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); - } - }); - }); - } + critical_section::with(|_| { + let rcc = crate::pac::RCC; + if T::HIGH_SPEED { + rcc.ahb1enr().modify(|w| w.set_usb_otg_hs_ulpien(_ulpien)); + rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hs_ulpilpen(_ulpien)); + } else { + rcc.ahb1enr().modify(|w| w.set_usb_otg_fs_ulpien(_ulpien)); + rcc.ahb1lpenr().modify(|w| w.set_usb_otg_fs_ulpilpen(_ulpien)); + } + }); let r = T::regs(); let core_id = r.cid().read().0; From 64b806db0bb6a3ae507330ddd3dc8c815e3b1563 Mon Sep 17 00:00:00 2001 From: chemicstry Date: Fri, 12 Apr 2024 17:59:25 +0300 Subject: [PATCH 25/35] Expose RCC enable and disable methods --- embassy-stm32/src/rcc/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index c328344aa..5497bba07 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -119,3 +119,21 @@ mod util { pub fn frequency() -> Hertz { T::frequency() } + +/// Enables and resets peripheral `T`. +/// +/// # Safety +/// +/// Peripheral must not be in use. +pub unsafe fn enable_and_reset() { + T::enable_and_reset(); +} + +/// Disables peripheral `T`. +/// +/// # Safety +/// +/// Peripheral must not be in use. +pub unsafe fn disable() { + T::disable(); +} From ffc61f78b0226b1898eb7aca66a759b76e0407af Mon Sep 17 00:00:00 2001 From: Michael Zill Date: Tue, 9 Apr 2024 06:56:15 +0200 Subject: [PATCH 26/35] stm32/spi,crc: update for new PAC --- embassy-stm32/Cargo.toml | 4 ++-- embassy-stm32/src/crc/v1.rs | 12 ++++++++++++ embassy-stm32/src/crc/v2v3.rs | 16 ++++++++-------- embassy-stm32/src/spi/mod.rs | 17 ++++++++++++----- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 89b24f0eb..93792ecf8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -70,7 +70,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0c4baf478324e19741c7a9795ab0aa8217c3691c" } vcell = "0.1.3" nb = "1.0.0" @@ -96,7 +96,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-2b7ec569a5510c324693f0515ac8ea20b12917a9", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0c4baf478324e19741c7a9795ab0aa8217c3691c", default-features = false, features = ["metadata"]} [features] default = ["rt"] diff --git a/embassy-stm32/src/crc/v1.rs b/embassy-stm32/src/crc/v1.rs index f8909d438..e8e0270af 100644 --- a/embassy-stm32/src/crc/v1.rs +++ b/embassy-stm32/src/crc/v1.rs @@ -32,6 +32,9 @@ impl<'d> Crc<'d> { /// Feeds a word to the peripheral and returns the current CRC value pub fn feed_word(&mut self, word: u32) -> u32 { // write a single byte to the device, and return the result + #[cfg(not(crc_v1))] + PAC_CRC.dr32().write_value(word); + #[cfg(crc_v1)] PAC_CRC.dr().write_value(word); self.read() } @@ -39,6 +42,9 @@ impl<'d> Crc<'d> { /// Feed a slice of words to the peripheral and return the result. pub fn feed_words(&mut self, words: &[u32]) -> u32 { for word in words { + #[cfg(not(crc_v1))] + PAC_CRC.dr32().write_value(*word); + #[cfg(crc_v1)] PAC_CRC.dr().write_value(*word); } @@ -46,6 +52,12 @@ impl<'d> Crc<'d> { } /// Read the CRC result value. + #[cfg(not(crc_v1))] + pub fn read(&self) -> u32 { + PAC_CRC.dr32().read() + } + /// Read the CRC result value. + #[cfg(crc_v1)] pub fn read(&self) -> u32 { PAC_CRC.dr().read() } diff --git a/embassy-stm32/src/crc/v2v3.rs b/embassy-stm32/src/crc/v2v3.rs index 46f5ea1be..13fb6778c 100644 --- a/embassy-stm32/src/crc/v2v3.rs +++ b/embassy-stm32/src/crc/v2v3.rs @@ -136,7 +136,7 @@ impl<'d> Crc<'d> { /// Feeds a byte into the CRC peripheral. Returns the computed checksum. pub fn feed_byte(&mut self, byte: u8) -> u32 { PAC_CRC.dr8().write_value(byte); - PAC_CRC.dr().read() + PAC_CRC.dr32().read() } /// Feeds an slice of bytes into the CRC peripheral. Returns the computed checksum. @@ -144,30 +144,30 @@ impl<'d> Crc<'d> { for byte in bytes { PAC_CRC.dr8().write_value(*byte); } - PAC_CRC.dr().read() + PAC_CRC.dr32().read() } /// Feeds a halfword into the CRC peripheral. Returns the computed checksum. pub fn feed_halfword(&mut self, halfword: u16) -> u32 { PAC_CRC.dr16().write_value(halfword); - PAC_CRC.dr().read() + PAC_CRC.dr32().read() } /// Feeds an slice of halfwords into the CRC peripheral. Returns the computed checksum. pub fn feed_halfwords(&mut self, halfwords: &[u16]) -> u32 { for halfword in halfwords { PAC_CRC.dr16().write_value(*halfword); } - PAC_CRC.dr().read() + PAC_CRC.dr32().read() } /// Feeds a words into the CRC peripheral. Returns the computed checksum. pub fn feed_word(&mut self, word: u32) -> u32 { - PAC_CRC.dr().write_value(word as u32); - PAC_CRC.dr().read() + PAC_CRC.dr32().write_value(word as u32); + PAC_CRC.dr32().read() } /// Feeds an slice of words into the CRC peripheral. Returns the computed checksum. pub fn feed_words(&mut self, words: &[u32]) -> u32 { for word in words { - PAC_CRC.dr().write_value(*word as u32); + PAC_CRC.dr32().write_value(*word as u32); } - PAC_CRC.dr().read() + PAC_CRC.dr32().read() } } diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 0b38c4288..450975f18 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -735,18 +735,22 @@ trait RegsExt { impl RegsExt for Regs { fn tx_ptr(&self) -> *mut W { - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(any(spi_v1, spi_f1))] let dr = self.dr(); + #[cfg(spi_v2)] + let dr = self.dr16(); #[cfg(any(spi_v3, spi_v4, spi_v5))] - let dr = self.txdr(); + let dr = self.txdr32(); dr.as_ptr() as *mut W } fn rx_ptr(&self) -> *mut W { - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(any(spi_v1, spi_f1))] let dr = self.dr(); + #[cfg(spi_v2)] + let dr = self.dr16(); #[cfg(any(spi_v3, spi_v4, spi_v5))] - let dr = self.rxdr(); + let dr = self.rxdr32(); dr.as_ptr() as *mut W } } @@ -815,11 +819,14 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { fn flush_rx_fifo(regs: Regs) { #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] while regs.sr().read().rxne() { + #[cfg(not(spi_v2))] let _ = regs.dr().read(); + #[cfg(spi_v2)] + let _ = regs.dr16().read(); } #[cfg(any(spi_v3, spi_v4, spi_v5))] while regs.sr().read().rxp() { - let _ = regs.rxdr().read(); + let _ = regs.rxdr32().read(); } } From 1f3b690f76b6732e1ff152091040cec833da25cf Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 02:55:15 +0200 Subject: [PATCH 27/35] stm32/flash: remove otp flash regions (removed in newer metapacs). --- embassy-stm32/build.rs | 2 -- embassy-stm32/src/flash/f4.rs | 5 +---- embassy-stm32/src/flash/h50.rs | 6 ++---- embassy-stm32/src/flash/mod.rs | 2 -- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 38b6c480c..0f87dd8ac 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -272,8 +272,6 @@ fn main() { "Bank1" } else if region.name.starts_with("BANK_2") { "Bank2" - } else if region.name == "OTP" { - "Otp" } else { continue; } diff --git a/embassy-stm32/src/flash/f4.rs b/embassy-stm32/src/flash/f4.rs index 00e61f2d2..90f13ff29 100644 --- a/embassy-stm32/src/flash/f4.rs +++ b/embassy-stm32/src/flash/f4.rs @@ -16,7 +16,7 @@ mod alt_regions { use embassy_hal_internal::PeripheralRef; use stm32_metapac::FLASH_SIZE; - use crate::_generated::flash_regions::{OTPRegion, BANK1_REGION1, BANK1_REGION2, BANK1_REGION3, OTP_REGION}; + use crate::_generated::flash_regions::{BANK1_REGION1, BANK1_REGION2, BANK1_REGION3}; use crate::flash::{asynch, Async, Bank1Region1, Bank1Region2, Blocking, Error, Flash, FlashBank, FlashRegion}; use crate::peripherals::FLASH; @@ -62,7 +62,6 @@ mod alt_regions { pub bank2_region1: AltBank2Region1<'d, MODE>, pub bank2_region2: AltBank2Region2<'d, MODE>, pub bank2_region3: AltBank2Region3<'d, MODE>, - pub otp_region: OTPRegion<'d, MODE>, } impl<'d> Flash<'d> { @@ -79,7 +78,6 @@ mod alt_regions { bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), - otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), } } @@ -96,7 +94,6 @@ mod alt_regions { bank2_region1: AltBank2Region1(&ALT_BANK2_REGION1, unsafe { p.clone_unchecked() }, PhantomData), bank2_region2: AltBank2Region2(&ALT_BANK2_REGION2, unsafe { p.clone_unchecked() }, PhantomData), bank2_region3: AltBank2Region3(&ALT_BANK2_REGION3, unsafe { p.clone_unchecked() }, PhantomData), - otp_region: OTPRegion(&OTP_REGION, unsafe { p.clone_unchecked() }, PhantomData), } } } diff --git a/embassy-stm32/src/flash/h50.rs b/embassy-stm32/src/flash/h50.rs index db05bef5d..5b15be261 100644 --- a/embassy-stm32/src/flash/h50.rs +++ b/embassy-stm32/src/flash/h50.rs @@ -55,7 +55,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) } pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { - assert!(sector.bank != FlashBank::Otp); assert!(sector.index_in_bank < 8); while busy() {} @@ -63,9 +62,8 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E interrupt::free(|_| { pac::FLASH.nscr().modify(|w| { w.set_bksel(match sector.bank { - FlashBank::Bank1 => Bksel::B_0X0, - FlashBank::Bank2 => Bksel::B_0X1, - _ => unreachable!(), + FlashBank::Bank1 => Bksel::BANK1, + FlashBank::Bank2 => Bksel::BANK2, }); w.set_snb(sector.index_in_bank); w.set_ser(true); diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs index 1d8031e82..9d7861816 100644 --- a/embassy-stm32/src/flash/mod.rs +++ b/embassy-stm32/src/flash/mod.rs @@ -89,8 +89,6 @@ pub enum FlashBank { Bank1 = 0, /// Bank 2 Bank2 = 1, - /// OTP region - Otp, } #[cfg_attr(any(flash_l0, flash_l1, flash_l4, flash_wl, flash_wb), path = "l.rs")] From 4079a8acf8d0d33dc1ca815475492cbf33407464 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 03:30:30 +0200 Subject: [PATCH 28/35] stm32/adc: update g4 for new pac. --- embassy-stm32/src/adc/g4.rs | 304 ++++++++++++++++++++++++++++++++ embassy-stm32/src/adc/mod.rs | 29 ++- examples/stm32g4/src/bin/adc.rs | 2 +- 3 files changed, 332 insertions(+), 3 deletions(-) create mode 100644 embassy-stm32/src/adc/g4.rs diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs new file mode 100644 index 000000000..f6741f019 --- /dev/null +++ b/embassy-stm32/src/adc/g4.rs @@ -0,0 +1,304 @@ +#[allow(unused)] +use pac::adc::vals::{Adcaldif, Difsel, Exten}; +use pac::adccommon::vals::Presc; + +use super::{blocking_delay_us, Adc, AdcPin, Instance, InternalChannel, Resolution, SampleTime}; +use crate::time::Hertz; +use crate::{pac, Peripheral}; + +/// Default VREF voltage used for sample conversion to millivolts. +pub const VREF_DEFAULT_MV: u32 = 3300; +/// VREF voltage used for factory calibration of VREFINTCAL register. +pub const VREF_CALIB_MV: u32 = 3300; + +/// Max single ADC operation clock frequency +#[cfg(stm32g4)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); +#[cfg(stm32h7)] +const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); + +#[cfg(stm32g4)] +const VREF_CHANNEL: u8 = 18; +#[cfg(stm32g4)] +const TEMP_CHANNEL: u8 = 16; + +#[cfg(stm32h7)] +const VREF_CHANNEL: u8 = 19; +#[cfg(stm32h7)] +const TEMP_CHANNEL: u8 = 18; + +// TODO this should be 14 for H7a/b/35 +const VBAT_CHANNEL: u8 = 17; + +// NOTE: Vrefint/Temperature/Vbat are not available on all ADCs, this currently cannot be modeled with stm32-data, so these are available from the software on all ADCs +/// Internal voltage reference channel. +pub struct VrefInt; +impl InternalChannel for VrefInt {} +impl super::SealedInternalChannel for VrefInt { + fn channel(&self) -> u8 { + VREF_CHANNEL + } +} + +/// Internal temperature channel. +pub struct Temperature; +impl InternalChannel for Temperature {} +impl super::SealedInternalChannel for Temperature { + fn channel(&self) -> u8 { + TEMP_CHANNEL + } +} + +/// Internal battery voltage channel. +pub struct Vbat; +impl InternalChannel for Vbat {} +impl super::SealedInternalChannel for Vbat { + fn channel(&self) -> u8 { + VBAT_CHANNEL + } +} + +// NOTE (unused): The prescaler enum closely copies the hardware capabilities, +// but high prescaling doesn't make a lot of sense in the current implementation and is ommited. +#[allow(unused)] +enum Prescaler { + NotDivided, + DividedBy2, + DividedBy4, + DividedBy6, + DividedBy8, + DividedBy10, + DividedBy12, + DividedBy16, + DividedBy32, + DividedBy64, + DividedBy128, + DividedBy256, +} + +impl Prescaler { + fn from_ker_ck(frequency: Hertz) -> Self { + let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; + match raw_prescaler { + 0 => Self::NotDivided, + 1 => Self::DividedBy2, + 2..=3 => Self::DividedBy4, + 4..=5 => Self::DividedBy6, + 6..=7 => Self::DividedBy8, + 8..=9 => Self::DividedBy10, + 10..=11 => Self::DividedBy12, + _ => unimplemented!(), + } + } + + fn divisor(&self) -> u32 { + match self { + Prescaler::NotDivided => 1, + Prescaler::DividedBy2 => 2, + Prescaler::DividedBy4 => 4, + Prescaler::DividedBy6 => 6, + Prescaler::DividedBy8 => 8, + Prescaler::DividedBy10 => 10, + Prescaler::DividedBy12 => 12, + Prescaler::DividedBy16 => 16, + Prescaler::DividedBy32 => 32, + Prescaler::DividedBy64 => 64, + Prescaler::DividedBy128 => 128, + Prescaler::DividedBy256 => 256, + } + } + + fn presc(&self) -> Presc { + match self { + Prescaler::NotDivided => Presc::DIV1, + Prescaler::DividedBy2 => Presc::DIV2, + Prescaler::DividedBy4 => Presc::DIV4, + Prescaler::DividedBy6 => Presc::DIV6, + Prescaler::DividedBy8 => Presc::DIV8, + Prescaler::DividedBy10 => Presc::DIV10, + Prescaler::DividedBy12 => Presc::DIV12, + Prescaler::DividedBy16 => Presc::DIV16, + Prescaler::DividedBy32 => Presc::DIV32, + Prescaler::DividedBy64 => Presc::DIV64, + Prescaler::DividedBy128 => Presc::DIV128, + Prescaler::DividedBy256 => Presc::DIV256, + } + } +} + +impl<'d, T: Instance> Adc<'d, T> { + /// Create a new ADC driver. + pub fn new(adc: impl Peripheral

+ 'd) -> Self { + embassy_hal_internal::into_ref!(adc); + T::enable_and_reset(); + + let prescaler = Prescaler::from_ker_ck(T::frequency()); + + T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); + + let frequency = Hertz(T::frequency().0 / prescaler.divisor()); + info!("ADC frequency set to {} Hz", frequency.0); + + if frequency > MAX_ADC_CLK_FREQ { + panic!("Maximal allowed frequency for the ADC is {} MHz and it varies with different packages, refer to ST docs for more information.", MAX_ADC_CLK_FREQ.0 / 1_000_000 ); + } + + let mut s = Self { + adc, + sample_time: SampleTime::from_bits(0), + }; + s.power_up(); + s.configure_differential_inputs(); + + s.calibrate(); + blocking_delay_us(1); + + s.enable(); + s.configure(); + + s + } + + fn power_up(&mut self) { + T::regs().cr().modify(|reg| { + reg.set_deeppwd(false); + reg.set_advregen(true); + }); + + blocking_delay_us(10); + } + + fn configure_differential_inputs(&mut self) { + T::regs().difsel().modify(|w| { + for n in 0..20 { + w.set_difsel(n, Difsel::SINGLEENDED); + } + }); + } + + fn calibrate(&mut self) { + T::regs().cr().modify(|w| { + w.set_adcaldif(Adcaldif::SINGLEENDED); + }); + + T::regs().cr().modify(|w| w.set_adcal(true)); + + while T::regs().cr().read().adcal() {} + } + + fn enable(&mut self) { + T::regs().isr().write(|w| w.set_adrdy(true)); + T::regs().cr().modify(|w| w.set_aden(true)); + while !T::regs().isr().read().adrdy() {} + T::regs().isr().write(|w| w.set_adrdy(true)); + } + + fn configure(&mut self) { + // single conversion mode, software trigger + T::regs().cfgr().modify(|w| { + w.set_cont(false); + w.set_exten(Exten::DISABLED); + }); + } + + /// Enable reading the voltage reference internal channel. + pub fn enable_vrefint(&self) -> VrefInt { + T::common_regs().ccr().modify(|reg| { + reg.set_vrefen(true); + }); + + VrefInt {} + } + + /// Enable reading the temperature internal channel. + pub fn enable_temperature(&self) -> Temperature { + T::common_regs().ccr().modify(|reg| { + reg.set_vsenseen(true); + }); + + Temperature {} + } + + /// Enable reading the vbat internal channel. + pub fn enable_vbat(&self) -> Vbat { + T::common_regs().ccr().modify(|reg| { + reg.set_vbaten(true); + }); + + Vbat {} + } + + /// Set the ADC sample time. + pub fn set_sample_time(&mut self, sample_time: SampleTime) { + self.sample_time = sample_time; + } + + /// Set the ADC resolution. + pub fn set_resolution(&mut self, resolution: Resolution) { + T::regs().cfgr().modify(|reg| reg.set_res(resolution.into())); + } + + /// Perform a single conversion. + fn convert(&mut self) -> u16 { + T::regs().isr().modify(|reg| { + reg.set_eos(true); + reg.set_eoc(true); + }); + + // Start conversion + T::regs().cr().modify(|reg| { + reg.set_adstart(true); + }); + + while !T::regs().isr().read().eos() { + // spin + } + + T::regs().dr().read().0 as u16 + } + + /// Read an ADC pin. + pub fn read

(&mut self, pin: &mut P) -> u16 + where + P: AdcPin, + P: crate::gpio::Pin, + { + pin.set_as_analog(); + + self.read_channel(pin.channel()) + } + + /// Read an ADC internal channel. + pub fn read_internal(&mut self, channel: &mut impl InternalChannel) -> u16 { + self.read_channel(channel.channel()) + } + + fn read_channel(&mut self, channel: u8) -> u16 { + // Configure channel + Self::set_channel_sample_time(channel, self.sample_time); + + #[cfg(stm32h7)] + { + T::regs().cfgr2().modify(|w| w.set_lshift(0)); + T::regs() + .pcsel() + .write(|w| w.set_pcsel(channel as _, Pcsel::PRESELECTED)); + } + + T::regs().sqr1().write(|reg| { + reg.set_sq(0, channel); + reg.set_l(0); + }); + + self.convert() + } + + fn set_channel_sample_time(ch: u8, sample_time: SampleTime) { + let sample_time = sample_time.into(); + if ch <= 9 { + T::regs().smpr().modify(|reg| reg.set_smp(ch as _, sample_time)); + } else { + T::regs().smpr2().modify(|reg| reg.set_smp((ch - 10) as _, sample_time)); + } + } +} diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 24dd7cc3c..12c5751bd 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -12,6 +12,7 @@ #[cfg_attr(adc_v2, path = "v2.rs")] #[cfg_attr(any(adc_v3, adc_g0, adc_h5), path = "v3.rs")] #[cfg_attr(adc_v4, path = "v4.rs")] +#[cfg_attr(adc_g4, path = "g4.rs")] mod _version; #[allow(unused)] @@ -79,13 +80,37 @@ pub(crate) fn blocking_delay_us(us: u32) { } /// ADC instance. -#[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5)))] +#[cfg(not(any( + adc_f1, + adc_v1, + adc_l0, + adc_v2, + adc_v3, + adc_v4, + adc_g4, + adc_f3, + adc_f3_v1_1, + adc_g0, + adc_h5 +)))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::Peripheral

{ type Interrupt: crate::interrupt::typelevel::Interrupt; } /// ADC instance. -#[cfg(any(adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_f3, adc_f3_v1_1, adc_g0, adc_h5))] +#[cfg(any( + adc_f1, + adc_v1, + adc_l0, + adc_v2, + adc_v3, + adc_v4, + adc_g4, + adc_f3, + adc_f3_v1_1, + adc_g0, + adc_h5 +))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::Peripheral

+ crate::rcc::RccPeripheral { type Interrupt: crate::interrupt::typelevel::Interrupt; diff --git a/examples/stm32g4/src/bin/adc.rs b/examples/stm32g4/src/bin/adc.rs index 68b54e406..3de38cbd6 100644 --- a/examples/stm32g4/src/bin/adc.rs +++ b/examples/stm32g4/src/bin/adc.rs @@ -29,7 +29,7 @@ async fn main(_spawner: Spawner) { info!("Hello World!"); let mut adc = Adc::new(p.ADC2); - adc.set_sample_time(SampleTime::CYCLES32_5); + adc.set_sample_time(SampleTime::CYCLES24_5); loop { let measured = adc.read(&mut p.PA7); From 65c085ce910f50903bc5c41ca82eda989810f855 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 13 Apr 2024 02:13:41 +0200 Subject: [PATCH 29/35] Add stm32u0 support. --- ci.sh | 3 ++ embassy-stm32/Cargo.toml | 38 +++++++++++++++++++++++-- embassy-stm32/src/exti.rs | 16 +++++------ embassy-stm32/src/rcc/l.rs | 28 +++++++++++++++--- embassy-stm32/src/rcc/mco.rs | 2 +- embassy-stm32/src/rcc/mod.rs | 2 +- examples/stm32u0/.cargo/config.toml | 9 ++++++ examples/stm32u0/Cargo.toml | 25 ++++++++++++++++ examples/stm32u0/build.rs | 5 ++++ examples/stm32u0/src/bin/blinky.rs | 26 +++++++++++++++++ examples/stm32u0/src/bin/button.rs | 24 ++++++++++++++++ examples/stm32u0/src/bin/button_exti.rs | 25 ++++++++++++++++ 12 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 examples/stm32u0/.cargo/config.toml create mode 100644 examples/stm32u0/Cargo.toml create mode 100644 examples/stm32u0/build.rs create mode 100644 examples/stm32u0/src/bin/blinky.rs create mode 100644 examples/stm32u0/src/bin/button.rs create mode 100644 examples/stm32u0/src/bin/button_exti.rs diff --git a/ci.sh b/ci.sh index d17f4e13e..1393b9d47 100755 --- a/ci.sh +++ b/ci.sh @@ -149,6 +149,9 @@ cargo batch \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h503rb,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv8m.main-none-eabihf --features stm32h562ag,defmt,exti,time-driver-any,time \ --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wb35ce,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u031r8,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \ + --- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \ --- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \ diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 93792ecf8..459d2e370 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -30,6 +30,7 @@ flavors = [ { regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" }, { regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf", features = ["low-power"] }, + { regex_feature = "stm32u0.*", target = "thumbv6m-none-eabi" }, { regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" }, { regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" }, { regex_feature = "stm32wba.*", target = "thumbv8m.main-none-eabihf" }, @@ -70,7 +71,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0c4baf478324e19741c7a9795ab0aa8217c3691c" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61" } vcell = "0.1.3" nb = "1.0.0" @@ -96,7 +97,7 @@ proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0c4baf478324e19741c7a9795ab0aa8217c3691c", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d674277b78ca7400ecfeeb1b5af4e460a65c1a61", default-features = false, features = ["metadata"]} [features] default = ["rt"] @@ -1419,6 +1420,38 @@ stm32l562qe = [ "stm32-metapac/stm32l562qe" ] stm32l562re = [ "stm32-metapac/stm32l562re" ] stm32l562ve = [ "stm32-metapac/stm32l562ve" ] stm32l562ze = [ "stm32-metapac/stm32l562ze" ] +stm32u031c6 = [ "stm32-metapac/stm32u031c6" ] +stm32u031c8 = [ "stm32-metapac/stm32u031c8" ] +stm32u031f4 = [ "stm32-metapac/stm32u031f4" ] +stm32u031f6 = [ "stm32-metapac/stm32u031f6" ] +stm32u031f8 = [ "stm32-metapac/stm32u031f8" ] +stm32u031g6 = [ "stm32-metapac/stm32u031g6" ] +stm32u031g8 = [ "stm32-metapac/stm32u031g8" ] +stm32u031k4 = [ "stm32-metapac/stm32u031k4" ] +stm32u031k6 = [ "stm32-metapac/stm32u031k6" ] +stm32u031k8 = [ "stm32-metapac/stm32u031k8" ] +stm32u031r6 = [ "stm32-metapac/stm32u031r6" ] +stm32u031r8 = [ "stm32-metapac/stm32u031r8" ] +stm32u073c8 = [ "stm32-metapac/stm32u073c8" ] +stm32u073cb = [ "stm32-metapac/stm32u073cb" ] +stm32u073cc = [ "stm32-metapac/stm32u073cc" ] +stm32u073h8 = [ "stm32-metapac/stm32u073h8" ] +stm32u073hb = [ "stm32-metapac/stm32u073hb" ] +stm32u073hc = [ "stm32-metapac/stm32u073hc" ] +stm32u073k8 = [ "stm32-metapac/stm32u073k8" ] +stm32u073kb = [ "stm32-metapac/stm32u073kb" ] +stm32u073kc = [ "stm32-metapac/stm32u073kc" ] +stm32u073m8 = [ "stm32-metapac/stm32u073m8" ] +stm32u073mb = [ "stm32-metapac/stm32u073mb" ] +stm32u073mc = [ "stm32-metapac/stm32u073mc" ] +stm32u073r8 = [ "stm32-metapac/stm32u073r8" ] +stm32u073rb = [ "stm32-metapac/stm32u073rb" ] +stm32u073rc = [ "stm32-metapac/stm32u073rc" ] +stm32u083cc = [ "stm32-metapac/stm32u083cc" ] +stm32u083hc = [ "stm32-metapac/stm32u083hc" ] +stm32u083kc = [ "stm32-metapac/stm32u083kc" ] +stm32u083mc = [ "stm32-metapac/stm32u083mc" ] +stm32u083rc = [ "stm32-metapac/stm32u083rc" ] stm32u535cb = [ "stm32-metapac/stm32u535cb" ] stm32u535cc = [ "stm32-metapac/stm32u535cc" ] stm32u535ce = [ "stm32-metapac/stm32u535ce" ] @@ -1474,6 +1507,7 @@ stm32u599vj = [ "stm32-metapac/stm32u599vj" ] stm32u599zi = [ "stm32-metapac/stm32u599zi" ] stm32u599zj = [ "stm32-metapac/stm32u599zj" ] stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ] +stm32u5a5qi = [ "stm32-metapac/stm32u5a5qi" ] stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ] stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ] stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ] diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 8d5dae436..224d51b84 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -27,11 +27,11 @@ fn cpu_regs() -> pac::exti::Exti { EXTI } -#[cfg(not(any(exti_c0, exti_g0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] +#[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, gpio_v1, exti_u5, exti_h5, exti_h50)))] fn exticr_regs() -> pac::syscfg::Syscfg { pac::SYSCFG } -#[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] +#[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] fn exticr_regs() -> pac::exti::Exti { EXTI } @@ -44,9 +44,9 @@ unsafe fn on_irq() { #[cfg(feature = "low-power")] crate::low_power::on_wakeup_irq(); - #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] + #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] let bits = EXTI.pr(0).read().0; - #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] + #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] let bits = EXTI.rpr(0).read().0 | EXTI.fpr(0).read().0; // We don't handle or change any EXTI lines above 16. @@ -61,9 +61,9 @@ unsafe fn on_irq() { } // Clear pending - #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] + #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] EXTI.pr(0).write_value(Lines(bits)); - #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] + #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] { EXTI.rpr(0).write_value(Lines(bits)); EXTI.fpr(0).write_value(Lines(bits)); @@ -241,9 +241,9 @@ impl<'a> ExtiInputFuture<'a> { EXTI.ftsr(0).modify(|w| w.set_line(pin, falling)); // clear pending bit - #[cfg(not(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50)))] + #[cfg(not(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50)))] EXTI.pr(0).write(|w| w.set_line(pin, true)); - #[cfg(any(exti_c0, exti_g0, exti_l5, exti_u5, exti_h5, exti_h50))] + #[cfg(any(exti_c0, exti_g0, exti_u0, exti_l5, exti_u5, exti_h5, exti_h50))] { EXTI.rpr(0).write(|w| w.set_line(pin, true)); EXTI.fpr(0).write(|w| w.set_line(pin, true)); diff --git a/embassy-stm32/src/rcc/l.rs b/embassy-stm32/src/rcc/l.rs index 9079ddd41..d7235ac7f 100644 --- a/embassy-stm32/src/rcc/l.rs +++ b/embassy-stm32/src/rcc/l.rs @@ -49,6 +49,7 @@ pub struct Config { pub sys: Sysclk, pub ahb_pre: AHBPrescaler, pub apb1_pre: APBPrescaler, + #[cfg(not(stm32u0))] pub apb2_pre: APBPrescaler, #[cfg(any(stm32wl5x, stm32wb))] pub core2_ahb_pre: AHBPrescaler, @@ -75,6 +76,7 @@ impl Default for Config { sys: Sysclk::MSI, ahb_pre: AHBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1, + #[cfg(not(stm32u0))] apb2_pre: APBPrescaler::DIV1, #[cfg(any(stm32wl5x, stm32wb))] core2_ahb_pre: AHBPrescaler::DIV1, @@ -130,7 +132,7 @@ pub const WPAN_DEFAULT: Config = Config { }; fn msi_enable(range: MSIRange) { - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] + #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] RCC.cr().modify(|w| { #[cfg(not(stm32wb))] w.set_msirgsel(crate::pac::rcc::vals::Msirgsel::CR); @@ -240,7 +242,7 @@ pub(crate) unsafe fn init(config: Config) { let pll_input = PllInput { hse, hsi, - #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] + #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] msi, }; let pll = init_pll(PllInstance::Pll, config.pll, &pll_input); @@ -254,6 +256,10 @@ pub(crate) unsafe fn init(config: Config) { Sysclk::HSI => hsi.unwrap(), Sysclk::MSI => msi.unwrap(), Sysclk::PLL1_R => pll.r.unwrap(), + #[cfg(stm32u0)] + Sysclk::LSI | Sysclk::LSE => todo!(), + #[cfg(stm32u0)] + Sysclk::_RESERVED_6 | Sysclk::_RESERVED_7 => unreachable!(), }; #[cfg(rcc_l4plus)] @@ -263,6 +269,7 @@ pub(crate) unsafe fn init(config: Config) { let hclk1 = sys_clk / config.ahb_pre; let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre); + #[cfg(not(stm32u0))] let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); #[cfg(any(stm32l4, stm32l5, stm32wlex))] let hclk2 = hclk1; @@ -315,6 +322,13 @@ pub(crate) unsafe fn init(config: Config) { ..=64_000_000 => 3, _ => 4, }; + #[cfg(stm32u0)] + let latency = match hclk1.0 { + // VOS RANGE1, others TODO. + ..=24_000_000 => 0, + ..=48_000_000 => 1, + _ => 2, + }; #[cfg(stm32l1)] FLASH.acr().write(|w| w.set_acc64(true)); @@ -326,7 +340,11 @@ pub(crate) unsafe fn init(config: Config) { RCC.cfgr().modify(|w| { w.set_sw(config.sys); w.set_hpre(config.ahb_pre); + #[cfg(stm32u0)] + w.set_ppre(config.apb1_pre); + #[cfg(not(stm32u0))] w.set_ppre1(config.apb1_pre); + #[cfg(not(stm32u0))] w.set_ppre2(config.apb2_pre); }); while RCC.cfgr().read().sws() != config.sys {} @@ -353,8 +371,10 @@ pub(crate) unsafe fn init(config: Config) { #[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] hclk3: Some(hclk3), pclk1: Some(pclk1), + #[cfg(not(stm32u0))] pclk2: Some(pclk2), pclk1_tim: Some(pclk1_tim), + #[cfg(not(stm32u0))] pclk2_tim: Some(pclk2_tim), #[cfg(stm32wl)] pclk3: Some(hclk3), @@ -408,7 +428,7 @@ fn msirange_to_hertz(range: MSIRange) -> Hertz { Hertz(32_768 * (1 << (range as u8 + 1))) } -#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] +#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] fn msirange_to_hertz(range: MSIRange) -> Hertz { match range { MSIRange::RANGE100K => Hertz(100_000), @@ -521,7 +541,7 @@ mod pll { } } -#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))] +#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl, stm32u0))] mod pll { use super::{pll_enable, PllInstance}; pub use crate::pac::rcc::vals::{ diff --git a/embassy-stm32/src/rcc/mco.rs b/embassy-stm32/src/rcc/mco.rs index d8604e07e..4b22a099d 100644 --- a/embassy-stm32/src/rcc/mco.rs +++ b/embassy-stm32/src/rcc/mco.rs @@ -52,7 +52,7 @@ macro_rules! impl_peri { }; } -#[cfg(any(rcc_c0, rcc_g0))] +#[cfg(any(rcc_c0, rcc_g0, rcc_u0))] #[allow(unused_imports)] use self::{McoSource as Mco1Source, McoSource as Mco2Source}; diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index 5497bba07..a4e497fe7 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -25,7 +25,7 @@ pub use hsi48::*; #[cfg_attr(stm32g0, path = "g0.rs")] #[cfg_attr(stm32g4, path = "g4.rs")] #[cfg_attr(any(stm32h5, stm32h7), path = "h.rs")] -#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl), path = "l.rs")] +#[cfg_attr(any(stm32l0, stm32l1, stm32l4, stm32l5, stm32wb, stm32wl, stm32u0), path = "l.rs")] #[cfg_attr(stm32u5, path = "u5.rs")] #[cfg_attr(stm32wba, path = "wba.rs")] mod _version; diff --git a/examples/stm32u0/.cargo/config.toml b/examples/stm32u0/.cargo/config.toml new file mode 100644 index 000000000..688347084 --- /dev/null +++ b/examples/stm32u0/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace stm32u083rctx with your chip as listed in `probe-rs chip list` +runner = "probe-rs run --chip stm32u083rctx" + +[build] +target = "thumbv6m-none-eabi" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32u0/Cargo.toml b/examples/stm32u0/Cargo.toml new file mode 100644 index 000000000..495be3e75 --- /dev/null +++ b/examples/stm32u0/Cargo.toml @@ -0,0 +1,25 @@ +[package] +edition = "2021" +name = "embassy-stm32u0-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +# Change stm32u083rc to your chip name, if necessary. +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32u083rc", "memory-x", "unstable-pac", "exti"] } +embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } +embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.8", default-features = false } + +[profile.release] +debug = 2 diff --git a/examples/stm32u0/build.rs b/examples/stm32u0/build.rs new file mode 100644 index 000000000..8cd32d7ed --- /dev/null +++ b/examples/stm32u0/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32u0/src/bin/blinky.rs b/examples/stm32u0/src/bin/blinky.rs new file mode 100644 index 000000000..90e479aae --- /dev/null +++ b/examples/stm32u0/src/bin/blinky.rs @@ -0,0 +1,26 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::Timer; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut led = Output::new(p.PA5, Level::High, Speed::Low); + + loop { + info!("high"); + led.set_high(); + Timer::after_millis(300).await; + + info!("low"); + led.set_low(); + Timer::after_millis(300).await; + } +} diff --git a/examples/stm32u0/src/bin/button.rs b/examples/stm32u0/src/bin/button.rs new file mode 100644 index 000000000..8017f0274 --- /dev/null +++ b/examples/stm32u0/src/bin/button.rs @@ -0,0 +1,24 @@ +#![no_std] +#![no_main] + +use cortex_m_rt::entry; +use defmt::*; +use embassy_stm32::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[entry] +fn main() -> ! { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let button = Input::new(p.PC13, Pull::Up); + + loop { + if button.is_high() { + info!("high"); + } else { + info!("low"); + } + } +} diff --git a/examples/stm32u0/src/bin/button_exti.rs b/examples/stm32u0/src/bin/button_exti.rs new file mode 100644 index 000000000..34a08bbc6 --- /dev/null +++ b/examples/stm32u0/src/bin/button_exti.rs @@ -0,0 +1,25 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::exti::ExtiInput; +use embassy_stm32::gpio::Pull; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let mut button = ExtiInput::new(p.PC13, p.EXTI13, Pull::Up); + + info!("Press the USER button..."); + + loop { + button.wait_for_falling_edge().await; + info!("Pressed!"); + button.wait_for_rising_edge().await; + info!("Released!"); + } +} From 5178c24cf4b0fcf4ac25f76b5456cf96e745a2be Mon Sep 17 00:00:00 2001 From: Adam Simpkins Date: Tue, 9 Apr 2024 11:00:44 -0700 Subject: [PATCH 30/35] Fix embassy-futures test failure Running `cargo test` in embassy-futures was failing. The `no_run` tag on this doc example caused it to still try and compile this example, just not run it, and compilation failed. This updates the example so that it can successfully compile and run. --- embassy-futures/src/yield_now.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/embassy-futures/src/yield_now.rs b/embassy-futures/src/yield_now.rs index bb3c67d17..4d4e535f2 100644 --- a/embassy-futures/src/yield_now.rs +++ b/embassy-futures/src/yield_now.rs @@ -9,10 +9,16 @@ use core::task::{Context, Poll}; /// hold, while still allowing other tasks to run concurrently (not monopolizing /// the executor thread). /// -/// ```rust,no_run +/// ```rust +/// # use embassy_futures::{block_on, yield_now}; +/// # async fn test_fn() { +/// # let mut iter_count: u32 = 0; +/// # let mut some_condition = || { iter_count += 1; iter_count > 10 }; /// while !some_condition() { /// yield_now().await; /// } +/// # } +/// # block_on(test_fn()); /// ``` /// /// The downside is this will spin in a busy loop, using 100% of the CPU, while From e147f29b5ccbe94fb0703a4cb37ce6a403c321f3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 14 Apr 2024 22:21:19 +0200 Subject: [PATCH 31/35] ci: test embassy-futures. --- .github/ci/test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ci/test.sh b/.github/ci/test.sh index 6cb3a4bff..41da644fc 100755 --- a/.github/ci/test.sh +++ b/.github/ci/test.sh @@ -8,6 +8,7 @@ export RUSTUP_HOME=/ci/cache/rustup export CARGO_HOME=/ci/cache/cargo export CARGO_TARGET_DIR=/ci/cache/target +cargo test --manifest-path ./embassy-futures/Cargo.toml cargo test --manifest-path ./embassy-sync/Cargo.toml cargo test --manifest-path ./embassy-embedded-hal/Cargo.toml cargo test --manifest-path ./embassy-hal-internal/Cargo.toml From 1741209ba242e43ba4f2974c685ca2fab7dca766 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sun, 14 Apr 2024 23:59:38 +0200 Subject: [PATCH 32/35] update nightly. Fixes docs build. --- rust-toolchain-nightly.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain-nightly.toml b/rust-toolchain-nightly.toml index 98696fd2b..ac160b995 100644 --- a/rust-toolchain-nightly.toml +++ b/rust-toolchain-nightly.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-03-20" +channel = "nightly-2024-04-14" components = [ "rust-src", "rustfmt", "llvm-tools", "miri" ] targets = [ "thumbv7em-none-eabi", From 86706bdc1438cdccf017d073f9b8f8ff2a0322fe Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 14 Apr 2024 19:35:59 -0300 Subject: [PATCH 33/35] Add map method --- embassy-sync/src/mutex.rs | 133 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/embassy-sync/src/mutex.rs b/embassy-sync/src/mutex.rs index 72459d660..b48a408c4 100644 --- a/embassy-sync/src/mutex.rs +++ b/embassy-sync/src/mutex.rs @@ -3,6 +3,7 @@ //! This module provides a mutex that can be used to synchronize data between asynchronous tasks. use core::cell::{RefCell, UnsafeCell}; use core::future::poll_fn; +use core::mem; use core::ops::{Deref, DerefMut}; use core::task::Poll; @@ -134,6 +135,7 @@ where /// successfully locked the mutex, and grants access to the contents. /// /// Dropping it unlocks the mutex. +#[clippy::has_significant_drop] pub struct MutexGuard<'a, M, T> where M: RawMutex, @@ -142,6 +144,25 @@ where mutex: &'a Mutex, } +impl<'a, M, T> MutexGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + /// Returns a locked view over a portion of the locked data. + pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> { + let mutex = this.mutex; + let value = fun(unsafe { &mut *this.mutex.inner.get() }); + // Don't run the `drop` method for MutexGuard. The ownership of the underlying + // locked state is being moved to the returned MappedMutexGuard. + mem::forget(this); + MappedMutexGuard { + state: &mutex.state, + value, + } + } +} + impl<'a, M, T> Drop for MutexGuard<'a, M, T> where M: RawMutex, @@ -180,3 +201,115 @@ where unsafe { &mut *(self.mutex.inner.get()) } } } + +/// A handle to a held `Mutex` that has had a function applied to it via [`MutexGuard::map`] or +/// [`MappedMutexGuard::map`]. +/// +/// This can be used to hold a subfield of the protected data. +#[clippy::has_significant_drop] +pub struct MappedMutexGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + state: &'a BlockingMutex>, + value: *mut T, +} + +impl<'a, M, T> MappedMutexGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + /// Returns a locked view over a portion of the locked data. + pub fn map(this: Self, fun: impl FnOnce(&mut T) -> &mut U) -> MappedMutexGuard<'a, M, U> { + let state = this.state; + let value = fun(unsafe { &mut *this.value }); + // Don't run the `drop` method for MutexGuard. The ownership of the underlying + // locked state is being moved to the returned MappedMutexGuard. + mem::forget(this); + MappedMutexGuard { state, value } + } +} + +impl<'a, M, T> Deref for MappedMutexGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + type Target = T; + fn deref(&self) -> &Self::Target { + // Safety: the MutexGuard represents exclusive access to the contents + // of the mutex, so it's OK to get it. + unsafe { &*self.value } + } +} + +impl<'a, M, T> DerefMut for MappedMutexGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + // Safety: the MutexGuard represents exclusive access to the contents + // of the mutex, so it's OK to get it. + unsafe { &mut *self.value } + } +} + +impl<'a, M, T> Drop for MappedMutexGuard<'a, M, T> +where + M: RawMutex, + T: ?Sized, +{ + fn drop(&mut self) { + self.state.lock(|s| { + let mut s = unwrap!(s.try_borrow_mut()); + s.locked = false; + s.waker.wake(); + }) + } +} + +unsafe impl Send for MappedMutexGuard<'_, M, T> +where + M: RawMutex + Sync, + T: Send + ?Sized, +{ +} + +unsafe impl Sync for MappedMutexGuard<'_, M, T> +where + M: RawMutex + Sync, + T: Sync + ?Sized, +{ +} + +#[cfg(test)] +mod tests { + use crate::blocking_mutex::raw::NoopRawMutex; + use crate::mutex::{Mutex, MutexGuard}; + + #[futures_test::test] + async fn mapped_guard_releases_lock_when_dropped() { + let mutex: Mutex = Mutex::new([0, 1]); + + { + let guard = mutex.lock().await; + assert_eq!(*guard, [0, 1]); + let mut mapped = MutexGuard::map(guard, |this| &mut this[1]); + assert_eq!(*mapped, 1); + *mapped = 2; + } + + { + let guard = mutex.lock().await; + assert_eq!(*guard, [0, 2]); + let mut mapped = MutexGuard::map(guard, |this| &mut this[1]); + assert_eq!(*mapped, 2); + *mapped = 3; + } + + assert_eq!(*mutex.lock().await, [0, 3]); + } +} From a25cae46c5f01821911f7d989e7d80ff5d8a5376 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 15 Apr 2024 00:52:42 +0200 Subject: [PATCH 34/35] ci: test embassy-sync on miri. --- .github/ci/test-nightly.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ci/test-nightly.sh b/.github/ci/test-nightly.sh index d6e5dc574..1724ffe89 100755 --- a/.github/ci/test-nightly.sh +++ b/.github/ci/test-nightly.sh @@ -11,3 +11,4 @@ mv rust-toolchain-nightly.toml rust-toolchain.toml MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-executor/Cargo.toml --features nightly +MIRIFLAGS=-Zmiri-ignore-leaks cargo miri test --manifest-path ./embassy-sync/Cargo.toml From fcaa7de87e48463b50b9842288b25ae648dc351f Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 15 Apr 2024 01:12:28 +0200 Subject: [PATCH 35/35] stm32/rcc: make ClockMux non_exhasutive. --- embassy-stm32/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 0f87dd8ac..67fceda56 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -662,6 +662,7 @@ fn main() { #(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )* #[derive(Clone, Copy)] + #[non_exhaustive] pub struct ClockMux { #( #struct_fields, )* }